[svn-commits] oej: branch oej/invitestate r47519 - /team/oej/invitestate/channels/chan_sip.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Sun Nov 12 12:18:09 MST 2006


Author: oej
Date: Sun Nov 12 13:18:08 2006
New Revision: 47519

URL: http://svn.digium.com/view/asterisk?view=rev&rev=47519
Log:
Removing SIP_CAN_BYE and implementing proper transaction state for 
INVITE transactions in order to kill all those bugs in regards
to BYE/CANCEL handling.

I know this is a fairly large change to release code, but there
was an attempt to solve this more cleanly that did not work.

Let's test this and see if it solves the current issues in 1.2.
If so, we'll port this to 1.4 and trunk.

Modified:
    team/oej/invitestate/channels/chan_sip.c

Modified: team/oej/invitestate/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/invitestate/channels/chan_sip.c?view=diff&rev=47519&r1=47518&r2=47519
==============================================================================
--- team/oej/invitestate/channels/chan_sip.c (original)
+++ team/oej/invitestate/channels/chan_sip.c Sun Nov 12 13:18:08 2006
@@ -148,6 +148,21 @@
 
 #define RTP 	1
 #define NO_RTP	0
+
+/*! \brief States for the INVITE transaction, not the dialog 
+	\note this is for the INVITE that sets up the dialog
+*/
+enum invitestates {
+	INV_NONE = 0,	/*!< No state at all, maybe not an INVITE dialog */
+	INV_CALLING,	/*!< Invite sent, no answer */
+	INV_PROCEEDING,	/*!< We got 1xx message */
+	INV_EARLY_MEDIA, /*!< We got 18x message with to-tag back */
+	INV_COMPLETED,	/*!< Got final response with error. Wait for ACK, then CONFIRMED */
+	INV_CONFIRMED,	/*!< Confirmed response - we've got an ack (Incoming calls only) */
+	INV_TERMINATED,	/*!< Transaction done - either successful (AST_STATE_UP) or failed, but done 
+				The only way out of this is a BYE from one side */
+	INV_CANCELLED	/*!< Transaction cancelled by client or server in non-terminated state */
+};
 
 /* Do _NOT_ make any changes to this enum, or the array following it;
    if you think you are doing the right thing, you are probably
@@ -531,7 +546,7 @@
 #define SIP_USECLIENTCODE	(1 << 12)	/*!< Trust X-ClientCode info message */
 #define SIP_OUTGOING		(1 << 13)	/*!< Is this an outgoing call? */
 #define SIP_SELFDESTRUCT	(1 << 14)	/*!< This is an autocreated peer */
-#define SIP_CAN_BYE		(1 << 15)	/*!< Can we send BYE for this dialog? */
+#define SIP_FREE_BIT		(1 << 15)	/*!< Document this here */
 /* --- Choices for DTMF support in SIP channel */
 #define SIP_DTMF		(3 << 16)	/*!< three settings, uses two bits */
 #define SIP_DTMF_RFC2833	(0 << 16)	/*!< RTP DTMF */
@@ -592,6 +607,7 @@
 /*! \brief sip_pvt: PVT structures are used for each SIP conversation, ie. a call  */
 static struct sip_pvt {
 	ast_mutex_t lock;			/*!< Channel private lock */
+	enum invitestates invitestate;		/*!< If this is an INVITE, track the state*/
 	int method;				/*!< SIP method of this packet */
 	char callid[128];			/*!< Global CallID */
 	char randdata[80];			/*!< Random data */
@@ -2080,6 +2096,7 @@
 	if ( res != -1 ) {
 		p->callingpres = ast->cid.cid_pres;
 		p->jointcapability = p->capability;
+		p->invitestate = INV_CALLING;
 		transmit_invite(p, SIP_INVITE, 1, 2);
 		if (p->maxtime) {
 			/* Initialize auto-congest time */
@@ -2431,7 +2448,8 @@
 		ast_osp_terminate(p->osphandle, AST_CAUSE_NORMAL, p->ospstart, time(NULL) - p->ospstart);
 	}
 #endif	
-	ast_log(LOG_DEBUG, "update_call_counter(%s) - decrement call limit counter\n", p->username);
+	if (option_debug)
+		ast_log(LOG_DEBUG, "update_call_counter(%s) - decrement call limit counter\n", p->username);
 	update_call_counter(p, DEC_CALL_LIMIT);
 	/* Determine how to disconnect */
 	if (p->owner != ast) {
@@ -2473,9 +2491,10 @@
 				/* stop retransmitting an INVITE that has not received a response */
 				__sip_pretend_ack(p);
 
-				/* are we allowed to send CANCEL yet? if not, mark
+				/* Don't send CANCEL until we're beyond CALLING state
+			  	   are we allowed to send CANCEL yet? if not, mark
 				   it pending */
-				if (!ast_test_flag(p, SIP_CAN_BYE)) {
+				if (p->invitestate == INV_CALLING) {
 					ast_set_flag(p, SIP_PENDINGBYE);
 					/* Do we need a timer here if we don't hear from them at all? */
 				} else {
@@ -5738,6 +5757,8 @@
 static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, int reliable, int newbranch)
 {
 	struct sip_request resp;
+	if (sipmethod == SIP_ACK)	
+		p->invitestate = INV_CONFIRMED;
 	reqprep(&resp, p, sipmethod, seqno, newbranch);
 	add_header_contentLength(&resp, 0);
 	add_blank_header(&resp);
@@ -9633,7 +9654,7 @@
 {
 	if (ast_test_flag(p, SIP_PENDINGBYE)) {
 		/* if we can't BYE, then this is really a pending CANCEL */
-		if (!ast_test_flag(p, SIP_CAN_BYE))
+		if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA)
 			transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, 1, 0);
 			/* Actually don't destroy us yet, wait for the 487 on our original 
 			   INVITE, but do set an autodestruct just in case we never get it. */
@@ -9642,7 +9663,8 @@
 		ast_clear_flag(p, SIP_PENDINGBYE);	
 		sip_scheddestroy(p, 32000);
 	} else if (ast_test_flag(p, SIP_NEEDREINVITE)) {
-		ast_log(LOG_DEBUG, "Sending pending reinvite on '%s'\n", p->callid);
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Sending pending reinvite on '%s'\n", p->callid);
 		/* Didn't get to reinvite yet, so do it now */
 		transmit_reinvite_with_sdp(p);
 		ast_clear_flag(p, SIP_NEEDREINVITE);	
@@ -9670,11 +9692,17 @@
 	/* RFC3261 says we must treat every 1xx response (but not 100)
 	   that we don't recognize as if it was 183.
 	*/
-	if ((resp > 100) &&
-	    (resp < 200) &&
-	    (resp != 180) &&
-	    (resp != 183))
+	if ((resp > 100) && (resp < 200) && (resp != 180) && (resp != 183))
 		resp = 183;
+	
+	/* Any response between 100 and 199 is PROCEEDING */
+	if (resp >= 100 && resp < 200 && p->invitestate == INV_CALLING)
+		p->invitestate = INV_PROCEEDING;
+
+	/* Final response, not 200 ? */
+	if (resp >= 300 && (p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA ))
+		p->invitestate = INV_COMPLETED;
+		
 
 	switch (resp) {
 	case 100:	/* Trying */
@@ -9691,13 +9719,13 @@
 				ast_setstate(p->owner, AST_STATE_RINGING);
 		}
 		if (find_sdp(req)) {
+			p->invitestate = INV_EARLY_MEDIA;
 			process_sdp(p, req);
 			if (!ignore && p->owner) {
 				/* Queue a progress frame only if we have SDP in 180 */
 				ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
 			}
 		}
-		ast_set_flag(p, SIP_CAN_BYE);
 		check_pendings(p);
 		break;
 	case 183:	/* Session progress */
@@ -9705,13 +9733,13 @@
 			sip_cancel_destroy(p);
 		/* Ignore 183 Session progress without SDP */
 		if (find_sdp(req)) {
+			p->invitestate = INV_EARLY_MEDIA;
 			process_sdp(p, req);
 			if (!ignore && p->owner) {
 				/* Queue a progress frame */
 				ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
 			}
 		}
-		ast_set_flag(p, SIP_CAN_BYE);
 		check_pendings(p);
 		break;
 	case 200:	/* 200 OK on invite - someone's answering our call */
@@ -9750,8 +9778,8 @@
 				ast_set_flag(p, SIP_PENDINGBYE);	
 		}
 		/* If I understand this right, the branch is different for a non-200 ACK only */
+		p->invitestate = INV_TERMINATED;	/* We're done with this INVITE */
 		transmit_request(p, SIP_ACK, seqno, 0, 1);
-		ast_set_flag(p, SIP_CAN_BYE);
 		check_pendings(p);
 		break;
 	case 407: /* Proxy authentication */
@@ -10642,6 +10670,7 @@
 		switch(c->_state) {
 		case AST_STATE_DOWN:
 			transmit_response(p, "100 Trying", req);
+			p->invitestate = INV_PROCEEDING;
 			ast_setstate(c, AST_STATE_RING);
 			if (strcmp(p->exten, ast_pickup_ext())) {
 				enum ast_pbx_result res;
@@ -10670,6 +10699,7 @@
 
 				if (res) {
 					ast_log(LOG_WARNING, "Failed to start PBX :(\n");
+					p->invitestate = INV_COMPLETED;
 					/* Unlock locks so ast_hangup can do its magic */
 					ast_mutex_unlock(&c->lock);
 					ast_mutex_unlock(&p->lock);
@@ -10685,6 +10715,7 @@
 						transmit_response(p, "503 Unavailable", req);
 					else
 						transmit_response_reliable(p, "503 Unavailable", req, 1);
+					p->invitestate = INV_COMPLETED;
 					ast_set_flag(p, SIP_ALREADYGONE);	
 					/* Unlock locks so ast_hangup can do its magic */
 					ast_mutex_unlock(&p->lock);
@@ -10692,6 +10723,7 @@
 					ast_mutex_lock(&p->lock);
 					c = NULL;
 				} else {
+					p->invitestate = INV_COMPLETED;
 					ast_mutex_unlock(&p->lock);
 					ast_setstate(c, AST_STATE_DOWN);
 					ast_hangup(c);
@@ -10702,12 +10734,15 @@
 			break;
 		case AST_STATE_RING:
 			transmit_response(p, "100 Trying", req);
+			p->invitestate = INV_PROCEEDING;
 			break;
 		case AST_STATE_RINGING:
 			transmit_response(p, "180 Ringing", req);
+			p->invitestate = INV_PROCEEDING;
 			break;
 		case AST_STATE_UP:
 			transmit_response_with_sdp(p, "200 OK", req, 1);
+			p->invitestate = INV_TERMINATED;
 			break;
 		default:
 			ast_log(LOG_WARNING, "Don't know how to handle INVITE in state %d\n", c->_state);
@@ -10721,6 +10756,7 @@
 				ast_log(LOG_NOTICE, "Unable to create/find channel\n");
 				transmit_response_reliable(p, "503 Unavailable", req, 1);
 			}
+			p->invitestate = INV_COMPLETED;
 			ast_set_flag(p, SIP_NEEDDESTROY);	
 		}
 	}
@@ -10804,6 +10840,7 @@
 		
 	check_via(p, req);
 	ast_set_flag(p, SIP_ALREADYGONE);	
+	p->invitestate = INV_CANCELLED;	/* When we get an ACK, it will be terminated */
 	if (p->rtp) {
 		/* Immediately stop RTP */
 		ast_rtp_stop(p->rtp);
@@ -10835,8 +10872,10 @@
 	struct ast_channel *bridged_to;
 	char iabuf[INET_ADDRSTRLEN];
 	
-	if (p->pendinginvite && !ast_test_flag(p, SIP_OUTGOING) && !ignore)
+	if (p->pendinginvite && !ast_test_flag(p, SIP_OUTGOING) && !ignore) {
+		p->invitestate = INV_TERMINATED;
 		transmit_response_reliable(p, "487 Request Terminated", &p->initreq, 1);
+	}
 
 	copy_request(&p->initreq, req);
 	check_via(p, req);
@@ -11317,6 +11356,7 @@
 	case SIP_ACK:
 		/* Make sure we don't ignore this */
 		if (seqno == p->pendinginvite) {
+			p->invitestate = INV_CONFIRMED;
 			p->pendinginvite = 0;
 			__sip_ack(p, seqno, FLAG_RESPONSE, 0);
 			if (find_sdp(req)) {



More information about the svn-commits mailing list