From c38c8101be49bb4cb9cf95815f0c2ce955876c3b Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Mon, 18 Aug 2014 08:54:43 +0000 Subject: Closed #1677: Contact uses source port in initial registration. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4888 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsip/sip_util.h | 15 +++++ pjsip/include/pjsua-lib/pjsua.h | 13 +++++ pjsip/src/pjsip/sip_util.c | 18 +++--- pjsip/src/pjsua-lib/pjsua_acc.c | 117 +++++++++++++++++++++++++++++++++++++++ pjsip/src/pjsua-lib/pjsua_core.c | 1 + 5 files changed, 155 insertions(+), 9 deletions(-) diff --git a/pjsip/include/pjsip/sip_util.h b/pjsip/include/pjsip/sip_util.h index 226dccd6..c8b43f35 100644 --- a/pjsip/include/pjsip/sip_util.h +++ b/pjsip/include/pjsip/sip_util.h @@ -371,6 +371,21 @@ PJ_DECL(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, const pjsip_tx_data *tdata, pjsip_tx_data **p_tdata); +/** + * Get destination address and port and transport type information for the + * specified URI. + * + * @param target_uri The destination URI. + * @param request_uri Optional request URI to be considered. May be NULL. + * @param pool Pool to allocate memory from. + * @param dest_info To be filled with destination info. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsip_get_dest_info(const pjsip_uri *target_uri, + const pjsip_uri *request_uri, + pj_pool_t *pool, + pjsip_host_info *dest_info); /** * Find which destination to be used to send the request message, based diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index a86644c5..d83b05f8 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -3054,6 +3054,19 @@ typedef struct pjsua_acc_config */ int contact_rewrite_method; + /** + * Specify if source TCP port should be used as the initial Contact + * address if TCP/TLS transport is used. Note that this feature will + * be automatically turned off when nameserver is configured because + * it may yield different destination address due to DNS SRV resolution. + * Also some platforms are unable to report the local address of the + * TCP socket when it is still connecting. In these cases, this + * feature will also be turned off. + * + * Default: PJ_TRUE (yes). + */ + pj_bool_t contact_rewrite_use_src_port; + /** * This option is used to overwrite the "sent-by" field of the Via header * for outgoing messages with the same interface address as the one in diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c index d7cde6fe..21ea2375 100644 --- a/pjsip/src/pjsip/sip_util.c +++ b/pjsip/src/pjsip/sip_util.c @@ -801,10 +801,10 @@ on_missing_hdr: /* Fill-up destination information from a target URI */ -static pj_status_t get_dest_info(const pjsip_uri *target_uri, - const pjsip_uri *request_uri, - pj_pool_t *pool, - pjsip_host_info *dest_info) +PJ_DEF(pj_status_t) pjsip_get_dest_info(const pjsip_uri *target_uri, + const pjsip_uri *request_uri, + pj_pool_t *pool, + pjsip_host_info *dest_info) { /* The target URI must be a SIP/SIPS URL so we can resolve it's address. * Otherwise we're in trouble (i.e. there's no host part in tel: URL). @@ -907,8 +907,8 @@ PJ_DEF(pj_status_t) pjsip_get_request_dest(const pjsip_tx_data *tdata, target_uri = tdata->msg->line.req.uri; } - return get_dest_info(target_uri, tdata->msg->line.req.uri, - (pj_pool_t*)tdata->pool, dest_info); + return pjsip_get_dest_info(target_uri, tdata->msg->line.req.uri, + (pj_pool_t*)tdata->pool, dest_info); } @@ -1011,8 +1011,8 @@ PJ_DEF(pj_status_t) pjsip_process_route_set(pjsip_tx_data *tdata, } /* Fill up the destination host/port from the URI. */ - status = get_dest_info(target_uri, new_request_uri, tdata->pool, - dest_info); + status = pjsip_get_dest_info(target_uri, new_request_uri, tdata->pool, + dest_info); if (status != PJ_SUCCESS) return status; @@ -1509,7 +1509,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_raw_to_uri(pjsip_endpoint *endpt, } /* Build destination info. */ - status = get_dest_info(uri, NULL, tdata->pool, &dest_info); + status = pjsip_get_dest_info(uri, NULL, tdata->pool, &dest_info); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); return status; diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 1abaedd1..dbdb698c 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -2933,6 +2933,28 @@ PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id, return PJ_SUCCESS; } +/* + * Internal: + * determine if an address is a valid IP address, and if it is, + * return the IP version (4 or 6). + */ +static int get_ip_addr_ver(const pj_str_t *host) +{ + pj_in_addr dummy; + pj_in6_addr dummy6; + + /* First check with inet_aton() */ + if (pj_inet_aton(host, &dummy) > 0) + return 4; + + /* Then check if this is an IPv6 address */ + if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS) + return 6; + + /* Not an IP address */ + return 0; +} + /* Get local transport address suitable to be used for Via or Contact address * to send request to the specified destination URI. */ @@ -3014,9 +3036,104 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, if (status != PJ_SUCCESS) return status; + /* Set this as default return value. This may be changed below + * for TCP/TLS + */ addr->host = tfla2_prm.ret_addr; addr->port = tfla2_prm.ret_port; + /* For TCP/TLS, acc may request to specify source port */ + if (acc->cfg.contact_rewrite_use_src_port) { + pjsip_host_info dinfo; + pjsip_transport *tp = NULL; + pj_addrinfo ai; + pj_bool_t log_written = PJ_FALSE; + + status = pjsip_get_dest_info((pjsip_uri*)sip_uri, NULL, + pool, &dinfo); + + if (status==PJ_SUCCESS && (dinfo.flag & PJSIP_TRANSPORT_RELIABLE)==0) { + /* Not TCP or TLS. No need to do this */ + status = PJ_EINVALIDOP; + log_written = PJ_TRUE; + } + + if (status==PJ_SUCCESS && + get_ip_addr_ver(&dinfo.addr.host)==0 && + pjsua_var.ua_cfg.nameserver_count) + { + /* If nameserver is configured, PJSIP will resolve destinations + * by their DNS SRV record first. On the other hand, we will + * resolve destination with DNS A record via pj_getaddrinfo(). + * They may yield different IP addresses, hence causing different + * TCP/TLS connection to be created and hence different source + * address. + */ + PJ_LOG(4,(THIS_FILE, "Warning: cannot use source TCP/TLS socket" + " address for Contact when nameserver is configured.")); + status = PJ_ENOTSUP; + log_written = PJ_TRUE; + } + + if (status == PJ_SUCCESS) { + unsigned cnt=1; + int af; + + af = (dinfo.type & PJSIP_TRANSPORT_IPV6)? PJ_AF_INET6 : PJ_AF_INET; + status = pj_getaddrinfo(af, &dinfo.addr.host, &cnt, &ai); + } + + if (status == PJ_SUCCESS) { + int addr_len = pj_sockaddr_get_len(&ai.ai_addr); + pj_uint16_t port = dinfo.addr.port; + + if (port==0) { + port = (dinfo.flag & PJSIP_TRANSPORT_SECURE) ? 5061 : 5060; + } + pj_sockaddr_set_port(&ai.ai_addr, port); + status = pjsip_endpt_acquire_transport(pjsua_var.endpt, + dinfo.type, + &ai.ai_addr, + addr_len, + &tp_sel, &tp); + } + + if (status == PJ_SUCCESS && (tp->local_name.port == 0 || + tp->local_name.host.slen==0 || + *tp->local_name.host.ptr=='0')) + { + /* Trap zero port or "0.0.0.0" address. */ + /* The TCP/TLS transport is still connecting and unfortunately + * this OS doesn't report the bound local address in this state. + */ + PJ_LOG(4,(THIS_FILE, "Unable to get transport local port " + "for Contact address (OS doesn't support)")); + status = PJ_ENOTSUP; + log_written = PJ_TRUE; + } + + if (status == PJ_SUCCESS) { + /* Got the local transport address */ + pj_strdup(pool, &addr->host, &tp->local_name.host); + addr->port = tp->local_name.port; + } + + if (tp) { + /* Here the transport's ref counter WILL reach zero. But the + * transport will NOT get destroyed because it should have an + * idle timer. + */ + pjsip_transport_dec_ref(tp); + tp = NULL; + } + + if (status != PJ_SUCCESS && !log_written) { + PJ_PERROR(4,(THIS_FILE, status, "Unable to use source local " + "TCP socket address for Contact")); + } + status = PJ_SUCCESS; + } + if (p_tp_type) *p_tp_type = tp_type; diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index d4fefe3c..056ff888 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -289,6 +289,7 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg) cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer; cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL; cfg->contact_rewrite_method = PJSUA_CONTACT_REWRITE_METHOD; + cfg->contact_rewrite_use_src_port = PJ_TRUE; cfg->use_rfc5626 = PJ_TRUE; cfg->reg_use_proxy = PJSUA_REG_USE_OUTBOUND_PROXY | PJSUA_REG_USE_ACC_PROXY; -- cgit v1.2.3