[svn-commits] rizzo: branch rizzo/astobj2 r47825 - /team/rizzo/astobj2/channels/chan_sip.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Sat Nov 18 12:29:12 MST 2006


Author: rizzo
Date: Sat Nov 18 13:29:11 2006
New Revision: 47825

URL: http://svn.digium.com/view/asterisk?view=rev&rev=47825
Log:
sync with version 47824


Modified:
    team/rizzo/astobj2/channels/chan_sip.c

Modified: team/rizzo/astobj2/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/channels/chan_sip.c?view=diff&rev=47825&r1=47824&r2=47825
==============================================================================
--- team/rizzo/astobj2/channels/chan_sip.c (original)
+++ team/rizzo/astobj2/channels/chan_sip.c Sat Nov 18 13:29:11 2006
@@ -239,6 +239,21 @@
 	AST_FAILURE = -1,
 };
 
+/*! \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
    not doing the right thing. If you think there are changes
@@ -516,6 +531,7 @@
 static int global_limitonpeers;		/*!< Match call limit on peers only */
 static int global_rtautoclear;
 static int global_notifyringing;	/*!< Send notifications on ringing */
+static int global_notifyhold;		/*!< Send notifications on hold */
 static int global_alwaysauthreject;	/*!< Send 401 Unauthorized for all failing requests */
 static int global_srvlookup;			/*!< SRV Lookup on or off. Default is off, RFC behavior is on */
 static int pedanticsipchecking;		/*!< Extra checking ?  Default off */
@@ -709,7 +725,7 @@
 #define SIP_REALTIME		(1 << 11)	/*!< Flag for realtime users */
 #define SIP_USECLIENTCODE	(1 << 12)	/*!< Trust X-ClientCode info message */
 #define SIP_OUTGOING		(1 << 13)	/*!< Direction of the last transaction in this dialog */
-#define SIP_CAN_BYE		(1 << 14)	/*!< Can we send BYE on this dialog? */
+#define SIP_FREE_BIT		(1 << 14)	/*!< ---- */
 #define SIP_DEFER_BYE_ON_TRANSFER	(1 << 15)	/*!< Do not hangup at first ast_hangup */
 #define SIP_DTMF		(3 << 16)	/*!< DTMF Support: four settings, uses two bits */
 #define SIP_DTMF_RFC2833	(0 << 16)	/*!< DTMF Support: RTP DTMF - "rfc2833" */
@@ -886,6 +902,7 @@
 	struct sip_pvt *next;			/*!< Next dialog in chain */
 	ast_mutex_t pvt_lock;			/*!< Dialog private lock */
 #endif
+	enum invitestates invitestate;		/*!< Track state of SIP_INVITEs */
 	int method;				/*!< SIP method that opened this dialog */
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(callid);	/*!< Global CallID */
@@ -2127,9 +2144,6 @@
 	/* Reset schedule ID */
 	p->autokillid = -1;
 
-	if (option_debug)
-		ast_log(LOG_DEBUG, "Auto destroying SIP dialog '%s'\n", p->callid);
-	append_history(p, "AutoDestroy", "%s", p->callid);
 	if (p->owner) {
 		ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner in place (Method: %s)\n", p->callid, sip_methods[p->method].text);
 		ast_queue_hangup(p->owner);
@@ -3039,6 +3053,8 @@
 		if (option_debug > 1)
 			ast_log(LOG_DEBUG,"Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
 		transmit_invite(p, SIP_INVITE, 1, 2);
+
+		p->invitestate = INV_CALLING;
 
 		/* Initialize auto-congest time */
 		p->initid = ast_sched_add(sched, SIP_TRANS_TIMEOUT, auto_congest, pvt_ref(p));
@@ -3579,12 +3595,13 @@
 				__sip_pretend_ack(p);
 
 				/* if we can't send right now, mark it pending */
-				if (!ast_test_flag(&p->flags[0], SIP_CAN_BYE)) {
+				if (p->invitestate == INV_CALLING) {
+					/* We can't send anything in CALLING state */
 					ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
 					/* Do we need a timer here if we don't hear from them at all? */
 				} else {
 					/* Send a new request: CANCEL */
-					transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, FALSE);
+					transmit_request(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, FALSE);
 					/* 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. */
 					needdestroy = 0;
@@ -5464,7 +5481,8 @@
 					"Uniqueid: %s\r\n",
 					p->owner->name, 
 					p->owner->uniqueid);
-			sip_peer_hold(p, 0);
+			if (global_notifyhold)
+				sip_peer_hold(p, 0);
 		} 
 		ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD);	/* Clear both flags */
 	} else if (!sin.sin_addr.s_addr || sendonly ) {
@@ -7697,6 +7715,9 @@
 static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype 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);
@@ -10668,6 +10689,7 @@
 	ast_cli(fd, "  Outbound reg. timeout:  %d secs\n", global_reg_timeout);
 	ast_cli(fd, "  Outbound reg. attempts: %d\n", global_regattempts_max);
 	ast_cli(fd, "  Notify ringing state:   %s\n", global_notifyringing ? "Yes" : "No");
+	ast_cli(fd, "  Notify hold state:      %s\n", global_notifyhold ? "Yes" : "No");
 	ast_cli(fd, "  SIP Transfer mode:      %s\n", transfermode2str(global_allowtransfer));
 	ast_cli(fd, "  Max Call Bitrate:       %d kbps\r\n", default_maxcallbitrate);
 	ast_cli(fd, "  Auto-Framing:           %s \r\n", global_autoframing ? "Yes" : "No");
@@ -11990,12 +12012,12 @@
 {
 	if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
 		/* if we can't BYE, then this is really a pending CANCEL */
-		if (!ast_test_flag(&p->flags[0], SIP_CAN_BYE))
-			transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, 1, 0);
+		if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA)
+			transmit_request(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, FALSE);
 			/* 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. */
 		else 
-			transmit_request_with_auth(p, SIP_BYE, 0, 1, 1);
+			transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
 		ast_clear_flag(&p->flags[0], SIP_PENDINGBYE);	
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 	} else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
@@ -12042,6 +12064,15 @@
 	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 */
 		if (!req_ignore(req))
@@ -12059,13 +12090,13 @@
 			}
 		}
 		if (find_sdp(req)) {
+			p->invitestate = INV_EARLY_MEDIA;
 			res = process_sdp(p, req);
 			if (!req_ignore(req) && 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->flags[0], SIP_CAN_BYE);
 		check_pendings(p);
 		break;
 
@@ -12074,13 +12105,13 @@
 			sip_cancel_destroy(p);
 		/* Ignore 183 Session progress without SDP */
 		if (find_sdp(req)) {
+			p->invitestate = INV_EARLY_MEDIA;
 			res = process_sdp(p, req);
 			if (!req_ignore(req) && p->owner) {
 				/* Queue a progress frame */
 				ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
 			}
 		}
-		ast_set_flag(&p->flags[0], SIP_CAN_BYE);
 		check_pendings(p);
 		break;
 
@@ -12125,8 +12156,8 @@
 				ast_log(LOG_WARNING, "Ooooh.. no tech!  That's REALLY bad\n");
 				break;
 			}
-			if (!strcasecmp(bridgepeer->tech->type,"SIP")) {
-				bridgepvt = bridgepeer->tech_pvt;
+			if (bridgepeer->tech == &sip_tech) {
+				bridgepvt = (struct sip_pvt*)(bridgepeer->tech_pvt);
 				if (bridgepvt->udptl) {
 					if (p->t38.state == T38_PEER_REINVITE) {
 						sip_handle_t38_reinvite(bridgepeer, p, 0);
@@ -12178,8 +12209,8 @@
 				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
 		}
 		/* If I understand this right, the branch is different for a non-200 ACK only */
+		p->invitestate = INV_TERMINATED;
 		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, TRUE);
-		ast_set_flag(&p->flags[0], SIP_CAN_BYE);
 		check_pendings(p);
 		break;
 
@@ -13808,6 +13839,7 @@
 			if (option_debug > 1)
 				ast_log(LOG_DEBUG, "%s: New call is still down.... Trying... \n", c->name);
 			transmit_response(p, "100 Trying", req);
+			p->invitestate = INV_PROCEEDING;
 			ast_setstate(c, AST_STATE_RING);
 			if (strcmp(p->exten, ast_pickup_ext())) {	/* Call to extension -start pbx on this call */
 				enum ast_pbx_result res;
@@ -13817,6 +13849,7 @@
 				switch(res) {
 				case AST_PBX_FAILED:
 					ast_log(LOG_WARNING, "Failed to start PBX :(\n");
+					p->invitestate = INV_COMPLETED;
 					if (req_ignore(req))
 						transmit_response(p, "503 Unavailable", req);
 					else
@@ -13824,6 +13857,7 @@
 					break;
 				case AST_PBX_CALL_LIMIT:
 					ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
+					p->invitestate = INV_COMPLETED;
 					if (req_ignore(req))
 						transmit_response(p, "480 Temporarily Unavailable", req);
 					else
@@ -13860,6 +13894,7 @@
 					ast_setstate(c, AST_STATE_DOWN);
 					c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
 				}
+				p->invitestate = INV_COMPLETED;
 				ast_hangup(c);
 				sip_pvt_lock(p);
 				c = NULL;
@@ -13867,9 +13902,11 @@
 			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:
 			if (option_debug > 1)
@@ -13882,8 +13919,8 @@
 				if ((bridgepeer = ast_bridged_channel(p->owner))) {
 					/* We have a bridge, and this is re-invite to switchover to T38 so we send re-invite with T38 SDP, to other side of bridge*/
 					/*! XXX: we should also check here does the other side supports t38 at all !!! XXX */
-					if (!strcasecmp(bridgepeer->tech->type, "SIP")) { /* If we are bridged to SIP channel */
-						bridgepvt = bridgepeer->tech_pvt;
+					if (bridgepeer->tech == &sip_tech) {
+						bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
 						if (bridgepvt->t38.state == T38_DISABLED) {
 							if (bridgepvt->udptl) { /* If everything is OK with other side's udptl struct */
 								/* Send re-invite to the bridged channel */
@@ -13935,8 +13972,8 @@
 				struct ast_channel *bridgepeer = NULL;
 				struct sip_pvt *bridgepvt = NULL;
 				if ((bridgepeer = ast_bridged_channel(p->owner))) {
-					if (!strcasecmp(bridgepeer->tech->type, sip_tech.type)) {
-						bridgepvt = bridgepeer->tech_pvt;
+					if (bridgepeer->tech == &sip_tech) {
+						bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
 						/* Does the bridged peer have T38 ? */
 						if (bridgepvt->t38.state == T38_ENABLED) {
 							ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
@@ -13954,6 +13991,7 @@
 					transmit_response_with_sdp(p, "200 OK", req, XMIT_CRITICAL);
 
 			}
+			p->invitestate = INV_TERMINATED;
 			break;
 		default:
 			ast_log(LOG_WARNING, "Don't know how to handle INVITE in state %d\n", c->_state);
@@ -13974,6 +14012,7 @@
 				transmit_response(p, msg, req);
 			else
 				transmit_response_reliable(p, msg, req);
+			p->invitestate = INV_COMPLETED;
 			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 		}
 	}
@@ -14431,6 +14470,7 @@
 		
 	check_via(p, req);
 	ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+	p->invitestate = INV_CANCELLED;
 	
 	if (p->owner && p->owner->_state == AST_STATE_UP) {
 		/* This call is up, cancel is ignored, we need a bye */
@@ -14465,6 +14505,8 @@
 	/* If we have an INCOMING invite that we haven't answered, terminate that transaction */
 	if (p->pendinginvite && !ast_test_flag(&p->flags[0], SIP_OUTGOING) && !req_ignore(req) && !p->owner)
 		transmit_response_reliable(p, "487 Request Terminated", &p->initreq);
+
+	p->invitestate = INV_TERMINATED;
 
 	copy_request(&p->initreq, req);
 
@@ -15071,6 +15113,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)) {
@@ -16507,6 +16550,7 @@
 	expiry = DEFAULT_EXPIRY;
 	global_notifyringing = DEFAULT_NOTIFYRINGING;
 	global_limitonpeers = FALSE;		/*!< Match call limit on peers only */
+	global_notifyhold = FALSE;		/*!< Keep track of hold status for a peer */
 	global_alwaysauthreject = 0;
 	global_allowsubscribe = FALSE;
 	ast_copy_string(global_useragent, DEFAULT_USERAGENT, sizeof(global_useragent));
@@ -16600,6 +16644,7 @@
 		M_STR("notifymimetype", default_notifymime)
 		M_BOOL("notifyringing", global_notifyringing)
 		M_BOOL("limitpeersonly", global_limitonpeers)
+		M_BOOL("notifyhold", global_notifyhold)
 		M_BOOL("alwaysauthreject", global_alwaysauthreject)
 		M_STR("mohinterpret", default_mohinterpret)
 		M_STR("musicclass", default_mohinterpret)



More information about the svn-commits mailing list