diff options
-rw-r--r-- | pjmedia/src/pjmedia/transport_ice.c | 128 | ||||
-rw-r--r-- | pjsip-apps/src/test-pjsua/scripts-sendto/200_ice_success_3.py | 35 | ||||
-rw-r--r-- | pjsip-apps/src/test-pjsua/scripts-sendto/200_ice_success_4.py | 35 |
3 files changed, 144 insertions, 54 deletions
diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c index 907259dd..046961c0 100644 --- a/pjmedia/src/pjmedia/transport_ice.c +++ b/pjmedia/src/pjmedia/transport_ice.c @@ -594,6 +594,14 @@ static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice, /* ICE has failed, application should have terminated this call */ } + /* Removing a=rtcp line when there is only one component. */ + if (comp_cnt == 1) { + attr = pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_RTCP, NULL); + if (attr) + pjmedia_sdp_attr_remove(&m->attr_count, m->attr, attr); + } + + return PJ_SUCCESS; } @@ -748,9 +756,9 @@ static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice, struct sdp_state *sdp_state) { const pjmedia_sdp_media *rem_m; - const pjmedia_sdp_attr *attr, *ufrag_attr, *pwd_attr; + const pjmedia_sdp_attr *ufrag_attr, *pwd_attr; const pjmedia_sdp_conn *rem_conn; - pj_bool_t comp1_found=PJ_FALSE, comp2_found=PJ_FALSE; + pj_bool_t comp1_found=PJ_FALSE, comp2_found=PJ_FALSE, has_rtcp=PJ_FALSE; pj_sockaddr rem_conn_addr, rtcp_addr; unsigned i; pj_status_t status; @@ -767,7 +775,7 @@ static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice, } /* Verify that default target for each component matches one of the - * candidatefor the component. Otherwise stop ICE with ICE ice_mismatch + * candidate for the component. Otherwise stop ICE with ICE ice_mismatch * error. */ @@ -793,55 +801,62 @@ static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice, if (status != PJ_SUCCESS) return status; - /* Component 2 is a=rtcp line, if present. */ - attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, - &STR_RTCP, NULL); - if (attr && tp_ice->comp_cnt > 1) { - pjmedia_sdp_rtcp_attr rtcp_attr; + if (tp_ice->comp_cnt > 1) { + const pjmedia_sdp_attr *attr; - status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp_attr); - if (status != PJ_SUCCESS) { - /* Error parsing a=rtcp attribute */ - return status; - } - - if (rtcp_attr.addr.slen) { - /* Verify address family matches */ - if ((tp_ice->af==pj_AF_INET() && - pj_strcmp(&rtcp_attr.addr_type, &STR_IP4)!=0) || - (tp_ice->af==pj_AF_INET6() && - pj_strcmp(&rtcp_attr.addr_type, &STR_IP6)!=0)) - { - return PJMEDIA_SDP_ETPORTNOTEQUAL; - } + /* Get default RTCP candidate from a=rtcp line, if present, otherwise + * calculate default RTCP candidate from default RTP target. + */ + attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, + &STR_RTCP, NULL); + has_rtcp = (attr != NULL); + + if (attr) { + pjmedia_sdp_rtcp_attr rtcp_attr; - /* Assign RTCP address */ - status = pj_sockaddr_init(tp_ice->af, &rtcp_addr, - &rtcp_attr.addr, - (pj_uint16_t)rtcp_attr.port); + status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp_attr); if (status != PJ_SUCCESS) { - return PJMEDIA_SDP_EINRTCP; + /* Error parsing a=rtcp attribute */ + return status; } - } else { - /* Assign RTCP address */ - status = pj_sockaddr_init(tp_ice->af, &rtcp_addr, - NULL, - (pj_uint16_t)rtcp_attr.port); - if (status != PJ_SUCCESS) { - return PJMEDIA_SDP_EINRTCP; + + if (rtcp_attr.addr.slen) { + /* Verify address family matches */ + if ((tp_ice->af==pj_AF_INET() && + pj_strcmp(&rtcp_attr.addr_type, &STR_IP4)!=0) || + (tp_ice->af==pj_AF_INET6() && + pj_strcmp(&rtcp_attr.addr_type, &STR_IP6)!=0)) + { + return PJMEDIA_SDP_ETPORTNOTEQUAL; + } + + /* Assign RTCP address */ + status = pj_sockaddr_init(tp_ice->af, &rtcp_addr, + &rtcp_attr.addr, + (pj_uint16_t)rtcp_attr.port); + if (status != PJ_SUCCESS) { + return PJMEDIA_SDP_EINRTCP; + } + } else { + /* Assign RTCP address */ + status = pj_sockaddr_init(tp_ice->af, &rtcp_addr, + NULL, + (pj_uint16_t)rtcp_attr.port); + if (status != PJ_SUCCESS) { + return PJMEDIA_SDP_EINRTCP; + } + pj_sockaddr_copy_addr(&rtcp_addr, &rem_conn_addr); } - pj_sockaddr_copy_addr(&rtcp_addr, &rem_conn_addr); + } else { + unsigned rtcp_port; + + rtcp_port = pj_sockaddr_get_port(&rem_conn_addr) + 1; + pj_sockaddr_cp(&rtcp_addr, &rem_conn_addr); + pj_sockaddr_set_port(&rtcp_addr, (pj_uint16_t)rtcp_port); } - - sdp_state->match_comp_cnt = 2; - - } else { - /* Don't have RTCP component */ - comp2_found = PJ_TRUE; - sdp_state->match_comp_cnt = 1; } - /* Find the default address in a=candidate attributes. + /* Find the default addresses in a=candidate attributes. */ for (i=0; i<rem_m->attr_count; ++i) { pj_ice_sess_cand cand; @@ -863,28 +878,33 @@ static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice, if (!comp1_found && cand.comp_id==COMP_RTP && pj_sockaddr_cmp(&rem_conn_addr, &cand.addr)==0) { - /* Found */ comp1_found = PJ_TRUE; - if (comp1_found && comp2_found) - break; } else if (!comp2_found && cand.comp_id==COMP_RTCP && pj_sockaddr_cmp(&rtcp_addr, &cand.addr)==0) { - /* Found */ comp2_found = PJ_TRUE; - if (comp1_found && comp2_found) - break; } + if (cand.comp_id == COMP_RTCP) + has_rtcp = PJ_TRUE; + + if (comp1_found && (comp2_found || tp_ice->comp_cnt==1)) + break; } - if (!comp1_found || !comp2_found) { - /* ICE ice_mismatch */ - sdp_state->ice_mismatch = PJ_TRUE; - } else { + /* Check matched component count and ice_mismatch */ + if (comp1_found && (tp_ice->comp_cnt==1 || !has_rtcp)) { + sdp_state->match_comp_cnt = 1; + sdp_state->ice_mismatch = PJ_FALSE; + } else if (comp1_found && comp2_found) { + sdp_state->match_comp_cnt = 2; sdp_state->ice_mismatch = PJ_FALSE; + } else { + sdp_state->match_comp_cnt = (tp_ice->comp_cnt > 1 && has_rtcp)? 2 : 1; + sdp_state->ice_mismatch = PJ_TRUE; } + /* Detect remote restarting session */ if (pj_ice_strans_has_sess(tp_ice->ice_st) && (pj_ice_strans_sess_is_running(tp_ice->ice_st) || diff --git a/pjsip-apps/src/test-pjsua/scripts-sendto/200_ice_success_3.py b/pjsip-apps/src/test-pjsua/scripts-sendto/200_ice_success_3.py new file mode 100644 index 00000000..2c741e44 --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-sendto/200_ice_success_3.py @@ -0,0 +1,35 @@ +# $Id$ +import inc_sip as sip +import inc_sdp as sdp + +sdp = \ +""" +v=0 +o=- 0 0 IN IP4 127.0.0.1 +s=pjmedia +c=IN IP4 127.0.0.1 +t=0 0 +m=audio 4000 RTP/AVP 0 101 +a=ice-ufrag:1234 +a=ice-pwd:5678 +a=rtpmap:0 PCMU/8000 +a=sendrecv +a=rtpmap:101 telephone-event/8000 +a=fmtp:101 0-15 +a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host +a=candidate:YY 2 UDP 1234 127.0.0.1 4001 typ host +""" + +args = "--null-audio --use-ice --auto-answer 200 --max-calls 1" +include = ["a=ice-ufrag", # must have ICE + "a=candidate:[0-9a-zA-Z]+ 2 UDP" # must have RTCP component + ] +exclude = [ + "ice-mismatch" # must not mismatch + ] + +sendto_cfg = sip.SendtoCfg( "caller sends two components without a=rtcp line", + pjsua_args=args, sdp=sdp, resp_code=200, + resp_inc=include, resp_exc=exclude, + enable_buffer = True) + diff --git a/pjsip-apps/src/test-pjsua/scripts-sendto/200_ice_success_4.py b/pjsip-apps/src/test-pjsua/scripts-sendto/200_ice_success_4.py new file mode 100644 index 00000000..0ec3849c --- /dev/null +++ b/pjsip-apps/src/test-pjsua/scripts-sendto/200_ice_success_4.py @@ -0,0 +1,35 @@ +# $Id$ +import inc_sip as sip +import inc_sdp as sdp + +sdp = \ +""" +v=0 +o=- 0 0 IN IP4 127.0.0.1 +s=pjmedia +c=IN IP4 127.0.0.1 +t=0 0 +m=audio 4000 RTP/AVP 0 101 +a=rtcp:4382 IN IP4 192.168.0.4 +a=ice-ufrag:1234 +a=ice-pwd:5678 +a=rtpmap:0 PCMU/8000 +a=sendrecv +a=rtpmap:101 telephone-event/8000 +a=fmtp:101 0-15 +a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host +a=candidate:YY 2 UDP 1234 127.0.0.2 4002 typ host +""" + +args = "--null-audio --use-ice --auto-answer 200 --max-calls 1 --ice-no-rtcp" +include = ["a=ice-ufrag"] # must have ICE +exclude = [ + "ice-mismatch", # must not mismatch + "a=candidate:[0-9a-zA-Z]+ 2 UDP" # must not have RTCP component + ] + +sendto_cfg = sip.SendtoCfg( "pjsua with --ice-no-rtcp ignores RTCP things in the SDP", + pjsua_args=args, sdp=sdp, resp_code=200, + resp_inc=include, resp_exc=exclude, + enable_buffer = True) + |