[asterisk-commits] mmichelson: branch 1.4 r187484 - /branches/1.4/channels/chan_sip.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Apr 9 13:51:25 CDT 2009


Author: mmichelson
Date: Thu Apr  9 13:51:20 2009
New Revision: 187484

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=187484
Log:
Handle a SIP race condition (reinvite before an ACK) properly.

RFC 5047 explains the proper course of action to take if a 
reINVITE is received before the ACK from a previous invite
transaction. What we are to do is to treat the reINVITE as
if it were both an ACK and a reINVITE and process it normally.

Later, when we receive the ACK we had been expecting, we will
ignore it since its CSeq is less than the current iseqno of
the sip_pvt representing this dialog.

(closes issue #13849)
Reported by: klaus3000
Patches:
      13849_v2.patch uploaded by mmichelson (license 60)
Tested by: mmichelson, klaus3000


Modified:
    branches/1.4/channels/chan_sip.c

Modified: branches/1.4/channels/chan_sip.c
URL: http://svn.digium.com/svn-view/asterisk/branches/1.4/channels/chan_sip.c?view=diff&rev=187484&r1=187483&r2=187484
==============================================================================
--- branches/1.4/channels/chan_sip.c (original)
+++ branches/1.4/channels/chan_sip.c Thu Apr  9 13:51:20 2009
@@ -14435,13 +14435,26 @@
 	}
 	
 	if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->pendinginvite) {
-		/* We already have a pending invite. Sorry. You are on hold. */
-		p->glareinvite = seqno;
-		transmit_response_reliable(p, "491 Request Pending", req);
-		if (option_debug)
-			ast_log(LOG_DEBUG, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
-		/* Don't destroy dialog here */
-		return 0;
+		if (!ast_test_flag(&p->flags[0], SIP_OUTGOING) && ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED)) {
+			/* We have received a reINVITE on an incoming call to which we have sent a 200 OK but not yet received
+			 * an ACK. According to RFC 5407, Section 3.1.4, the proper way to handle this race condition is to accept
+			 * the reINVITE since we have established a dialog.
+			 */
+			 
+			/* Note that this will both clear the pendinginvite flag and cancel the 
+			 * retransmission of the 200 OK. Basically, we're accepting this reINVITE as both an ACK
+			 * and a reINVITE in one request.
+			 */
+			__sip_ack(p, p->lastinvite, FLAG_RESPONSE, 0);
+		} else {
+			/* We already have a pending invite. Sorry. You are on hold. */
+			p->glareinvite = seqno;
+			transmit_response_reliable(p, "491 Request Pending", req);
+			if (option_debug)
+				ast_log(LOG_DEBUG, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
+			/* Don't destroy dialog here */
+			return 0;
+		}
 	}
 
 	p_replaces = get_header(req, "Replaces");




More information about the asterisk-commits mailing list