summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2016-02-25 04:38:34 +0000
committerNanang Izzuddin <nanang@teluu.com>2016-02-25 04:38:34 +0000
commitdc8713e43f4470112d27d32d045231cf581ae20d (patch)
tree7586317836dc4794e02e080353c20fff782852fa
parent149f4596c83f124c361d057e6b949e19e29e7804 (diff)
Fix #1311: Updated pjsip_tpmgr_acquire_transport2() to look up from transport hash table (instead of always create a new one) when transport selector is set to TCP/TLS listener (thanks George Joseph for the patch).
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5246 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip/include/pjsip/sip_transport.h2
-rw-r--r--pjsip/src/pjsip/sip_transport.c114
2 files changed, 86 insertions, 30 deletions
diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index 1fe3b5af..785b1312 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -799,6 +799,8 @@ struct pjsip_transport
pjsip_endpoint *endpt; /**< Endpoint instance. */
pjsip_tpmgr *tpmgr; /**< Transport manager. */
+ pjsip_tpfactory *factory; /**< Factory instance. Note: it
+ may be invalid/shutdown. */
pj_timer_entry idle_timer; /**< Timer when ref cnt is zero.*/
pj_timestamp last_recv_ts; /**< Last time receiving data. */
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index 04103243..fffc5cf3 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -1295,6 +1295,23 @@ PJ_DECL(void) pjsip_tpmgr_fla2_param_default(pjsip_tpmgr_fla2_param *prm)
pj_bzero(prm, sizeof(*prm));
}
+static pj_bool_t pjsip_tpmgr_is_tpfactory_valid(pjsip_tpmgr *mgr,
+ pjsip_tpfactory *tpf)
+{
+ pjsip_tpfactory *p;
+
+ pj_lock_acquire(mgr->lock);
+ for (p=mgr->factory_list.next; p!=&mgr->factory_list; p=p->next) {
+ if (p == tpf) {
+ pj_lock_release(mgr->lock);
+ return PJ_TRUE;
+ }
+ }
+ pj_lock_release(mgr->lock);
+
+ return PJ_FALSE;
+}
+
/*****************************************************************************
*
* TRANSPORT MANAGER
@@ -2000,34 +2017,28 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
TRACE_((THIS_FILE, "Transport %s acquired", seltp->obj_name));
return PJ_SUCCESS;
-
- } else if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER &&
- sel->u.listener)
- {
- /* Application has requested that a specific listener is to
- * be used. In this case, skip transport hash table lookup.
- */
-
- /* Verify that the listener type matches the destination type */
- if (sel->u.listener->type != type) {
- pj_lock_release(mgr->lock);
- return PJSIP_ETPNOTSUITABLE;
- }
-
- /* We'll use this listener to create transport */
- factory = sel->u.listener;
-
} else {
/*
* This is the "normal" flow, where application doesn't specify
- * specific transport/listener to be used to send message to.
+ * specific transport to be used to send message to.
* In this case, lookup the transport from the hash table.
*/
pjsip_transport_key key;
int key_len;
pjsip_transport *transport;
+ /* If listener is specified, verify that the listener type matches
+ * the destination type.
+ */
+ if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && sel->u.listener)
+ {
+ if (sel->u.listener->type != type) {
+ pj_lock_release(mgr->lock);
+ return PJSIP_ETPNOTSUITABLE;
+ }
+ }
+
pj_bzero(&key, sizeof(key));
key_len = sizeof(key.type) + addr_len;
@@ -2069,6 +2080,19 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
}
}
+ /* If transport is found and listener is specified, verify listener */
+ else if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER &&
+ sel->u.listener && transport->factory != sel->u.listener)
+ {
+ transport = NULL;
+ /* This will cause a new transport to be created which will be a
+ * 'duplicate' of the existing transport (same type & remote addr,
+ * but different factory). Any future hash lookup will return
+ * the new one, and eventually the old one will still be freed
+ * (by application or #1774).
+ */
+ }
+
if (transport!=NULL && !transport->is_shutdown) {
/*
* Transport found!
@@ -2081,22 +2105,51 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
return PJ_SUCCESS;
}
+
/*
* Transport not found!
- * Find factory that can create such transport.
+ * So we need to create one, find factory that can create
+ * such transport.
*/
- factory = mgr->factory_list.next;
- while (factory != &mgr->factory_list) {
- if (factory->type == type)
- break;
- factory = factory->next;
- }
+ if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && sel->u.listener)
+ {
+ /* Application has requested that a specific listener is to
+ * be used.
+ */
- if (factory == &mgr->factory_list) {
- /* No factory can create the transport! */
- pj_lock_release(mgr->lock);
- TRACE_((THIS_FILE, "No suitable factory was found either"));
- return PJSIP_EUNSUPTRANSPORT;
+ /* Verify that the listener type matches the destination type */
+ if (sel->u.listener->type != type) {
+ pj_lock_release(mgr->lock);
+ return PJSIP_ETPNOTSUITABLE;
+ }
+
+ /* We'll use this listener to create transport */
+ factory = sel->u.listener;
+
+ /* Verify if listener is still valid */
+ if (!pjsip_tpmgr_is_tpfactory_valid(mgr, factory)) {
+ pj_lock_release(mgr->lock);
+ PJ_LOG(3,(THIS_FILE, "Specified factory for creating "
+ "transport is not found"));
+ return PJ_ENOTFOUND;
+ }
+
+ } else {
+
+ /* Find factory with type matches the destination type */
+ factory = mgr->factory_list.next;
+ while (factory != &mgr->factory_list) {
+ if (factory->type == type)
+ break;
+ factory = factory->next;
+ }
+
+ if (factory == &mgr->factory_list) {
+ /* No factory can create the transport! */
+ pj_lock_release(mgr->lock);
+ TRACE_((THIS_FILE, "No suitable factory was found either"));
+ return PJSIP_EUNSUPTRANSPORT;
+ }
}
}
@@ -2116,6 +2169,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
PJ_ASSERT_ON_FAIL(tp!=NULL,
{pj_lock_release(mgr->lock); return PJ_EBUG;});
pjsip_transport_add_ref(*tp);
+ (*tp)->factory = factory;
}
pj_lock_release(mgr->lock);
return status;