From 3985dd57937870f3d47a4ddd68b477a42ffddec1 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Fri, 5 Feb 2016 04:29:17 +0000 Subject: 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 --- pjsip/src/pjsip/sip_dialog.c | 49 +++++++++++++-- pjsip/src/pjsip/sip_transaction.c | 112 ++++++++++++++++++--------------- pjsip/src/pjsip/sip_ua_layer.c | 2 +- pjsip/src/pjsua-lib/pjsua_call.c | 26 +++++++- pjsip/src/pjsua-lib/pjsua_core.c | 4 +- pjsip/src/pjsua-lib/pjsua_pres.c | 9 ++- pjsip/src/test/inv_offer_answer_test.c | 5 +- 7 files changed, 143 insertions(+), 64 deletions(-) (limited to 'pjsip/src') 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