summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2016-02-05 04:29:17 +0000
committerNanang Izzuddin <nanang@teluu.com>2016-02-05 04:29:17 +0000
commit3985dd57937870f3d47a4ddd68b477a42ffddec1 (patch)
tree7cfd8a02592a91bbae1f72e1792bac0954a0e1db
parent09977f8551064c5972ea5d23605bfd4adb886189 (diff)
Fixed #1902:
- Crash when endpoint has multiple worker threads and SIP TCP transport is disconnected during incoming call handling. - Deprecated pjsip_dlg_create_uas(), replaced by pjsip_dlg_create_uas_and_inc_lock(). - Serialized transaction state notifications (of 'terminated' and 'destroyed') in case of transport error. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5241 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip-apps/src/samples/footprint.c2
-rw-r--r--pjsip-apps/src/samples/pjsip-perf.c8
-rw-r--r--pjsip-apps/src/samples/simpleua.c25
-rw-r--r--pjsip-apps/src/samples/sipecho.c11
-rw-r--r--pjsip-apps/src/samples/siprtp.c7
-rw-r--r--pjsip/include/pjsip-ua/sip_replaces.h2
-rw-r--r--pjsip/include/pjsip/sip_dialog.h59
-rw-r--r--pjsip/src/pjsip/sip_dialog.c49
-rw-r--r--pjsip/src/pjsip/sip_transaction.c112
-rw-r--r--pjsip/src/pjsip/sip_ua_layer.c2
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c26
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c4
-rw-r--r--pjsip/src/pjsua-lib/pjsua_pres.c9
-rw-r--r--pjsip/src/test/inv_offer_answer_test.c5
14 files changed, 240 insertions, 81 deletions
diff --git a/pjsip-apps/src/samples/footprint.c b/pjsip-apps/src/samples/footprint.c
index 9b666874..74e6be43 100644
--- a/pjsip-apps/src/samples/footprint.c
+++ b/pjsip-apps/src/samples/footprint.c
@@ -341,7 +341,7 @@ int dummy_function()
pjsip_ua_init_module(NULL, NULL);
pjsip_ua_destroy();
pjsip_dlg_create_uac(NULL, NULL, NULL, NULL, NULL, NULL);
- pjsip_dlg_create_uas(NULL, NULL, NULL, NULL);
+ pjsip_dlg_create_uas_and_inc_lock(NULL, NULL, NULL, NULL);
pjsip_dlg_terminate(NULL);
pjsip_dlg_set_route_set(NULL, NULL);
pjsip_dlg_create_request(NULL, NULL, -1, NULL);
diff --git a/pjsip-apps/src/samples/pjsip-perf.c b/pjsip-apps/src/samples/pjsip-perf.c
index 10bde943..bc963330 100644
--- a/pjsip-apps/src/samples/pjsip-perf.c
+++ b/pjsip-apps/src/samples/pjsip-perf.c
@@ -475,8 +475,8 @@ static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata)
}
/* Create UAS dialog */
- status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
- &app.local_contact, &dlg);
+ status = pjsip_dlg_create_uas_and_inc_lock( pjsip_ua_instance(), rdata,
+ &app.local_contact, &dlg);
if (status != PJ_SUCCESS) {
const pj_str_t reason = pj_str("Unable to create dialog");
pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
@@ -502,9 +502,13 @@ static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata)
if (status != PJ_SUCCESS) {
pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata);
pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
+ pjsip_dlg_dec_lock(dlg);
return PJ_TRUE;
}
+ /* Invite session has been created, decrement & release dialog lock. */
+ pjsip_dlg_dec_lock(dlg);
+
/* Send 100/Trying if needed */
if (app.server.send_trying) {
status = send_response(call->inv, rdata, 100, &has_initial);
diff --git a/pjsip-apps/src/samples/simpleua.c b/pjsip-apps/src/samples/simpleua.c
index b7f10250..a1bac754 100644
--- a/pjsip-apps/src/samples/simpleua.c
+++ b/pjsip-apps/src/samples/simpleua.c
@@ -725,10 +725,10 @@ static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
/*
* Create UAS dialog.
*/
- status = pjsip_dlg_create_uas( pjsip_ua_instance(),
- rdata,
- &local_uri, /* contact */
- &dlg);
+ status = pjsip_dlg_create_uas_and_inc_lock( pjsip_ua_instance(),
+ rdata,
+ &local_uri, /* contact */
+ &dlg);
if (status != PJ_SUCCESS) {
pjsip_endpt_respond_stateless(g_endpt, rdata, 500, NULL,
NULL, NULL);
@@ -741,7 +741,11 @@ static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool,
MAX_MEDIA_CNT, g_sock_info, &local_sdp);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
+ pj_assert(status == PJ_SUCCESS);
+ if (status != PJ_SUCCESS) {
+ pjsip_dlg_dec_lock(dlg);
+ return PJ_TRUE;
+ }
/*
@@ -749,7 +753,16 @@ static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
* capability to the session.
*/
status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &g_inv);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
+ pj_assert(status == PJ_SUCCESS);
+ if (status != PJ_SUCCESS) {
+ pjsip_dlg_dec_lock(dlg);
+ return PJ_TRUE;
+ }
+
+ /*
+ * Invite session has been created, decrement & release dialog lock.
+ */
+ pjsip_dlg_dec_lock(dlg);
/*
diff --git a/pjsip-apps/src/samples/sipecho.c b/pjsip-apps/src/samples/sipecho.c
index 6c5244d8..b0fb4c2f 100644
--- a/pjsip-apps/src/samples/sipecho.c
+++ b/pjsip-apps/src/samples/sipecho.c
@@ -417,7 +417,7 @@ static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
pj_sockaddr hostaddr;
char temp[80], hostip[PJ_INET6_ADDRSTRLEN];
pj_str_t local_uri;
- pjsip_dialog *dlg;
+ pjsip_dialog *dlg = NULL;
pjsip_rdata_sdp_info *sdp_info;
pjmedia_sdp_session *answer = NULL;
pjsip_tx_data *tdata = NULL;
@@ -498,13 +498,18 @@ static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>", hostip, sip_port);
local_uri = pj_str(temp);
- status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
- &local_uri, &dlg);
+ status = pjsip_dlg_create_uas_and_inc_lock( pjsip_ua_instance(), rdata,
+ &local_uri, &dlg);
if (status == PJ_SUCCESS)
answer = create_answer((int)(call-app.call), dlg->pool, sdp_info->sdp);
+
if (status == PJ_SUCCESS)
status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &call->inv);
+
+ if (dlg)
+ pjsip_dlg_dec_lock(dlg);
+
if (status == PJ_SUCCESS)
status = pjsip_inv_initial_answer(call->inv, rdata, 100,
NULL, NULL, &tdata);
diff --git a/pjsip-apps/src/samples/siprtp.c b/pjsip-apps/src/samples/siprtp.c
index 262e2033..8e74c338 100644
--- a/pjsip-apps/src/samples/siprtp.c
+++ b/pjsip-apps/src/samples/siprtp.c
@@ -637,8 +637,8 @@ static void process_incoming_call(pjsip_rx_data *rdata)
}
/* Create UAS dialog */
- status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
- &app.local_contact, &dlg);
+ status = pjsip_dlg_create_uas_and_inc_lock( pjsip_ua_instance(), rdata,
+ &app.local_contact, &dlg);
if (status != PJ_SUCCESS) {
const pj_str_t reason = pj_str("Unable to create dialog");
pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
@@ -655,9 +655,12 @@ static void process_incoming_call(pjsip_rx_data *rdata)
if (status != PJ_SUCCESS) {
pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata);
pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
+ pjsip_dlg_dec_lock(dlg);
return;
}
+ /* Invite session has been created, decrement & release dialog lock */
+ pjsip_dlg_dec_lock(dlg);
/* Attach call data to invite session */
call->inv->mod_data[mod_siprtp.id] = call;
diff --git a/pjsip/include/pjsip-ua/sip_replaces.h b/pjsip/include/pjsip-ua/sip_replaces.h
index aff44498..4544b7ac 100644
--- a/pjsip/include/pjsip-ua/sip_replaces.h
+++ b/pjsip/include/pjsip-ua/sip_replaces.h
@@ -138,7 +138,7 @@
// Create UAS Invite session as usual.
//
- status = pjsip_dlg_create_uas(.., rdata, .., &dlg);
+ status = pjsip_dlg_create_uas_and_inc_lock(.., rdata, .., &dlg);
..
status = pjsip_inv_create_uas(dlg, .., &inv);
diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h
index 9f37c32f..7f68476c 100644
--- a/pjsip/include/pjsip/sip_dialog.h
+++ b/pjsip/include/pjsip/sip_dialog.h
@@ -61,6 +61,15 @@
PJ_BEGIN_DECL
+/* Deprecated API pjsip_dlg_create_uas() due to a fatal bug of possible
+ * premature dialog destroy. Application should not change this setting,
+ * unless it uses single worker thread.
+ * See also https://trac.pjsip.org/repos/ticket/1902.
+ */
+#ifndef DEPRECATED_FOR_TICKET_1902
+# define DEPRECATED_FOR_TICKET_1902 1
+#endif
+
/**
* This structure is used to describe dialog's participants, which in this
* case is local party (i.e. us) and remote party.
@@ -240,6 +249,7 @@ PJ_DECL(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
pjsip_dialog **p_dlg);
+#if !DEPRECATED_FOR_TICKET_1902
/**
* Initialize UAS dialog from the information found in the incoming request
* that creates a dialog (such as INVITE, REFER, or SUBSCRIBE), and set the
@@ -279,6 +289,50 @@ PJ_DECL(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
pjsip_rx_data *rdata,
const pj_str_t *contact,
pjsip_dialog **p_dlg);
+#endif
+
+
+/**
+ * Initialize UAS dialog from the information found in the incoming request
+ * that creates a dialog (such as INVITE, REFER, or SUBSCRIBE), and set the
+ * local Contact to contact. If contact is not specified, the local contact
+ * is initialized from the URI in the To header in the request.
+ *
+ * This function will also create UAS transaction for the incoming request,
+ * and associate the transaction to the rdata. Application can query the
+ * transaction used to handle this request by calling #pjsip_rdata_get_tsx()
+ * after this function returns.
+ *
+ * Note that initially, the session count in the dialog will be initialized
+ * to 1 (one), and the dialog is locked. Application needs to explicitly call
+ * #pjsip_dlg_dec_lock() to release the lock and decrease the session count.
+ *
+ *
+ * @param ua The user agent module instance.
+ * @param rdata The incoming request that creates the dialog,
+ * such as INVITE, SUBSCRIBE, or REFER.
+ * @param contact Optional dialog local Contact to be put as Contact
+ * header value, hence the format must follow
+ * RFC 3261 Section 20.10:
+ * When the header field value contains a display
+ * name, the URI including all URI parameters is
+ * enclosed in "<" and ">". If no "<" and ">" are
+ * present, all parameters after the URI are header
+ * parameters, not URI parameters. The display name
+ * can be tokens, or a quoted string, if a larger
+ * character set is desired.
+ * If this argument is NULL, the local contact will be
+ * initialized from the value of To header in the
+ * request.
+ * @param p_dlg Pointer to receive the dialog.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t)
+pjsip_dlg_create_uas_and_inc_lock( pjsip_user_agent *ua,
+ pjsip_rx_data *rdata,
+ const pj_str_t *contact,
+ pjsip_dialog **p_dlg);
/**
@@ -361,8 +415,9 @@ PJ_DECL(pj_status_t) pjsip_dlg_terminate( pjsip_dialog *dlg );
* for UAC dialog, before any request is sent. After dialog has been
* established, the route set can not be changed.
*
- * For UAS dialog,the route set will be initialized in pjsip_dlg_create_uas()
- * from the Record-Route headers in the incoming request.
+ * For UAS dialog, the route set will be initialized in
+ * pjsip_dlg_create_uas_and_inc_lock() from the Record-Route headers in
+ * the incoming request.
*
* The route_set argument is standard list of Route headers (i.e. with
* sentinel).
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
index d158bc3d..1964caa9 100644
--- a/pjsip/src/pjsip/sip_dialog.c
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -311,10 +311,11 @@ on_error:
/*
* Create UAS dialog.
*/
-PJ_DEF(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
- pjsip_rx_data *rdata,
- const pj_str_t *contact,
- pjsip_dialog **p_dlg)
+pj_status_t create_uas_dialog( pjsip_user_agent *ua,
+ pjsip_rx_data *rdata,
+ const pj_str_t *contact,
+ pj_bool_t inc_lock,
+ pjsip_dialog **p_dlg)
{
pj_status_t status;
pjsip_hdr *pos = NULL;
@@ -510,6 +511,12 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
if (status != PJ_SUCCESS)
goto on_error;
+ /* Increment the dialog's lock since tsx may cause the dialog to be
+ * destroyed prematurely (such as in case of transport error).
+ */
+ if (inc_lock)
+ pjsip_dlg_inc_lock(dlg);
+
/* Create UAS transaction for this request. */
status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
if (status != PJ_SUCCESS)
@@ -552,11 +559,43 @@ on_error:
--dlg->tsx_count;
}
- destroy_dialog(dlg, PJ_FALSE);
+ if (inc_lock) {
+ pjsip_dlg_dec_lock(dlg);
+ } else {
+ destroy_dialog(dlg, PJ_FALSE);
+ }
+
return status;
}
+#if !DEPRECATED_FOR_TICKET_1902
+/*
+ * Create UAS dialog.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
+ pjsip_rx_data *rdata,
+ const pj_str_t *contact,
+ pjsip_dialog **p_dlg)
+{
+ return create_uas_dialog(ua, rdata, contact, PJ_FALSE, p_dlg);
+}
+#endif
+
+
+/*
+ * Create UAS dialog and increase its session count.
+ */
+PJ_DEF(pj_status_t)
+pjsip_dlg_create_uas_and_inc_lock( pjsip_user_agent *ua,
+ pjsip_rx_data *rdata,
+ const pj_str_t *contact,
+ pjsip_dialog **p_dlg)
+{
+ return create_uas_dialog(ua, rdata, contact, PJ_TRUE, p_dlg);
+}
+
+
/*
* Bind dialog to a specific transport/listener.
*/
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index ccd3af61..46bd971c 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -138,6 +138,12 @@ static pj_time_val timeout_timer_val = { (64*PJSIP_T1_TIMEOUT)/1000,
#define TIMEOUT_TIMER 2
#define TRANSPORT_ERR_TIMER 3
+/* Flags for tsx_set_state() */
+enum
+{
+ NO_NOTIFY = 1,
+ NO_SCHEDULE_HANDLER = 2,
+};
/* Prototypes. */
static pj_status_t tsx_on_state_null( pjsip_transaction *tsx,
@@ -169,11 +175,8 @@ static void tsx_tp_state_callback(
static void tsx_set_state( pjsip_transaction *tsx,
pjsip_tsx_state_e state,
pjsip_event_id_e event_src_type,
- void *event_src );
-static void tsx_set_state_no_notify( pjsip_transaction *tsx,
- pjsip_tsx_state_e state,
- pjsip_event_id_e event_src_type,
- void *event_src );
+ void *event_src,
+ int flag);
static void tsx_set_status_code(pjsip_transaction *tsx,
int code, const pj_str_t *reason);
static pj_status_t tsx_create( pjsip_module *tsx_user,
@@ -1103,6 +1106,7 @@ static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry)
entry->id = 0;
if (tsx->state < PJSIP_TSX_STATE_TERMINATED) {
pjsip_tsx_state_e prev_state;
+ pj_time_val timeout = { 0, 0 };
pj_grp_lock_acquire(tsx->grp_lock);
prev_state = tsx->state;
@@ -1122,8 +1126,15 @@ static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry)
* otherwise we'll get a deadlock. See:
* https://trac.pjsip.org/repos/ticket/1646
*/
- tsx_set_state_no_notify( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TRANSPORT_ERROR, NULL);
+ /* Also don't schedule tsx handler, otherwise we'll get race
+ * condition of TU notifications due to delayed TERMINATED
+ * state TU notification. It happened in multiple worker threads
+ * environment between TERMINATED & DESTROYED! See:
+ * https://trac.pjsip.org/repos/ticket/1902
+ */
+ tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
+ PJSIP_EVENT_TRANSPORT_ERROR, NULL,
+ NO_NOTIFY | NO_SCHEDULE_HANDLER);
pj_grp_lock_release(tsx->grp_lock);
/* Now notify TU about state change, WITHOUT holding the
@@ -1138,6 +1149,10 @@ static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry)
prev_state);
(*tsx->tsx_user->on_tsx_state)(tsx, &e);
}
+
+ /* Now let's schedule the tsx handler */
+ tsx_schedule_timer(tsx, &tsx->timeout_timer, &timeout,
+ TIMEOUT_TIMER);
}
} else {
pjsip_event event;
@@ -1167,7 +1182,8 @@ static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry)
static void tsx_set_state( pjsip_transaction *tsx,
pjsip_tsx_state_e state,
pjsip_event_id_e event_src_type,
- void *event_src )
+ void *event_src,
+ int flag)
{
pjsip_tsx_state_e prev_state = tsx->state;
@@ -1192,7 +1208,9 @@ static void tsx_set_state( pjsip_transaction *tsx,
/* Before informing TU about state changed, inform TU about
* rx event.
*/
- if (event_src_type==PJSIP_EVENT_RX_MSG && tsx->tsx_user) {
+ if (event_src_type==PJSIP_EVENT_RX_MSG && tsx->tsx_user &&
+ (flag & NO_NOTIFY)==0)
+ {
pjsip_rx_data *rdata = (pjsip_rx_data*) event_src;
pj_assert(rdata != NULL);
@@ -1206,7 +1224,9 @@ static void tsx_set_state( pjsip_transaction *tsx,
}
/* Inform TU about state changed. */
- if (tsx->tsx_user && tsx->tsx_user->on_tsx_state) {
+ if (tsx->tsx_user && tsx->tsx_user->on_tsx_state &&
+ (flag & NO_NOTIFY) == 0)
+ {
pjsip_event e;
PJSIP_EVENT_INIT_TSX_STATE(e, tsx, event_src_type, event_src,
prev_state);
@@ -1218,7 +1238,7 @@ static void tsx_set_state( pjsip_transaction *tsx,
* saved last transmitted message.
*/
if (state == PJSIP_TSX_STATE_TERMINATED) {
- pj_time_val timeout = {0, 0};
+ pj_time_val timeout = { 0, 0 };
/* If we're still waiting for a message to be sent.. */
if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
@@ -1236,7 +1256,10 @@ static void tsx_set_state( pjsip_transaction *tsx,
lock_timer(tsx);
tsx_cancel_timer(tsx, &tsx->timeout_timer);
- tsx_schedule_timer( tsx, &tsx->timeout_timer, &timeout, TIMEOUT_TIMER);
+ if ((flag & NO_SCHEDULE_HANDLER) == 0) {
+ tsx_schedule_timer(tsx, &tsx->timeout_timer, &timeout,
+ TIMEOUT_TIMER);
+ }
unlock_timer(tsx);
} else if (state == PJSIP_TSX_STATE_DESTROYED) {
@@ -1251,18 +1274,6 @@ static void tsx_set_state( pjsip_transaction *tsx,
pj_log_pop_indent();
}
-/* Set transaction state without notifying tsx_user */
-static void tsx_set_state_no_notify( pjsip_transaction *tsx,
- pjsip_tsx_state_e state,
- pjsip_event_id_e event_src_type,
- void *event_src )
-{
- pjsip_module *tsx_user = tsx->tsx_user;
- tsx->tsx_user = NULL;
- tsx_set_state(tsx, state, event_src_type, event_src);
- tsx->tsx_user = tsx_user;
-}
-
/*
* Create, initialize, and register UAC transaction.
*/
@@ -1626,7 +1637,8 @@ PJ_DEF(pj_status_t) pjsip_tsx_terminate( pjsip_transaction *tsx, int code )
if (tsx->state < PJSIP_TSX_STATE_TERMINATED) {
tsx_set_status_code(tsx, code, NULL);
- tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, PJSIP_EVENT_USER, NULL);
+ tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, PJSIP_EVENT_USER,
+ NULL, 0);
}
pj_grp_lock_release(tsx->grp_lock);
@@ -1837,7 +1849,7 @@ static void send_msg_callback( pjsip_send_state *send_state,
/* Pending destroy? */
if (tsx->transport_flag & TSX_HAS_PENDING_DESTROY) {
tsx_set_state( tsx, PJSIP_TSX_STATE_DESTROYED,
- PJSIP_EVENT_UNKNOWN, NULL );
+ PJSIP_EVENT_UNKNOWN, NULL, 0 );
pj_grp_lock_release(tsx->grp_lock);
return;
}
@@ -1912,7 +1924,8 @@ static void send_msg_callback( pjsip_send_state *send_state,
tsx->state != PJSIP_TSX_STATE_DESTROYED)
{
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TRANSPORT_ERROR, send_state->tdata);
+ PJSIP_EVENT_TRANSPORT_ERROR,
+ send_state->tdata, 0);
}
/* Don't forget to destroy if we have pending destroy flag
* (http://trac.pjsip.org/repos/ticket/906)
@@ -1920,7 +1933,8 @@ static void send_msg_callback( pjsip_send_state *send_state,
else if (tsx->transport_flag & TSX_HAS_PENDING_DESTROY)
{
tsx_set_state( tsx, PJSIP_TSX_STATE_DESTROYED,
- PJSIP_EVENT_TRANSPORT_ERROR, send_state->tdata);
+ PJSIP_EVENT_TRANSPORT_ERROR,
+ send_state->tdata, 0);
}
} else {
@@ -2122,7 +2136,7 @@ static pj_status_t tsx_send_msg( pjsip_transaction *tsx,
tsx_set_status_code(tsx, PJSIP_SC_TSX_TRANSPORT_ERROR, &err);
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TRANSPORT_ERROR, NULL );
+ PJSIP_EVENT_TRANSPORT_ERROR, NULL, 0 );
return status;
}
@@ -2354,7 +2368,7 @@ static pj_status_t tsx_on_state_null( pjsip_transaction *tsx,
event->body.rx_msg.rdata->msg_info.msg->type ==
PJSIP_REQUEST_MSG);
tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, PJSIP_EVENT_RX_MSG,
- event->body.rx_msg.rdata);
+ event->body.rx_msg.rdata, 0);
} else {
pjsip_tx_data *tdata;
@@ -2409,7 +2423,7 @@ static pj_status_t tsx_on_state_null( pjsip_transaction *tsx,
/* Move state. */
tsx_set_state( tsx, PJSIP_TSX_STATE_CALLING,
- PJSIP_EVENT_TX_MSG, tdata);
+ PJSIP_EVENT_TX_MSG, tdata, 0);
}
return PJ_SUCCESS;
@@ -2450,7 +2464,7 @@ static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx,
/* Inform TU. */
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TIMER, &tsx->timeout_timer);
+ PJSIP_EVENT_TIMER, &tsx->timeout_timer, 0);
/* Transaction is destroyed */
//return PJSIP_ETSXDESTROYED;
@@ -2569,7 +2583,7 @@ static pj_status_t tsx_on_state_trying( pjsip_transaction *tsx,
if (status==PJ_SUCCESS && tsx->state == PJSIP_TSX_STATE_TRYING) {
tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING,
- PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata);
+ PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata, 0);
}
@@ -2650,7 +2664,7 @@ static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
}
tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING,
- PJSIP_EVENT_TX_MSG, tdata );
+ PJSIP_EVENT_TX_MSG, tdata, 0 );
/* Retransmit provisional response every 1 minute if this is
* an INVITE provisional response greater than 100.
@@ -2684,7 +2698,7 @@ static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
* is handled by TU.
*/
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TX_MSG, tdata );
+ PJSIP_EVENT_TX_MSG, tdata, 0 );
/* Transaction is destroyed. */
//return PJSIP_ETSXDESTROYED;
@@ -2742,7 +2756,7 @@ static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
/* Set state to "Completed" */
tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED,
- PJSIP_EVENT_TX_MSG, tdata );
+ PJSIP_EVENT_TX_MSG, tdata, 0 );
}
} else if (tsx->status_code >= 300) {
@@ -2801,7 +2815,7 @@ static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
/* Inform TU */
tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED,
- PJSIP_EVENT_TX_MSG, tdata );
+ PJSIP_EVENT_TX_MSG, tdata, 0 );
} else {
pj_assert(0);
@@ -2835,7 +2849,7 @@ static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL);
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TIMER, &tsx->timeout_timer);
+ PJSIP_EVENT_TIMER, &tsx->timeout_timer, 0);
return PJ_EBUG;
@@ -2900,7 +2914,7 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx,
/* Inform the message to TU. */
tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING,
- PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
+ PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata, 0 );
} else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code,200)) {
@@ -2914,7 +2928,7 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx,
*/
if (tsx->method.id == PJSIP_INVITE_METHOD) {
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
+ PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata, 0 );
//return PJSIP_ETSXDESTROYED;
} else {
@@ -2941,7 +2955,7 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx,
/* Move state to Completed, inform TU. */
tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED,
- PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
+ PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata, 0 );
}
} else if (event->type == PJSIP_EVENT_TIMER &&
@@ -2949,7 +2963,7 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx,
/* Inform TU. */
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TIMER, &tsx->timeout_timer);
+ PJSIP_EVENT_TIMER, &tsx->timeout_timer, 0);
} else if (tsx->status_code >= 300 && tsx->status_code <= 699) {
@@ -3040,7 +3054,7 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx,
/* Inform TU. */
tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED,
- PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata);
+ PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata, 0);
/* Generate and send ACK for INVITE. */
if (tsx->method.id == PJSIP_INVITE_METHOD) {
@@ -3151,7 +3165,7 @@ static pj_status_t tsx_on_state_completed_uas( pjsip_transaction *tsx,
/* Move state to "Confirmed" */
tsx_set_state( tsx, PJSIP_TSX_STATE_CONFIRMED,
- PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
+ PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata, 0 );
}
} else if (event->type == PJSIP_EVENT_TIMER) {
@@ -3175,14 +3189,14 @@ static pj_status_t tsx_on_state_completed_uas( pjsip_transaction *tsx,
tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL);
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TIMER, &tsx->timeout_timer );
+ PJSIP_EVENT_TIMER, &tsx->timeout_timer, 0 );
//return PJSIP_ETSXDESTROYED;
} else {
/* Transaction terminated, it can now be deleted. */
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TIMER, &tsx->timeout_timer );
+ PJSIP_EVENT_TIMER, &tsx->timeout_timer, 0 );
//return PJSIP_ETSXDESTROYED;
}
}
@@ -3215,7 +3229,7 @@ static pj_status_t tsx_on_state_completed_uac( pjsip_transaction *tsx,
/* Move to Terminated state. */
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TIMER, event->body.timer.entry );
+ PJSIP_EVENT_TIMER, event->body.timer.entry, 0 );
/* Transaction has been destroyed. */
//return PJSIP_ETSXDESTROYED;
@@ -3290,7 +3304,7 @@ static pj_status_t tsx_on_state_confirmed( pjsip_transaction *tsx,
/* Move to Terminated state. */
tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
- PJSIP_EVENT_TIMER, &tsx->timeout_timer );
+ PJSIP_EVENT_TIMER, &tsx->timeout_timer, 0 );
/* Transaction has been destroyed. */
//return PJSIP_ETSXDESTROYED;
@@ -3321,7 +3335,7 @@ static pj_status_t tsx_on_state_terminated( pjsip_transaction *tsx,
/* Destroy this transaction */
tsx_set_state(tsx, PJSIP_TSX_STATE_DESTROYED,
- event->type, event->body.user.user1 );
+ event->type, event->body.user.user1, 0 );
return PJ_SUCCESS;
}
diff --git a/pjsip/src/pjsip/sip_ua_layer.c b/pjsip/src/pjsip/sip_ua_layer.c
index 021005a4..716d25a2 100644
--- a/pjsip/src/pjsip/sip_ua_layer.c
+++ b/pjsip/src/pjsip/sip_ua_layer.c
@@ -277,7 +277,7 @@ static struct dlg_set *alloc_dlgset_node(void)
/*
* Register new dialog. Called by pjsip_dlg_create_uac() and
- * pjsip_dlg_create_uas();
+ * pjsip_dlg_create_uas_and_inc_lock();
*/
PJ_DEF(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
pjsip_dialog *dlg )
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index 86306ffd..bb549654 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -982,10 +982,19 @@ on_incoming_call_med_tp_complete(pjsua_call_id call_id,
pjmedia_sdp_session *answer;
pjsip_tx_data *response = NULL;
unsigned options = 0;
+ pjsip_dialog *dlg = call->async_call.dlg;
int sip_err_code = (info? info->sip_err_code: 0);
pj_status_t status = (info? info->status: PJ_SUCCESS);
PJSUA_LOCK();
+
+ /* Increment the dialog's lock to prevent it to be destroyed prematurely,
+ * such as in case of transport error.
+ */
+ pjsip_dlg_inc_lock(dlg);
+
+ /* Decrement dialog session. */
+ pjsip_dlg_dec_session(dlg, &pjsua_var.mod);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error initializing media channel", status);
@@ -996,6 +1005,7 @@ on_incoming_call_med_tp_complete(pjsua_call_id call_id,
if (call->async_call.med_ch_deinit) {
pjsua_media_channel_deinit(call->index);
call->med_ch_cb = NULL;
+ pjsip_dlg_dec_lock(dlg);
PJSUA_UNLOCK();
return PJ_SUCCESS;
}
@@ -1067,7 +1077,9 @@ on_return:
process_pending_call_answer(call);
}
}
-
+
+ pjsip_dlg_dec_lock(dlg);
+
PJSUA_UNLOCK();
return status;
}
@@ -1351,8 +1363,8 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
}
/* Create dialog: */
- status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
- &contact, &dlg);
+ status = pjsip_dlg_create_uas_and_inc_lock( pjsip_ua_instance(), rdata,
+ &contact, &dlg);
if (status != PJ_SUCCESS) {
pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
NULL, NULL);
@@ -1460,6 +1472,8 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
call->async_call.dlg = dlg;
pj_list_init(&call->async_call.call_var.inc_call.answers);
+ pjsip_dlg_inc_session(dlg, &pjsua_var.mod);
+
/* Init media channel, only when there is offer or call replace request.
* For incoming call without SDP offer, media channel init will be done
* in pjsua_call_answer(), see ticket #1526.
@@ -1501,6 +1515,8 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
}
pjsip_dlg_dec_lock(dlg);
+ pjsip_dlg_dec_session(dlg, &pjsua_var.mod);
+
call->inv = NULL;
call->async_call.dlg = NULL;
goto on_return;
@@ -1618,6 +1634,10 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
/* This INVITE request has been handled. */
on_return:
+ if (dlg) {
+ pjsip_dlg_dec_lock(dlg);
+ }
+
pj_log_pop_indent();
PJSUA_UNLOCK();
return PJ_TRUE;
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index c3e919df..41254c4c 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -1105,7 +1105,9 @@ PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg,
pjsua_var.ua_cfg.thread_cnt = PJ_ARRAY_SIZE(pjsua_var.thread);
for (ii=0; ii<pjsua_var.ua_cfg.thread_cnt; ++ii) {
- status = pj_thread_create(pjsua_var.pool, "pjsua", &worker_thread,
+ char thread_name[16];
+ pj_ansi_snprintf(thread_name, 16, "pjsua_%d", ii);
+ status = pj_thread_create(pjsua_var.pool, thread_name, &worker_thread,
NULL, 0, 0, &pjsua_var.thread[ii]);
if (status != PJ_SUCCESS)
goto on_error;
diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c
index 6b35070f..bc22143d 100644
--- a/pjsip/src/pjsua-lib/pjsua_pres.c
+++ b/pjsip/src/pjsua-lib/pjsua_pres.c
@@ -855,8 +855,8 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata)
}
/* Create UAS dialog: */
- status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata,
- &contact, &dlg);
+ status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata,
+ &contact, &dlg);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Unable to create UAS dialog for subscription",
@@ -921,11 +921,15 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata)
tdata);
}
+ pjsip_dlg_dec_lock(dlg);
PJSUA_UNLOCK();
pj_log_pop_indent();
return PJ_TRUE;
}
+ /* Subscription has been created, decrement & release dlg lock */
+ pjsip_dlg_dec_lock(dlg);
+
/* If account is locked to specific transport, then lock dialog
* to this transport too.
*/
@@ -1035,7 +1039,6 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata)
}
/* Done: */
-
PJSUA_UNLOCK();
pj_log_pop_indent();
return PJ_TRUE;
diff --git a/pjsip/src/test/inv_offer_answer_test.c b/pjsip/src/test/inv_offer_answer_test.c
index 2131ae6f..4c5eb28b 100644
--- a/pjsip/src/test/inv_offer_answer_test.c
+++ b/pjsip/src/test/inv_offer_answer_test.c
@@ -308,8 +308,8 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata)
* Create UAS
*/
uri = pj_str(CONTACT);
- status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata,
- &uri, &dlg);
+ status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata,
+ &uri, &dlg);
pj_assert(status == PJ_SUCCESS);
if (inv_test.param.oa[0] == OFFERER_UAC)
@@ -321,6 +321,7 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata)
status = pjsip_inv_create_uas(dlg, rdata, sdp, inv_test.param.inv_option, &inv_test.uas);
pj_assert(status == PJ_SUCCESS);
+ pjsip_dlg_dec_lock(dlg);
TRACE_((THIS_FILE, " Sending 183 with SDP"));