summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-09-19 13:37:53 +0000
committerBenny Prijono <bennylp@teluu.com>2006-09-19 13:37:53 +0000
commit4b188d682a36a7fa454884ca55b5cf5a7bad069c (patch)
treec7f94ec4bd11263869fc2ed8804a7864a93a0591
parentcf81bc0a2ab2947f4a2c5c5fd20bc77ea5611947 (diff)
Fixed race-condition/deadlock problems in the dialog/user agent layer
all the way up to PJSUA-API: - standardized locking order: dialog then user agent, and dialog then PJSUA - any threads that attempt to acquire mutexes in different order than above MUST employ retry mechanism (for an example, see acquire_call() in pjsua_call.c). This retry mechanism has also been used in the UA layer (sip_ua_layer.c) since it needs to lock user agent layer first before the dialog. - introduced pjsip_dlg_try_inc_lock() and PJSUA_TRY_LOCK() to accomodate above. - pjsua tested on Quad Xeon with 4 threads and 200 cps, so far so good. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@729 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c5
-rw-r--r--pjsip/include/pjsip/sip_dialog.h10
-rw-r--r--pjsip/include/pjsip/sip_ua_layer.h18
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h8
-rw-r--r--pjsip/src/pjsip/sip_dialog.c32
-rw-r--r--pjsip/src/pjsip/sip_ua_layer.c72
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c263
7 files changed, 227 insertions, 181 deletions
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index 57b6ad2e..0a495b03 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -1196,6 +1196,11 @@ static void call_timeout_callback(pj_timer_heap_t *timer_heap,
PJ_UNUSED_ARG(timer_heap);
+ if (call_id == PJSUA_INVALID_ID) {
+ PJ_LOG(1,(THIS_FILE, "Invalid call ID in timer callback"));
+ return;
+ }
+
/* Add warning header */
pjsua_msg_data_init(&msg_data);
pjsip_generic_string_hdr_init2(&warn, &hname, &hvalue);
diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h
index 191196a5..b4d2a1ac 100644
--- a/pjsip/include/pjsip/sip_dialog.h
+++ b/pjsip/include/pjsip/sip_dialog.h
@@ -356,6 +356,16 @@ PJ_DECL(void*) pjsip_dlg_get_mod_data( pjsip_dialog *dlg,
PJ_DECL(void) pjsip_dlg_inc_lock( pjsip_dialog *dlg );
/**
+ * Try to acquire dialog's lock, but return immediately if lock can not
+ * be acquired.
+ *
+ * @param dlg The dialog.
+ *
+ * @return PJ_SUCCESS if lock has been acquired.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_try_inc_lock( pjsip_dialog *dlg );
+
+/**
* Unlock dialog and decrement temporary session counter. After this function
* is called, dialog may be destroyed.
*
diff --git a/pjsip/include/pjsip/sip_ua_layer.h b/pjsip/include/pjsip/sip_ua_layer.h
index 08e692ca..c4e2d7c7 100644
--- a/pjsip/include/pjsip/sip_ua_layer.h
+++ b/pjsip/include/pjsip/sip_ua_layer.h
@@ -81,24 +81,6 @@ PJ_DECL(pjsip_user_agent*) pjsip_ua_instance(void);
/**
- * Lock the dialog's hash table. This function is normally called by
- * dialog code only.
- *
- * @return PJ_SUCCESS on success or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_ua_lock_dlg_table(void);
-
-
-/**
- * Unlock the dialog's hash table. This function is normally called by
- * dialog code only.
- *
- * @return PJ_SUCCESS on success or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_ua_unlock_dlg_table(void);
-
-
-/**
* Destroy the user agent layer.
*
* @return PJ_SUCCESS on success.
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index 8b1002b4..10e76635 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -257,11 +257,13 @@ PJ_INLINE(pjsua_im_data*) pjsua_im_data_dup(pj_pool_t *pool,
}
-#if 0
-#define PJSUA_LOCK() pj_mutex_lock(pjsua_var.mutex);
-#define PJSUA_UNLOCK() pj_mutex_unlock(pjsua_var.mutex);
+#if 1
+#define PJSUA_LOCK() pj_mutex_lock(pjsua_var.mutex)
+#define PJSUA_TRY_LOCK() pj_mutex_trylock(pjsua_var.mutex)
+#define PJSUA_UNLOCK() pj_mutex_unlock(pjsua_var.mutex)
#else
#define PJSUA_LOCK()
+#define PJSUA_TRY_LOCK() PJ_SUCCESS
#define PJSUA_UNLOCK()
#endif
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
index 6cc76141..aab06704 100644
--- a/pjsip/src/pjsip/sip_dialog.c
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -692,17 +692,37 @@ PJ_DEF(void) pjsip_dlg_inc_lock(pjsip_dialog *dlg)
PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_inc_lock(), sess_count=%d",
dlg->sess_count));
- pjsip_ua_lock_dlg_table();
-
pj_mutex_lock(dlg->mutex_);
dlg->sess_count++;
- //pjsip_ua_unlock_dlg_table();
-
PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_inc_lock(), sess_count=%d",
dlg->sess_count));
}
+/* Try to acquire dialog's mutex, but bail out if mutex can not be
+ * acquired immediately.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_try_inc_lock(pjsip_dialog *dlg)
+{
+ pj_status_t status;
+
+ PJ_LOG(6,(dlg->obj_name,"Entering pjsip_dlg_try_inc_lock(), sess_count=%d",
+ dlg->sess_count));
+
+ status = pj_mutex_trylock(dlg->mutex_);
+ if (status != PJ_SUCCESS) {
+ PJ_LOG(6,(dlg->obj_name, "pjsip_dlg_try_inc_lock() failed"));
+ return status;
+ }
+
+ dlg->sess_count++;
+
+ PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_try_inc_lock(), sess_count=%d",
+ dlg->sess_count));
+
+ return PJ_SUCCESS;
+}
+
/*
* Unlock dialog and decrement session counter.
@@ -713,8 +733,6 @@ PJ_DEF(void) pjsip_dlg_dec_lock(pjsip_dialog *dlg)
PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_dec_lock(), sess_count=%d",
dlg->sess_count));
- //pjsip_ua_lock_dlg_table();
-
pj_assert(dlg->sess_count > 0);
--dlg->sess_count;
@@ -726,8 +744,6 @@ PJ_DEF(void) pjsip_dlg_dec_lock(pjsip_dialog *dlg)
pj_mutex_unlock(dlg->mutex_);
}
- pjsip_ua_unlock_dlg_table();
-
PJ_LOG(6,(THIS_FILE, "Leaving pjsip_dlg_dec_lock() (dlg=%p)", dlg));
}
diff --git a/pjsip/src/pjsip/sip_ua_layer.c b/pjsip/src/pjsip/sip_ua_layer.c
index d8552ce0..48764081 100644
--- a/pjsip/src/pjsip/sip_ua_layer.c
+++ b/pjsip/src/pjsip/sip_ua_layer.c
@@ -209,30 +209,6 @@ PJ_DEF(pjsip_user_agent*) pjsip_ua_instance(void)
}
-/**
- * Lock the dialog's hash table. This function is normally called by
- * dialog code only.
- *
- * @return PJ_SUCCESS on success or the appropriate error code.
- */
-PJ_DEF(pj_status_t) pjsip_ua_lock_dlg_table(void)
-{
- return pj_mutex_lock(mod_ua.mutex);
-}
-
-
-/**
- * Unlock the dialog's hash table. This function is normally called by
- * dialog code only.
- *
- * @return PJ_SUCCESS on success or the appropriate error code.
- */
-PJ_DEF(pj_status_t) pjsip_ua_unlock_dlg_table(void)
-{
- return pj_mutex_unlock(mod_ua.mutex);
-}
-
-
/*
* Get the endpoint where this UA is currently registered.
*/
@@ -499,6 +475,7 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata)
struct dlg_set *dlg_set;
pj_str_t *from_tag;
pjsip_dialog *dlg;
+ pj_status_t status;
/* Optimized path: bail out early if request is not CANCEL and it doesn't
* have To tag
@@ -509,6 +486,8 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata)
return PJ_FALSE;
}
+retry_on_deadlock:
+
/* Lock user agent before looking up the dialog hash table. */
pj_mutex_lock(mod_ua.mutex);
@@ -585,9 +564,21 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata)
/* Mark the dialog id of the request. */
rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
- /* Lock the dialog */
+ /* Try to lock the dialog */
PJ_LOG(6,(dlg->obj_name, "UA layer acquiring dialog lock for request"));
- pjsip_dlg_inc_lock(dlg);
+ status = pjsip_dlg_try_inc_lock(dlg);
+ if (status != PJ_SUCCESS) {
+ /* Failed to acquire dialog mutex immediately, this could be
+ * because of deadlock. Release UA mutex, yield, and retry
+ * the whole thing once again.
+ */
+ pj_mutex_unlock(mod_ua.mutex);
+ pj_thread_sleep(0);
+ goto retry_on_deadlock;
+ }
+
+ /* Done with processing in UA layer, release lock */
+ pj_mutex_unlock(mod_ua.mutex);
/* Pass to dialog. */
pjsip_dlg_on_rx_request(dlg, rdata);
@@ -595,9 +586,6 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata)
/* Unlock the dialog. This may destroy the dialog */
pjsip_dlg_dec_lock(dlg);
- /* Done processing in the UA */
- pj_mutex_unlock(mod_ua.mutex);
-
/* Report as handled. */
return PJ_TRUE;
}
@@ -609,7 +597,8 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
{
pjsip_transaction *tsx;
struct dlg_set *dlg_set;
- pjsip_dialog *dlg = NULL;
+ pjsip_dialog *dlg;
+ pj_status_t status;
/*
* Find the dialog instance for the response.
@@ -621,6 +610,10 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
* the response is a forked response.
*/
+retry_on_deadlock:
+
+ dlg = NULL;
+
/* Lock user agent dlg table before we're doing anything. */
pj_mutex_lock(mod_ua.mutex);
@@ -782,9 +775,21 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
/* Put the dialog instance in the rdata. */
rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
- /* Acquire lock to the dialog. */
+ /* Attempt to acquire lock to the dialog. */
PJ_LOG(6,(dlg->obj_name, "UA layer acquiring dialog lock for response"));
- pjsip_dlg_inc_lock(dlg);
+ status = pjsip_dlg_try_inc_lock(dlg);
+ if (status != PJ_SUCCESS) {
+ /* Failed to acquire dialog mutex. This could indicate a deadlock
+ * situation, and for safety, try to avoid deadlock by releasing
+ * UA mutex, yield, and retry the whole processing once again.
+ */
+ pj_mutex_unlock(mod_ua.mutex);
+ pj_thread_sleep(0);
+ goto retry_on_deadlock;
+ }
+
+ /* We're done with processing in the UA layer, we can release the mutex */
+ pj_mutex_unlock(mod_ua.mutex);
/* Pass the response to the dialog. */
pjsip_dlg_on_rx_response(dlg, rdata);
@@ -792,9 +797,6 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
/* Unlock the dialog. This may destroy the dialog. */
pjsip_dlg_dec_lock(dlg);
- /* Unlock dialog hash table. */
- pj_mutex_unlock(mod_ua.mutex);
-
/* Done. */
return PJ_TRUE;
}
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index a7e0dd47..d9faeb0c 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -383,6 +383,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
if (dlg || tsx)
return PJ_FALSE;
+ PJSUA_LOCK();
/* Verify that we can handle the request. */
status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
@@ -407,6 +408,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
NULL, NULL);
}
+ PJSUA_UNLOCK();
return PJ_TRUE;
}
@@ -427,6 +429,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
NULL, NULL);
PJ_LOG(2,(THIS_FILE,
"Unable to accept incoming call (too many calls)"));
+ PJSUA_UNLOCK();
return PJ_TRUE;
}
@@ -445,6 +448,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
if (status != PJ_SUCCESS) {
pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
NULL, NULL);
+ PJSUA_UNLOCK();
return PJ_TRUE;
}
@@ -462,6 +466,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
NULL, NULL);
+ PJSUA_UNLOCK();
return PJ_TRUE;
}
@@ -471,7 +476,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
if (status != PJ_SUCCESS) {
pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
NULL, NULL);
-
+ PJSUA_UNLOCK();
return PJ_TRUE;
}
@@ -499,6 +504,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
/* Can't terminate dialog because transaction is in progress.
pjsip_dlg_terminate(dlg);
*/
+ PJSUA_UNLOCK();
return PJ_TRUE;
}
@@ -520,6 +526,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);
pjsip_inv_terminate(inv, 500, PJ_FALSE);
+ PJSUA_UNLOCK();
return PJ_TRUE;
} else {
@@ -536,6 +543,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
pjsua_var.ua_cfg.cb.on_incoming_call(acc_id, call_id, rdata);
/* This INVITE request has been handled. */
+ PJSUA_UNLOCK();
return PJ_TRUE;
}
@@ -565,17 +573,91 @@ PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id)
}
+/* Acquire lock to the specified call_id */
+static pj_status_t acquire_call(const char *title,
+ pjsua_call_id call_id,
+ pjsua_call **p_call)
+{
+ enum { MAX_RETRY=50 };
+ unsigned retry;
+ pjsua_call *call;
+ pj_bool_t has_pjsua_lock;
+ pj_status_t status;
+
+ for (retry=0; retry<MAX_RETRY; ++retry) {
+
+ has_pjsua_lock = PJ_FALSE;
+
+ status = PJSUA_TRY_LOCK();
+ if (status != PJ_SUCCESS) {
+ pj_thread_sleep(retry/10);
+ continue;
+ }
+
+ has_pjsua_lock = PJ_TRUE;
+ call = &pjsua_var.calls[call_id];
+
+ if (call->inv == NULL) {
+ PJSUA_UNLOCK();
+ PJ_LOG(3,(THIS_FILE, "Invalid call_id %d in %s", call_id, title));
+ return PJSIP_ESESSIONTERMINATED;
+ }
+
+ status = pjsip_dlg_try_inc_lock(call->inv->dlg);
+ if (status != PJ_SUCCESS) {
+ PJSUA_UNLOCK();
+ pj_thread_sleep(retry/10);
+ continue;
+ }
+
+ PJSUA_UNLOCK();
+
+ break;
+ }
+
+ if (status != PJ_SUCCESS) {
+ if (has_pjsua_lock == PJ_FALSE)
+ PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire PJSUA mutex "
+ "(possibly system has deadlocked) in %s",
+ title));
+ else
+ PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire dialog mutex "
+ "(possibly system has deadlocked) in %s",
+ title));
+ return PJ_ETIMEDOUT;
+ }
+
+ *p_call = call;
+
+ return PJ_SUCCESS;
+}
+
+
/*
* Get the conference port identification associated with the call.
*/
PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id)
{
+ pjsua_call *call;
+ pjsua_conf_port_id port_id;
+ pj_status_t status;
+
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- return pjsua_var.calls[call_id].conf_slot;
+
+ status = acquire_call("pjsua_call_get_conf_port()", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return -1;
+
+ port_id = call->conf_slot;
+
+ pjsip_dlg_dec_lock(call->inv->dlg);
+
+ return port_id;
}
+
/*
* Obtain detail information about the specified call.
*/
@@ -583,24 +665,18 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,
pjsua_call_info *info)
{
pjsua_call *call;
+ pj_status_t status;
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
pj_bzero(info, sizeof(*info));
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
-
- if (call->inv == NULL) {
- PJSUA_UNLOCK();
- return PJ_SUCCESS;
+ status = acquire_call("pjsua_call_get_info()", call_id, &call);
+ if (status != PJ_SUCCESS) {
+ return status;
}
- pjsip_dlg_inc_lock(call->inv->dlg);
-
-
/* id and role */
info->id = call_id;
info->role = call->inv->role;
@@ -696,7 +772,6 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,
}
pjsip_dlg_dec_lock(call->inv->dlg);
- PJSUA_UNLOCK();
return PJ_SUCCESS;
}
@@ -742,15 +817,9 @@ PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id,
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
-
- if (call->inv == NULL) {
- PJ_LOG(3,(THIS_FILE, "Call %d already disconnected", call_id));
- PJSUA_UNLOCK();
- return PJSIP_ESESSIONTERMINATED;
- }
+ status = acquire_call("pjsua_call_answer()", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
if (call->res_time.sec == 0)
pj_gettimeofday(&call->res_time);
@@ -760,7 +829,7 @@ PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id,
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating response",
status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -773,7 +842,7 @@ PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id,
pjsua_perror(THIS_FILE, "Error sending response",
status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -793,18 +862,17 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
pjsip_tx_data *tdata;
+ if (call_id<0 || call_id>=(int)pjsua_var.ua_cfg.max_calls) {
+ PJ_LOG(1,(THIS_FILE, "pjsua_call_hangup(): invalid call id %d",
+ call_id));
+ }
+
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Invalid call or call has been disconnected"));
- PJSUA_UNLOCK();
- return PJ_EINVAL;
- }
+ status = acquire_call("pjsua_call_hangup()", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
if (code==0) {
if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
@@ -820,7 +888,7 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
pjsua_perror(THIS_FILE,
"Failed to create end session message",
status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -829,7 +897,7 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
* with any provisional responses.
*/
if (tdata == NULL) {
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJ_SUCCESS;
}
@@ -842,11 +910,11 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
pjsua_perror(THIS_FILE,
"Failed to send end session message",
status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJ_SUCCESS;
}
@@ -866,25 +934,20 @@ PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id,
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
+ status = acquire_call("pjsua_call_set_hold()", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
- call = &pjsua_var.calls[call_id];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- PJSUA_UNLOCK();
- return PJSIP_ESESSIONTERMINATED;
- }
if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJSIP_ESESSIONSTATE;
}
status = create_inactive_sdp(call, &sdp);
if (status != PJ_SUCCESS) {
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -892,7 +955,7 @@ PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id,
status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -903,11 +966,11 @@ PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id,
status = pjsip_inv_send_msg( call->inv, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJ_SUCCESS;
}
@@ -929,20 +992,13 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id,
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- PJSUA_UNLOCK();
- return PJSIP_ESESSIONTERMINATED;
- }
-
+ status = acquire_call("pjsua_call_reinvite()", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJSIP_ESESSIONSTATE;
}
@@ -954,7 +1010,7 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id,
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint",
status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -962,7 +1018,7 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id,
status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -973,11 +1029,11 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id,
status = pjsip_inv_send_msg( call->inv, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJ_SUCCESS;
}
@@ -999,15 +1055,11 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id,
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
+ pjsip_dlg_dec_lock(call->inv->dlg);
+ status = acquire_call("pjsua_call_xfer()", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- PJSUA_UNLOCK();
- return PJSIP_ESESSIONTERMINATED;
- }
/* Create xfer client subscription.
* We're not interested in knowing the transfer result, so we
@@ -1016,7 +1068,7 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id,
status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create xfer", status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -1026,7 +1078,7 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id,
status = pjsip_xfer_initiate(sub, dest, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -1037,7 +1089,7 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id,
status = pjsip_xfer_send_request(sub, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -1046,7 +1098,7 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id,
* may want to hold the INVITE, or terminate the invite, or whatever.
*/
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJ_SUCCESS;
@@ -1065,19 +1117,21 @@ PJ_DEF(pj_status_t) pjsua_call_dial_dtmf( pjsua_call_id call_id,
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
+ status = acquire_call("pjsua_call_dial_dtmf()", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
call = &pjsua_var.calls[call_id];
if (!call->session) {
PJ_LOG(3,(THIS_FILE, "Media is not established yet!"));
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJ_EINVALIDOP;
}
status = pjmedia_session_dial_dtmf( call->session, 0, digits);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return status;
}
@@ -1103,19 +1157,10 @@ PJ_DEF(pj_status_t) pjsua_call_send_im( pjsua_call_id call_id,
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- PJSUA_UNLOCK();
- return PJSIP_ESESSIONTERMINATED;
- }
-
- /* Lock dialog. */
- pjsip_dlg_inc_lock(call->inv->dlg);
-
+ status = acquire_call("pjsua_call_send_im", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
+
/* Set default media type if none is specified */
if (mime_type == NULL) {
mime_type = &mime_text_plain;
@@ -1167,7 +1212,6 @@ PJ_DEF(pj_status_t) pjsua_call_send_im( pjsua_call_id call_id,
on_return:
pjsip_dlg_dec_lock(call->inv->dlg);
- PJSUA_UNLOCK();
return status;
}
@@ -1183,23 +1227,13 @@ PJ_DEF(pj_status_t) pjsua_call_send_typing_ind( pjsua_call_id call_id,
pjsip_tx_data *tdata;
pj_status_t status;
-
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
-
- if (!call->inv) {
- PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
- PJSUA_UNLOCK();
- return PJSIP_ESESSIONTERMINATED;
- }
+ status = acquire_call("pjsua_call_send_typing_ind", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
- /* Lock dialog. */
- pjsip_dlg_inc_lock(call->inv->dlg);
-
/* Create request message. */
status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
-1, &tdata);
@@ -1224,7 +1258,6 @@ PJ_DEF(pj_status_t) pjsua_call_send_typing_ind( pjsua_call_id call_id,
on_return:
pjsip_dlg_dec_lock(call->inv->dlg);
- PJSUA_UNLOCK();
return status;
}
@@ -1501,25 +1534,21 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id,
pj_time_val duration, res_delay, con_delay;
char tmp[128];
char *p, *end;
+ pj_status_t status;
int len;
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- PJSUA_LOCK();
-
- call = &pjsua_var.calls[call_id];
+ status = acquire_call("pjsua_call_dump()", call_id, &call);
+ if (status != PJ_SUCCESS)
+ return status;
*buffer = '\0';
p = buffer;
end = buffer + maxlen;
len = 0;
- if (call->inv == NULL) {
- PJSUA_UNLOCK();
- return PJ_EINVALIDOP;
- }
-
print_call(indent, call_id, tmp, sizeof(tmp));
len = pj_ansi_strlen(tmp);
@@ -1569,7 +1598,7 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id,
if (with_media && call->session)
dump_media_session(indent, p, end-p, call->session);
- PJSUA_UNLOCK();
+ pjsip_dlg_dec_lock(call->inv->dlg);
return PJ_SUCCESS;
}