diff options
author | Matt Jordan <mjordan@digium.com> | 2015-07-14 22:17:45 -0500 |
---|---|---|
committer | Gerrit Code Review <gerrit2@gerrit.digium.api> | 2015-07-14 22:17:45 -0500 |
commit | 00d858da87c77954778c6ea5dc559029d21e4bf5 (patch) | |
tree | 2b7a82897efa7870cb575478350fd7df38bbdb9d /res | |
parent | 0b6ff77afbad10b96a31932dd697e06748281d80 (diff) | |
parent | 653f2087e0d2edc9df8a0154c09e2e608e13a5c5 (diff) |
Merge "res_pjsip_session.c: Fix crash on call disconnect." into 13
Diffstat (limited to 'res')
-rw-r--r-- | res/res_pjsip_session.c | 65 |
1 files changed, 59 insertions, 6 deletions
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 8c04a7cfb..2c2ea616d 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2247,7 +2247,7 @@ static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdat } } -static int session_end(struct ast_sip_session *session) +static void session_end(struct ast_sip_session *session) { struct ast_sip_session_supplement *iter; @@ -2256,14 +2256,28 @@ static int session_end(struct ast_sip_session *session) ao2_ref(session, -1); } - /* Session is dead. Let's get rid of the reference to the session */ + /* Session is dead. Notify the supplements. */ AST_LIST_TRAVERSE(&session->supplements, iter, next) { if (iter->session_end) { iter->session_end(session); } } +} + +/*! + * \internal + * \brief Complete ending session activities. + * \since 13.5.0 + * + * \param vsession Which session to complete stopping. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int session_end_completion(void *vsession) +{ + struct ast_sip_session *session = vsession; - session->inv_session->mod_data[session_module.id] = NULL; ast_sip_dialog_set_serializer(session->inv_session->dlg, NULL); ast_sip_dialog_set_endpoint(session->inv_session->dlg, NULL); ao2_cleanup(session); @@ -2340,9 +2354,7 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans print_debug_details(inv, tsx, e); if (!session) { - /* Transaction likely timed out after the call was hung up. Just - * ignore such transaction changes - */ + /* The session has ended. Ignore the transaction change. */ return; } switch (e->body.tsx_state.type) { @@ -2423,7 +2435,48 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } break; case PJSIP_EVENT_TRANSPORT_ERROR: + /* + * Clear the module data now to block session_inv_on_state_changed() + * from calling session_end() if it hasn't already done so. + */ + inv->mod_data[session_module.id] = NULL; + + if (inv->state != PJSIP_INV_STATE_DISCONNECTED) { + session_end(session); + } + + /* + * Pass the session ref held by session->inv_session to + * session_end_completion(). + */ + session_end_completion(session); + return; case PJSIP_EVENT_TIMER: + /* + * The timer event is run by the pjsip monitor thread and not + * by the session serializer. + */ + if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { + /* + * We are locking because ast_sip_dialog_get_session() needs + * the dialog locked to get the session by other threads. + */ + pjsip_dlg_inc_lock(inv->dlg); + session = inv->mod_data[session_module.id]; + inv->mod_data[session_module.id] = NULL; + pjsip_dlg_dec_lock(inv->dlg); + + /* + * Pass the session ref held by session->inv_session to + * session_end_completion(). + */ + if (ast_sip_push_task(session->serializer, session_end_completion, session)) { + /* Do it anyway even though this is not the right thread. */ + session_end_completion(session); + } + return; + } + break; case PJSIP_EVENT_USER: case PJSIP_EVENT_UNKNOWN: case PJSIP_EVENT_TSX_STATE: |