More work on ticket #50: binding of PJSUA-API account to specific transport, and minor fixes in PJSIP core implementation. Tested okay.

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@881 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index fd71f99..37f36ce 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -225,7 +225,6 @@
     if (status != PJ_SUCCESS)
 	return status;
 
-
     /* Mark account as valid */
     pjsua_var.acc[acc_id].valid = PJ_TRUE;
 
@@ -258,7 +257,6 @@
 		     PJ_ETOOMANY);
 
     /* Must have a transport */
-    PJ_TODO(associate_acc_with_transport);
     PJ_ASSERT_RETURN(pjsua_var.tpdata[0].data.ptr != NULL, PJ_EINVALIDOP);
 
     PJSUA_LOCK();
@@ -320,7 +318,7 @@
 					 pjsua_acc_id *p_acc_id)
 {
     pjsua_acc_config cfg;
-    struct transport_data *t = &pjsua_var.tpdata[tid];
+    pjsua_transport_data *t = &pjsua_var.tpdata[tid];
     char uri[PJSIP_MAX_URL_SIZE];
 
     /* ID must be valid */
@@ -382,7 +380,10 @@
 	--pjsua_var.acc_cnt;
     }
 
-    PJ_TODO(may_need_to_scan_calls);
+    /* Leave the calls intact, as I don't think calls need to
+     * access account once it's created
+     */
+
 
     PJSUA_UNLOCK();
 
@@ -491,6 +492,7 @@
     pj_pool_t *pool;
     pj_status_t status;
 
+    PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
     acc = &pjsua_var.acc[acc_id];
 
     if (acc->cfg.reg_uri.slen == 0) {
@@ -538,6 +540,17 @@
 	return status;
     }
 
+    /* If account is locked to specific transport, then set transport to
+     * the client registration.
+     */
+    if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
+	pjsip_tpselector tp_sel;
+
+	pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+	pjsip_regc_set_transport(acc->regc, &tp_sel);
+    }
+
+
     /* Set credentials
      */
     if (acc->cred_cnt) {
@@ -640,6 +653,7 @@
     pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
 
     PJ_ASSERT_RETURN(info != NULL, PJ_EINVAL);
+    PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
     
     pj_bzero(info, sizeof(pjsua_acc_info));
 
@@ -854,7 +868,7 @@
 	unsigned acc_id = pjsua_var.acc_ids[i];
 	pjsua_acc *acc = &pjsua_var.acc[acc_id];
 
-	if (pj_stricmp(&acc->user_part, &sip_uri->user)==0 &&
+	if (acc->valid && pj_stricmp(&acc->user_part, &sip_uri->user)==0 &&
 	    pj_stricmp(&acc->srv_domain, &sip_uri->host)==0) 
 	{
 	    /* Match ! */
@@ -868,19 +882,30 @@
 	unsigned acc_id = pjsua_var.acc_ids[i];
 	pjsua_acc *acc = &pjsua_var.acc[acc_id];
 
-	if (pj_stricmp(&acc->srv_domain, &sip_uri->host)==0) {
+	if (acc->valid && pj_stricmp(&acc->srv_domain, &sip_uri->host)==0) {
 	    /* Match ! */
 	    PJSUA_UNLOCK();
 	    return acc_id;
 	}
     }
 
-    /* No matching account, try match user part only. */
+    /* No matching account, try match user part (and transport type) only. */
     for (i=0; i < pjsua_var.acc_cnt; ++i) {
 	unsigned acc_id = pjsua_var.acc_ids[i];
 	pjsua_acc *acc = &pjsua_var.acc[acc_id];
 
-	if (pj_stricmp(&acc->user_part, &sip_uri->user)==0) {
+	if (acc->valid && pj_stricmp(&acc->user_part, &sip_uri->user)==0) {
+
+	    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
+		pjsip_transport_type_e type;
+		type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
+		if (type == PJSIP_TRANSPORT_UNSPECIFIED)
+		    type = PJSIP_TRANSPORT_UDP;
+
+		if (pjsua_var.tpdata[acc->cfg.transport_id].type != type)
+		    continue;
+	    }
+
 	    /* Match ! */
 	    PJSUA_UNLOCK();
 	    return acc_id;
@@ -903,10 +928,12 @@
     pj_status_t status;
     pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
     pj_str_t local_addr;
+    pjsip_tpselector tp_sel;
     unsigned flag;
     int secure;
     int local_port;
     
+    PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
     acc = &pjsua_var.acc[acc_id];
 
     /* If route-set is configured for the account, then URI is the 
@@ -945,9 +972,13 @@
     flag = pjsip_transport_get_flag_from_type(tp_type);
     secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
 
+    /* Init transport selector. */
+    pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+
     /* Get local address suitable to send request from */
     status = pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
-					 pool, tp_type, &local_addr, &local_port);
+					 pool, tp_type, &tp_sel, 
+					 &local_addr, &local_port);
     if (status != PJ_SUCCESS)
 	return status;
 
@@ -990,10 +1021,12 @@
     pj_status_t status;
     pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
     pj_str_t local_addr;
+    pjsip_tpselector tp_sel;
     unsigned flag;
     int secure;
     int local_port;
     
+    PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
     acc = &pjsua_var.acc[acc_id];
 
     /* If Record-Route is present, then URI is the top Record-Route. */
@@ -1038,9 +1071,13 @@
     flag = pjsip_transport_get_flag_from_type(tp_type);
     secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
 
+    /* Init transport selector. */
+    pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+
     /* Get local address suitable to send request from */
     status = pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
-					 pool, tp_type, &local_addr, &local_port);
+					 pool, tp_type, &tp_sel,
+					 &local_addr, &local_port);
     if (status != PJ_SUCCESS)
 	return status;
 
@@ -1064,4 +1101,19 @@
 }
 
 
+PJ_DEF(pj_status_t) pjsua_acc_set_transport( pjsua_acc_id acc_id,
+					     pjsua_transport_id tp_id)
+{
+    pjsua_acc *acc;
+
+    PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
+    acc = &pjsua_var.acc[acc_id];
+
+    PJ_ASSERT_RETURN(tp_id >= 0 && tp_id < PJ_ARRAY_SIZE(pjsua_var.tpdata),
+		     PJ_EINVAL);
+    
+    acc->cfg.transport_id = tp_id;
+
+    return PJ_SUCCESS;
+}
 
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index f7b7734..6b40bec 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -330,6 +330,16 @@
     /* Attach user data */
     call->user_data = user_data;
 
+    /* If account is locked to specific transport, then lock dialog
+     * to this transport too.
+     */
+    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
+	pjsip_tpselector tp_sel;
+
+	pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
+	pjsip_dlg_set_transport(dlg, &tp_sel);
+    }
+
     /* Set dialog Route-Set: */
     if (!pj_list_empty(&acc->route_set))
 	pjsip_dlg_set_route_set(dlg, &acc->route_set);
@@ -619,6 +629,15 @@
     dlg->mod_data[pjsua_var.mod.id] = call;
     inv->mod_data[pjsua_var.mod.id] = call;
 
+    /* If account is locked to specific transport, then lock dialog
+     * to this transport too.
+     */
+    if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
+	pjsip_tpselector tp_sel;
+
+	pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+	pjsip_dlg_set_transport(dlg, &tp_sel);
+    }
 
     /* Must answer with some response to initial INVITE.
      */
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 2186483..b719411 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -1189,7 +1189,7 @@
 PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id,
 					      pjsua_transport_info *info)
 {
-    struct transport_data *t = &pjsua_var.tpdata[id];
+    pjsua_transport_data *t = &pjsua_var.tpdata[id];
     pj_status_t status;
 
     pj_bzero(info, sizeof(*info));
@@ -1416,6 +1416,34 @@
 
 
 /*
+ * Internal function to init transport selector from transport id.
+ */
+void pjsua_init_tpselector(pjsua_transport_id tp_id,
+			   pjsip_tpselector *sel)
+{
+    pjsua_transport_data *tpdata;
+    unsigned flag;
+
+    pj_bzero(sel, sizeof(*sel));
+    if (tp_id == PJSUA_INVALID_ID)
+	return;
+
+    pj_assert(tp_id >= 0 && tp_id < PJ_ARRAY_SIZE(pjsua_var.tpdata));
+    tpdata = &pjsua_var.tpdata[tp_id];
+
+    flag = pjsip_transport_get_flag_from_type(tpdata->type);
+
+    if (flag & PJSIP_TRANSPORT_DATAGRAM) {
+	sel->type = PJSIP_TPSELECTOR_TRANSPORT;
+	sel->u.transport = tpdata->data.tp;
+    } else {
+	sel->type = PJSIP_TPSELECTOR_LISTENER;
+	sel->u.listener = tpdata->data.factory;
+    }
+}
+
+
+/*
  * Verify that valid SIP url is given.
  */
 PJ_DEF(pj_status_t) pjsua_verify_sip_url(const char *c_url)
diff --git a/pjsip/src/pjsua-lib/pjsua_im.c b/pjsip/src/pjsua-lib/pjsua_im.c
index 462796a..0e29b43 100644
--- a/pjsip/src/pjsua-lib/pjsua_im.c
+++ b/pjsip/src/pjsua-lib/pjsua_im.c
@@ -433,6 +433,16 @@
 	return status;
     }
 
+    /* If account is locked to specific transport, then set transport to
+     * the request.
+     */
+    if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
+	pjsip_tpselector tp_sel;
+
+	pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+	pjsip_tx_data_set_transport(tdata, &tp_sel);
+    }
+
     /* Add accept header. */
     pjsip_msg_add_hdr( tdata->msg, 
 		       (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
@@ -520,6 +530,16 @@
     }
 
 
+    /* If account is locked to specific transport, then set transport to
+     * the request.
+     */
+    if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
+	pjsip_tpselector tp_sel;
+
+	pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+	pjsip_tx_data_set_transport(tdata, &tp_sel);
+    }
+
     /* Add accept header. */
     pjsip_msg_add_hdr( tdata->msg, 
 		       (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c
index 78f913d..f9f8755 100644
--- a/pjsip/src/pjsua-lib/pjsua_pres.c
+++ b/pjsip/src/pjsua-lib/pjsua_pres.c
@@ -501,6 +501,16 @@
 	return PJ_TRUE;
     }
 
+    /* If account is locked to specific transport, then lock dialog
+     * to this transport too.
+     */
+    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
+	pjsip_tpselector tp_sel;
+
+	pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
+	pjsip_dlg_set_transport(dlg, &tp_sel);
+    }
+
     /* Attach our data to the subscription: */
     uapres = pj_pool_alloc(dlg->pool, sizeof(pjsua_srv_pres));
     uapres->sub = sub;
@@ -988,6 +998,16 @@
 	return;
     }
 
+    /* If account is locked to specific transport, then lock dialog
+     * to this transport too.
+     */
+    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
+	pjsip_tpselector tp_sel;
+
+	pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
+	pjsip_dlg_set_transport(dlg, &tp_sel);
+    }
+
     /* Set route-set */
     if (!pj_list_empty(&acc->route_set)) {
 	pjsip_dlg_set_route_set(dlg, &acc->route_set);