summaryrefslogtreecommitdiff
path: root/pjsip/src
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-01-12 06:37:35 +0000
committerBenny Prijono <bennylp@teluu.com>2007-01-12 06:37:35 +0000
commit7567c6b90e8e0dd20204a579cd548ad7ae00febf (patch)
treefaadb7133a618fe5b1551b3ea89717eec860bee3 /pjsip/src
parent5058236717c4a44f02a1507b2833e8cff8f54083 (diff)
Workaround for ticket #50: added API to lock/bind transaction, dialog, and regc to a specific transport/listener
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@879 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src')
-rw-r--r--pjsip/src/pjsip-ua/sip_reg.c21
-rw-r--r--pjsip/src/pjsip/sip_dialog.c36
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c3
-rw-r--r--pjsip/src/pjsip/sip_transaction.c43
-rw-r--r--pjsip/src/pjsip/sip_transport.c223
-rw-r--r--pjsip/src/pjsip/sip_util.c2
6 files changed, 268 insertions, 60 deletions
diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c
index 5cba23ee..d6078c73 100644
--- a/pjsip/src/pjsip-ua/sip_reg.c
+++ b/pjsip/src/pjsip-ua/sip_reg.c
@@ -76,6 +76,9 @@ struct pjsip_regc
pj_time_val last_reg;
pj_time_val next_reg;
pj_timer_entry timer;
+
+ /* Transport selector */
+ pjsip_tpselector tp_sel;
};
@@ -124,6 +127,7 @@ PJ_DEF(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc)
regc->_delete_flag = 1;
regc->cb = NULL;
} else {
+ pjsip_tpselector_dec_ref(&regc->tp_sel);
pjsip_endpt_release_pool(regc->endpt, regc->pool);
}
@@ -310,6 +314,23 @@ PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc,
return PJ_SUCCESS;
}
+
+/*
+ * Bind client registration to a specific transport/listener.
+ */
+PJ_DEF(pj_status_t) pjsip_regc_set_transport( pjsip_regc *regc,
+ const pjsip_tpselector *sel)
+{
+ PJ_ASSERT_RETURN(regc && sel, PJ_EINVAL);
+
+ pjsip_tpselector_dec_ref(&regc->tp_sel);
+ pj_memcpy(&regc->tp_sel, sel, sizeof(*sel));
+ pjsip_tpselector_add_ref(&regc->tp_sel);
+
+ return PJ_SUCCESS;
+}
+
+
PJ_DEF(pj_status_t) pjsip_regc_add_headers( pjsip_regc *regc,
const pjsip_hdr *hdr_list)
{
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
index 515b8616..bf8eef40 100644
--- a/pjsip/src/pjsip/sip_dialog.c
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -506,6 +506,34 @@ on_error:
/*
+ * Bind dialog to a specific transport/listener.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_set_transport( pjsip_dialog *dlg,
+ const pjsip_tpselector *sel)
+{
+ /* Validate */
+ PJ_ASSERT_RETURN(dlg && sel, PJ_EINVAL);
+
+ /* Start locking the dialog. */
+ pjsip_dlg_inc_lock(dlg);
+
+ /* Decrement reference counter of previous transport selector */
+ pjsip_tpselector_dec_ref(&dlg->tp_sel);
+
+ /* Copy transport selector structure .*/
+ pj_memcpy(&dlg->tp_sel, sel, sizeof(*sel));
+
+ /* Increment reference counter */
+ pjsip_tpselector_add_ref(&dlg->tp_sel);
+
+ /* Unlock dialog. */
+ pjsip_dlg_dec_lock(dlg);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
* Create forked dialog from a response.
*/
PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
@@ -1065,6 +1093,10 @@ PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg,
if (status != PJ_SUCCESS)
goto on_error;
+ /* Set transport selector */
+ status = pjsip_tsx_set_transport(tsx, &dlg->tp_sel);
+ pj_assert(status == PJ_SUCCESS);
+
/* Attach this dialog to the transaction, so that user agent
* will dispatch events to this dialog.
*/
@@ -1086,6 +1118,10 @@ PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg,
}
} else {
+ /* Set transport selector */
+ pjsip_tx_data_set_transport(tdata, &dlg->tp_sel);
+
+ /* Send request */
status = pjsip_endpt_send_request_stateless(dlg->endpt, tdata,
NULL, NULL);
if (status != PJ_SUCCESS)
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index 59729987..8c112395 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -1043,10 +1043,11 @@ PJ_DEF(pj_status_t) pjsip_endpt_acquire_transport(pjsip_endpoint *endpt,
pjsip_transport_type_e type,
const pj_sockaddr_t *remote,
int addr_len,
+ const pjsip_tpselector *sel,
pjsip_transport **transport)
{
return pjsip_tpmgr_acquire_transport(endpt->transport_mgr, type,
- remote, addr_len, transport);
+ remote, addr_len, sel, transport);
}
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index 23685ff6..a0574ca4 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -931,6 +931,9 @@ static pj_status_t tsx_destroy( pjsip_transaction *tsx )
pjsip_transport_dec_ref( tsx->transport );
tsx->transport = NULL;
}
+ /* Decrement reference counter in transport selector */
+ pjsip_tpselector_dec_ref(&tsx->tp_sel);
+
/* Free last transmitted message. */
if (tsx->last_tx) {
pjsip_tx_data_dec_ref( tsx->last_tx );
@@ -1363,6 +1366,36 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user,
/*
+ * Bind transaction to a specific transport/listener.
+ */
+PJ_DEF(pj_status_t) pjsip_tsx_set_transport(pjsip_transaction *tsx,
+ const pjsip_tpselector *sel)
+{
+ struct tsx_lock_data lck;
+
+ /* Must be UAC transaction */
+ PJ_ASSERT_RETURN(tsx && sel && tsx->role == PJSIP_ROLE_UAC, PJ_EINVAL);
+
+ /* Start locking the transaction. */
+ lock_tsx(tsx, &lck);
+
+ /* Decrement reference counter of previous transport selector */
+ pjsip_tpselector_dec_ref(&tsx->tp_sel);
+
+ /* Copy transport selector structure .*/
+ pj_memcpy(&tsx->tp_sel, sel, sizeof(*sel));
+
+ /* Increment reference counter */
+ pjsip_tpselector_add_ref(&tsx->tp_sel);
+
+ /* Unlock transaction. */
+ unlock_tsx(tsx, &lck);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
* Set transaction status code and reason.
*/
static void tsx_set_status_code(pjsip_transaction *tsx,
@@ -1423,11 +1456,17 @@ PJ_DEF(pj_status_t) pjsip_tsx_send_msg( pjsip_transaction *tsx,
/* Dispatch to transaction. */
lock_tsx(tsx, &lck);
+
+ /* Set transport selector to tdata */
+ pjsip_tx_data_set_transport(tdata, &tsx->tp_sel);
+
+ /* Dispatch to state handler */
status = (*tsx->state_handler)(tsx, &event);
+
unlock_tsx(tsx, &lck);
- /* Will always decrement tdata reference counter
- * (consistent with other send functions.
+ /* Only decrement reference counter when it returns success.
+ * (This is the specification from the .PDF design document).
*/
if (status == PJ_SUCCESS) {
pjsip_tx_data_dec_ref(tdata);
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index 38db3993..9a3ae6a1 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -259,6 +259,37 @@ PJ_DEF(const char*) pjsip_transport_get_type_name(pjsip_transport_type_e type)
return transport_names[type].name.ptr;
}
+
+/*****************************************************************************
+ *
+ * TRANSPORT SELECTOR
+ *
+ *****************************************************************************/
+
+/*
+ * Add transport/listener reference in the selector.
+ */
+PJ_DEF(void) pjsip_tpselector_add_ref(pjsip_tpselector *sel)
+{
+ if (sel->type == PJSIP_TPSELECTOR_TRANSPORT && sel->u.transport != NULL)
+ pjsip_transport_add_ref(sel->u.transport);
+ else if (sel->type == PJSIP_TPSELECTOR_LISTENER && sel->u.listener != NULL)
+ ; /* Hmm.. looks like we don't have reference counter for listener */
+}
+
+
+/*
+ * Decrement transport/listener reference in the selector.
+ */
+PJ_DEF(void) pjsip_tpselector_dec_ref(pjsip_tpselector *sel)
+{
+ if (sel->type == PJSIP_TPSELECTOR_TRANSPORT && sel->u.transport != NULL)
+ pjsip_transport_dec_ref(sel->u.transport);
+ else if (sel->type == PJSIP_TPSELECTOR_LISTENER && sel->u.listener != NULL)
+ ; /* Hmm.. looks like we don't have reference counter for listener */
+}
+
+
/*****************************************************************************
*
* TRANSMIT DATA BUFFER MANIPULATION.
@@ -330,6 +361,7 @@ PJ_DEF(pj_status_t) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata )
if (pj_atomic_dec_and_get(tdata->ref_cnt) <= 0) {
PJ_LOG(5,(tdata->obj_name, "Destroying txdata %s",
pjsip_tx_data_get_info(tdata)));
+ pjsip_tpselector_dec_ref(&tdata->tp_sel);
#if defined(PJ_DEBUG) && PJ_DEBUG!=0
pj_atomic_dec( tdata->mgr->tdata_counter );
#endif
@@ -408,6 +440,24 @@ PJ_DEF(char*) pjsip_tx_data_get_info( pjsip_tx_data *tdata )
return tdata->info;
}
+PJ_DEF(pj_status_t) pjsip_tx_data_set_transport(pjsip_tx_data *tdata,
+ const pjsip_tpselector *sel)
+{
+ PJ_ASSERT_RETURN(tdata && sel, PJ_EINVAL);
+
+ pj_lock_acquire(tdata->lock);
+
+ pjsip_tpselector_dec_ref(&tdata->tp_sel);
+
+ pj_memcpy(&tdata->tp_sel, sel, sizeof(*sel));
+ pjsip_tpselector_add_ref(&tdata->tp_sel);
+
+ pj_lock_release(tdata->lock);
+
+ return PJ_SUCCESS;
+}
+
+
PJ_DEF(char*) pjsip_rx_data_get_info(pjsip_rx_data *rdata)
{
char obj_name[PJ_MAX_OBJ_NAME];
@@ -911,7 +961,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr,
pj_sockaddr_in_init(&remote, NULL, 0);
status = pjsip_tpmgr_acquire_transport(tpmgr, type, &remote,
- sizeof(remote), &tp);
+ sizeof(remote), NULL, &tp);
if (status == PJ_SUCCESS) {
pj_strdup(pool, ip_addr, &tp->local_name.host);
@@ -1200,11 +1250,9 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
pjsip_transport_type_e type,
const pj_sockaddr_t *remote,
int addr_len,
+ const pjsip_tpselector *sel,
pjsip_transport **tp)
{
- struct transport_key key;
- int key_len;
- pjsip_transport *transport;
pjsip_tpfactory *factory;
pj_status_t status;
@@ -1215,74 +1263,135 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
pj_lock_acquire(mgr->lock);
- key_len = sizeof(key.type) + addr_len;
+ /* If transport is specified, then just use it if it is suitable
+ * for the destination.
+ */
+ if (sel && sel->type == PJSIP_TPSELECTOR_TRANSPORT &&
+ sel->u.transport)
+ {
+ pjsip_transport *seltp = sel->u.transport;
+
+ /* See if the transport is (not) suitable */
+ if (seltp->key.type != type) {
+ pj_lock_release(mgr->lock);
+ return PJSIP_ETPNOTSUITABLE;
+ }
- /* First try to get exact destination. */
- key.type = type;
- pj_memcpy(&key.addr, remote, addr_len);
+ /* We could also verify that the destination address is reachable
+ * from this transport (i.e. both are equal), but if application
+ * has requested a specific transport to be used, assume that
+ * it knows what to do.
+ *
+ * In other words, I don't think destination verification is a good
+ * idea for now.
+ */
- transport = pj_hash_get(mgr->table, &key, key_len, NULL);
- if (transport == NULL) {
- unsigned flag = pjsip_transport_get_flag_from_type(type);
- const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
+ /* Transport looks to be suitable to use, so just use it. */
+ pjsip_transport_add_ref(seltp);
+ pj_lock_release(mgr->lock);
+ *tp = seltp;
- /* Ignore address for loop transports. */
- if (type == PJSIP_TRANSPORT_LOOP ||
- type == PJSIP_TRANSPORT_LOOP_DGRAM)
- {
- pj_sockaddr_in *addr = (pj_sockaddr_in*)&key.addr;
+ 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.
+ */
- pj_bzero(addr, sizeof(pj_sockaddr_in));
- key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
- transport = pj_hash_get(mgr->table, &key, key_len, NULL);
+ /* Verify that the listener type matches the destination type */
+ if (sel->u.listener->type != type) {
+ pj_lock_release(mgr->lock);
+ return PJSIP_ETPNOTSUITABLE;
}
- /* For datagram INET transports, try lookup with zero address.
+
+ /* 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.
+ * In this case, lookup the transport from the hash table.
*/
- else if ((flag & PJSIP_TRANSPORT_DATAGRAM) &&
- (remote_addr->sa_family == PJ_AF_INET))
- {
- pj_sockaddr_in *addr = (pj_sockaddr_in*)&key.addr;
+ struct transport_key key;
+ int key_len;
+ pjsip_transport *transport;
+
+ key_len = sizeof(key.type) + addr_len;
+
+ /* First try to get exact destination. */
+ key.type = type;
+ pj_memcpy(&key.addr, remote, addr_len);
- pj_bzero(addr, sizeof(pj_sockaddr_in));
- addr->sin_family = PJ_AF_INET;
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
+ if (transport == NULL) {
+ unsigned flag = pjsip_transport_get_flag_from_type(type);
+ const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
- key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
- transport = pj_hash_get(mgr->table, &key, key_len, NULL);
+ /* Ignore address for loop transports. */
+ if (type == PJSIP_TRANSPORT_LOOP ||
+ type == PJSIP_TRANSPORT_LOOP_DGRAM)
+ {
+ pj_sockaddr_in *addr = (pj_sockaddr_in*)&key.addr;
+
+ pj_bzero(addr, sizeof(pj_sockaddr_in));
+ key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
+ }
+ /* For datagram INET transports, try lookup with zero address.
+ */
+ else if ((flag & PJSIP_TRANSPORT_DATAGRAM) &&
+ (remote_addr->sa_family == PJ_AF_INET))
+ {
+ pj_sockaddr_in *addr = (pj_sockaddr_in*)&key.addr;
+
+ pj_bzero(addr, sizeof(pj_sockaddr_in));
+ addr->sin_family = PJ_AF_INET;
+
+ key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
+ }
}
- }
-
- if (transport!=NULL && !transport->is_shutdown) {
+
+ if (transport!=NULL && !transport->is_shutdown) {
+ /*
+ * Transport found!
+ */
+ pjsip_transport_add_ref(transport);
+ pj_lock_release(mgr->lock);
+ *tp = transport;
+
+ TRACE_((THIS_FILE, "Transport %s acquired", transport->obj_name));
+ return PJ_SUCCESS;
+ }
+
/*
- * Transport found!
+ * Transport not found!
+ * Find factory that can create such transport.
*/
- pjsip_transport_add_ref(transport);
- pj_lock_release(mgr->lock);
- *tp = transport;
-
- TRACE_((THIS_FILE, "Transport %s acquired", transport->obj_name));
- return PJ_SUCCESS;
- }
+ factory = mgr->factory_list.next;
+ while (factory != &mgr->factory_list) {
+ if (factory->type == type)
+ break;
+ factory = factory->next;
+ }
- /*
- * Transport not found!
- * 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 (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;
+ }
- 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;
}
- TRACE_((THIS_FILE, "%s, creating new one from factory",
- (transport?"Transport is shutdown":"No transport found")));
+
+ TRACE_((THIS_FILE, "Creating new transport from factory"));
/* Request factory to create transport. */
status = factory->create_transport(factory, mgr, mgr->endpt,
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index 0b72e568..6d9f3ff4 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -837,6 +837,7 @@ static void stateless_send_transport_cb( void *token,
cur_addr_type,
cur_addr,
cur_addr_len,
+ &tdata->tp_sel,
&stateless_data->cur_transport);
if (status != PJ_SUCCESS) {
sent = -status;
@@ -1111,6 +1112,7 @@ static void send_response_resolver_cb( pj_status_t status, void *token,
addr->entry[0].type,
&addr->entry[0].addr,
addr->entry[0].addr_len,
+ &send_state->tdata->tp_sel,
&send_state->cur_transport);
if (status != PJ_SUCCESS) {
if (send_state->app_cb) {