summaryrefslogtreecommitdiff
path: root/pjsip/src/pjsua-lib/pjsua_acc.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip/src/pjsua-lib/pjsua_acc.c')
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c117
1 files changed, 117 insertions, 0 deletions
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;