summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2013-08-29 22:25:16 +0000
committerMark Michelson <mmichelson@digium.com>2013-08-29 22:25:16 +0000
commitde7ce39187f4cc22ded82a7b10cad1aa7654dfb0 (patch)
tree11e6e8a261c1960e4a3e8daf3aac001ebb812f1a
parente1cfc18a78195cce9504b61f0aaeb4b61582fa15 (diff)
Fix a race condition where a canceled call was answered.
RFC 5407 section 3.1.2 details a scenario where a UAC sends a CANCEL at the same time that a UAS sends a 200 OK for the INVITE that the UAC is canceling. When this occurs, it is the role of the UAC to immediately send a BYE to terminate the call. This scenario was reproducible by have a Digium phone with two lines place a call to a second phone that forwarded the call to the second line on the original phone. The Digium phone, upon realizing that it was connecting to itself, would attempt to cancel the call. The timing of this happened to trigger the aforementioned race condition about 80% of the time. Asterisk was not doing its job of sending a BYE when receiving a 200 OK on a cancelled INVITE. The result was that the ast_channel structure was destroyed but the underlying SIP session, as well as the PJSIP inv_session and dialog, were still alive. Attempting to perform an action such as a transfer, once in this state, would result in Asterisk crashing. The circumstances are now detected properly and the session is ended as recommended in RFC 5407. (closes issue AST-1209) reported by John Bigelow ........ Merged revisions 397945 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397956 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--res/res_pjsip_session.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 13c1e1d6e..226e43f3e 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1868,17 +1868,33 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
break;
case PJSIP_EVENT_RX_MSG:
if (tsx->method.id == PJSIP_INVITE_METHOD) {
- if (tsx->role == PJSIP_ROLE_UAC && tsx->state == PJSIP_TSX_STATE_COMPLETED) {
- /* This means we got a non 2XX final response to our outgoing INVITE */
- if (tsx->status_code == PJSIP_SC_REQUEST_PENDING) {
- reschedule_reinvite(session, tsx->mod_data[session_module.id], tsx->last_tx);
- return;
- } else if (inv->state == PJSIP_INV_STATE_CONFIRMED &&
- tsx->status_code != 488) {
- /* Other reinvite failures (except 488) result in destroying the session. */
- pjsip_tx_data *tdata;
- if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) {
- ast_sip_session_send_request(session, tdata);
+ if (tsx->role == PJSIP_ROLE_UAC) {
+ if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
+ /* This means we got a non 2XX final response to our outgoing INVITE */
+ if (tsx->status_code == PJSIP_SC_REQUEST_PENDING) {
+ reschedule_reinvite(session, tsx->mod_data[session_module.id], tsx->last_tx);
+ return;
+ } else if (inv->state == PJSIP_INV_STATE_CONFIRMED &&
+ tsx->status_code != 488) {
+ /* Other reinvite failures (except 488) result in destroying the session. */
+ pjsip_tx_data *tdata;
+ if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) {
+ ast_sip_session_send_request(session, tdata);
+ }
+ }
+ } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
+ if (inv->cancelling && tsx->status_code == PJSIP_SC_OK) {
+ /* This is a race condition detailed in RFC 5407 section 3.1.2.
+ * We sent a CANCEL at the same time that the UAS sent us a 200 OK for
+ * the original INVITE. As a result, we have now received a 200 OK for
+ * a cancelled call. Our role is to immediately send a BYE to end the
+ * dialog.
+ */
+ pjsip_tx_data *tdata;
+
+ if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS) {
+ ast_sip_session_send_request(session, tdata);
+ }
}
}
}