summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorzuul <zuul@gerrit.asterisk.org>2016-09-07 14:04:26 -0500
committerGerrit Code Review <gerrit2@gerrit.digium.api>2016-09-07 14:04:26 -0500
commit892536729188c29aecb6b2b5a6bab8928a63f530 (patch)
tree56c258d7f982dd3b7f96a4a19cb926fc03cdf7fc /res
parent4b66c74c9422c10c25dd42c7d204c5f499749d80 (diff)
parent9bca89546992a540d106a725734e6038cb91d76f (diff)
Merge "res_pjsip_session: segfault on already disconnected session" into 13
Diffstat (limited to 'res')
-rw-r--r--res/res_pjsip_session.c71
1 files changed, 62 insertions, 9 deletions
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 856626a02..050970998 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -213,6 +213,11 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd
int i;
int handled = 0;
+ if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+ ast_log(LOG_ERROR, "Failed to handle incoming SDP. Session has been already disconnected\n");
+ return -1;
+ }
+
for (i = 0; i < sdp->media_count; ++i) {
/* See if there are registered handlers for this media stream type */
char media[20];
@@ -2087,6 +2092,16 @@ static int new_invite(void *data)
* so that we will be notified so we can destroy the session properly
*/
+ if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+ ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
+ invite->session->inv_session->cause,
+ pjsip_get_status_text(invite->session->inv_session->cause)->ptr);
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+ pjsip_inv_dec_ref(invite->session->inv_session);
+#endif
+ return -1;
+ }
+
switch (get_destination(invite->session, invite->rdata)) {
case SIP_GET_DEST_EXTEN_FOUND:
/* Things worked. Keep going */
@@ -2097,7 +2112,7 @@ static int new_invite(void *data)
} else {
pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
}
- return 0;
+ goto end;
case SIP_GET_DEST_EXTEN_NOT_FOUND:
case SIP_GET_DEST_EXTEN_PARTIAL:
default:
@@ -2110,7 +2125,7 @@ static int new_invite(void *data)
} else {
pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE);
}
- return 0;
+ goto end;
};
if ((sdp_info = pjsip_rdata_get_sdp_info(invite->rdata)) && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) {
@@ -2120,7 +2135,7 @@ static int new_invite(void *data)
} else {
pjsip_inv_terminate(invite->session->inv_session, 488, PJ_TRUE);
}
- return 0;
+ goto end;
}
/* We are creating a local SDP which is an answer to their offer */
local = create_local_sdp(invite->session->inv_session, invite->session, sdp_info->sdp);
@@ -2136,7 +2151,7 @@ static int new_invite(void *data)
} else {
pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
}
- return 0;
+ goto end;
} else {
pjsip_inv_set_local_sdp(invite->session->inv_session, local);
pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE);
@@ -2153,12 +2168,16 @@ static int new_invite(void *data)
/* At this point, we've verified what we can, so let's go ahead and send a 100 Trying out */
if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
- return 0;
+ goto end;
}
ast_sip_session_send_response(invite->session, tdata);
handle_incoming_request(invite->session, invite->rdata);
+end:
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+ pjsip_inv_dec_ref(invite->session->inv_session);
+#endif
return 0;
}
@@ -2179,6 +2198,20 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
return;
}
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+ if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
+ ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
+ if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
+ if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
+ pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
+ } else {
+ internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
+ }
+ }
+ return;
+ }
+#endif
+
session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
if (!session) {
if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
@@ -2186,6 +2219,9 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
} else {
internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
}
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+ pjsip_inv_dec_ref(inv_session);
+#endif
return;
}
@@ -2196,6 +2232,9 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
} else {
internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
}
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+ pjsip_inv_dec_ref(inv_session);
+#endif
ao2_cleanup(invite);
}
ao2_ref(session, -1);
@@ -2467,8 +2506,9 @@ static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdat
}
}
-static void session_end(struct ast_sip_session *session)
+static int session_end(void *vsession)
{
+ struct ast_sip_session *session = vsession;
struct ast_sip_session_supplement *iter;
/* Stop the scheduled termination */
@@ -2480,6 +2520,7 @@ static void session_end(struct ast_sip_session *session)
iter->session_end(session);
}
}
+ return 0;
}
/*!
@@ -2585,7 +2626,10 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
}
if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
- session_end(session);
+ if (ast_sip_push_task(session->serializer, session_end, session)) {
+ /* Do it anyway even though this is not the right thread. */
+ session_end(session);
+ }
}
}
@@ -2752,7 +2796,11 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
* Pass the session ref held by session->inv_session to
* session_end_completion().
*/
- session_end_completion(session);
+ if (session
+ && 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;
@@ -2877,7 +2925,12 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru
static const pj_str_t STR_IP6 = { "IP6", 3 };
pjmedia_sdp_session *local;
- if (!(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
+ if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
+ ast_log(LOG_ERROR, "Failed to create session SDP. Session has been already disconnected\n");
+ return NULL;
+ }
+
+ if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
return NULL;
}