[asterisk-commits] branch oej/02-labarea r21077 - /team/oej/02-labarea/channels/chan_sip.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Apr 18 00:08:55 MST 2006


Author: oej
Date: Tue Apr 18 02:08:46 2006
New Revision: 21077

URL: http://svn.digium.com/view/asterisk?rev=21077&view=rev
Log:
Fixing stuff focused on avoiding loops

Modified:
    team/oej/02-labarea/channels/chan_sip.c

Modified: team/oej/02-labarea/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/02-labarea/channels/chan_sip.c?rev=21077&r1=21076&r2=21077&view=diff
==============================================================================
--- team/oej/02-labarea/channels/chan_sip.c (original)
+++ team/oej/02-labarea/channels/chan_sip.c Tue Apr 18 02:08:46 2006
@@ -718,6 +718,20 @@
 	{ REFER_NOAUTH,		"Failed - auth failure" }
 } ;
 
+#ifdef SKREP
+struct sip_transaction {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(skrep);
+	);
+	unsigned int cseq;			/*!< This transactions outgoing seqno */
+	//enum transactiondirection dir;		/*!< Direction of this transaction */
+	struct ast_flags flags[2];		/*!< SIP_ flags */
+	struct sip_request initreq;		/*!< Initial request that opened the SIP dialog */
+	struct sip_pvt *pvtowner;		/*!< SIP dialog we are referring */
+	/* Transaction Timers */
+}
+#endif
+
 /*! \brief Structure to handle SIP transfers. Dynamically allocated when needed  */
 /* OEJ: Should be moved to string fields */
 struct sip_refer {
@@ -737,13 +751,15 @@
 	enum referstatus status;			/*!< REFER status */
 };
 
+
 /*! \brief sip_pvt: PVT structures are used for each SIP dialog, ie. a call, a registration, a subscribe  */
 static struct sip_pvt {
 	ast_mutex_t lock;			/*!< Dialog private lock */
 	int method;				/*!< SIP method that opened this dialog */
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(callid);	/*!< Global CallID */
-		AST_STRING_FIELD(viabranchtag);	/*!< Via branch in this session */
+		AST_STRING_FIELD(viabranchtag);	/*!< Topmost via branch captured in this session */
+		AST_STRING_FIELD(ourbranch);	/*!< Our branch tag */
 		AST_STRING_FIELD(randdata);	/*!< Random data */
 		AST_STRING_FIELD(accountcode);	/*!< Account code */
 		AST_STRING_FIELD(realm);	/*!< Authorization realm */
@@ -801,7 +817,6 @@
 	int callingpres;			/*!< Calling presentation */
 	int authtries;				/*!< Times we've tried to authenticate */
 	int expiry;				/*!< How long we take to expire */
-	long branch;				/*!< One random number */
 	char tag[11];				/*!< Another random number */
 	int sessionid;				/*!< SDP Session ID */
 	int sessionversion;			/*!< SDP Session Version */
@@ -1110,6 +1125,7 @@
 static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
 static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
 static int handle_request_options(struct sip_pvt *p, struct sip_request *req);
+static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
 
 /*------Response handling functions */
 static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
@@ -1321,8 +1337,8 @@
 	const char *rport = ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_RFC3581 ? ";rport" : "";
 
 	/* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-	ast_string_field_build(p, via, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x%s",
-			 ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch, rport);
+	ast_string_field_build(p, via, "SIP/2.0/UDP %s:%d;branch=%s%s",
+			 ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->ourbranch, rport);
 }
 
 /*! \brief NAT fix - decide which IP address to use for ASterisk server?
@@ -2742,7 +2758,7 @@
 				__sip_pretend_ack(p);
 
 				/* Send a new request: CANCEL */
-				transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, 0);
+				transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, TRUE);
 				/* 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. */
 				ast_clear_flag(&locflags, SIP_NEEDDESTROY);
@@ -2763,7 +2779,7 @@
 		} else {	/* Call is in UP state, send BYE */
 			if (!p->pendinginvite) {
 				/* Send a hangup */
-				transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
+				transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
 			} else {
 				/* Note we will need a BYE when this all settles out
 				   but we can't send one while we have "INVITE" outstanding. */
@@ -3360,7 +3376,7 @@
 /*! \brief Make our SIP dialog tag */
 static void make_our_tag(char *tagbuf, size_t len)
 {
-	snprintf(tagbuf, len, "as%08lx", ast_random());
+	snprintf(tagbuf, len, "ast-%08lx", ast_random());
 }
 
 /*! \brief Allocate SIP_PVT structure and set defaults */
@@ -3368,6 +3384,7 @@
 				 int useglobal_nat, const int intended_method)
 {
 	struct sip_pvt *p;
+	char buf[33];
 
 	if (!(p = ast_calloc(1, sizeof(*p))))
 		return NULL;
@@ -3399,7 +3416,7 @@
 	ast_copy_flags(&p->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
 
-	p->branch = ast_random();	
+	ast_string_field_build(p, ourbranch, "z9hG4bK-ast-%s",generate_random_string(buf,sizeof(buf)));
 	make_our_tag(p->tag, sizeof(p->tag));
 	p->ocseq = INITIAL_CSEQ;
 
@@ -3490,7 +3507,7 @@
 
 	if (pedanticsipchecking) {
 		/* In principle Call-ID's uniquely identify a call, but with a forking SIP proxy
-		   we need more to identify a branch - so we have to check branch, from
+		   we need more to identify a dialog - so we have to check branch, from
 		   and to tags to identify a call leg.
 		   For Asterisk to behave correctly, you need to turn on pedanticsipchecking
 		   in sip.conf
@@ -3545,7 +3562,7 @@
 
 	if ((p = sip_alloc(req->callid, sin, 1, intended_method))) {	/* Allocate new call */
 		ast_mutex_lock(&p->lock);		/* Lock this new PVT while we are in action */
-		find_via_branch(p, req);
+		find_via_branch(p, req);		/* Find the branch and store it */
 	}
 	return p;
 }
@@ -4338,11 +4355,13 @@
 	copy_via_headers(p, resp, req, "Via");
 	if (msg[0] == '2')
 		copy_all_header(resp, req, "Record-Route");
+	ast_log(LOG_DEBUG, "RESPPREP: Call ID in req: %s\n", ast_strlen_zero(req->callid) ? "<none>" : req->callid );
 	//if (!ast_strlen_zero(req->from))
 		//add_header(resp, "From", req->from);
 	//else
 		copy_header(resp, req, "From");
-	ot = req->to ? req->to : get_header(req, "To");
+	//ot = req->to ? ast_strlen_zero(req->to) : get_header(req, "To");
+	ot = get_header(req, "To");
 	if (!strcasestr(ot, "tag=") && strncmp(msg, "100", 3)) {
 		/* Add the proper tag if we don't have it already.  If they have specified
 		   their tag, use it.  Otherwise, use our own tag */
@@ -4406,7 +4425,9 @@
 	}
 	
 	if (newbranch) {
-		p->branch ^= ast_random();
+		char buf[33];
+		/* This is a new SIP transaction, create a new branch */
+		ast_string_field_build(p, ourbranch, "z9hG4bK-ast-%s",generate_random_string(buf,sizeof(buf)));
 		build_via(p);
 	}
 
@@ -5248,14 +5269,16 @@
 	req.method = sipmethod;
 	if (init) {
 		/* Bump branch even on initial requests */
-		p->branch ^= ast_random();
+		char buf[33];
+		/* This is a new SIP transaction, create a new branch */
+		ast_string_field_build(p, ourbranch, "z9hG4bK-ast-%s",generate_random_string(buf,sizeof(buf)));
 		build_via(p);
 		if (init > 1)
 			initreqprep(&req, p, sipmethod);
 		else
-			reqprep(&req, p, sipmethod, 0, 1);
+			reqprep(&req, p, sipmethod, 0, TRUE);
 	} else
-		reqprep(&req, p, sipmethod, 0, 1);
+		reqprep(&req, p, sipmethod, 0, TRUE);
 		
 	if (p->options && p->options->auth)
 		add_header(&req, p->options->authheader, p->options->auth);
@@ -5422,7 +5445,7 @@
 		*a = '\0';
 	mto = c;
 
-	reqprep(&req, p, SIP_NOTIFY, 0, 1);
+	reqprep(&req, p, SIP_NOTIFY, 0, TRUE);
 
 	
 	add_header(&req, "Event", subscriptiontype->event);
@@ -5552,7 +5575,8 @@
 {
 	struct sip_request req;
 	char tmp[50];
-	reqprep(&req, p, SIP_NOTIFY, 0, 1);
+
+	reqprep(&req, p, SIP_NOTIFY, 0, TRUE);
 	snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq);
 	add_header(&req, "Event", tmp);
 	add_header(&req, "Subscription-state", "terminated;reason=noresource");
@@ -5679,6 +5703,7 @@
 	char tmp[80];
 	char addr[80];
 	struct sip_pvt *p;
+	char branch[33];
 
 	/* exit if we are already in process with this registrar ?*/
 	if ( r == NULL || ((auth==NULL) && (r->regstate==REG_STATE_REGSENT || r->regstate==REG_STATE_AUTHSENT))) {
@@ -5794,7 +5819,6 @@
 		snprintf(addr, sizeof(addr), "sip:%s", r->hostname);
 	ast_string_field_set(p, uri, addr);
 
-	p->branch ^= ast_random();
 
 	memset(&req, 0, sizeof(req));
 	init_req(&req, sipmethod, addr);
@@ -5802,6 +5826,9 @@
 	/* Add to CSEQ */
 	snprintf(tmp, sizeof(tmp), "%u %s", ++r->ocseq, sip_methods[sipmethod].text);
 	p->ocseq = r->ocseq;
+
+	/* This is a new SIP transaction, create a new branch */
+	ast_string_field_build(p, ourbranch, "z9hG4bK-ast-%s",generate_random_string(branch,sizeof(branch)));
 
 	build_via(p);
 	add_header(&req, "Via", p->via);
@@ -5858,7 +5885,7 @@
 {
 	struct sip_request req;
 
-	reqprep(&req, p, SIP_MESSAGE, 0, 1);
+	reqprep(&req, p, SIP_MESSAGE, 0, TRUE);
 	add_text(&req, text);
 	return send_request(p, &req, 1, p->ocseq);
 }
@@ -5907,7 +5934,7 @@
 	ast_string_field_set(p, refer_to, referto);
 	ast_string_field_set(p, referred_by, p->our_contact);
 
-	reqprep(&req, p, SIP_REFER, 0, 1);
+	reqprep(&req, p, SIP_REFER, 0, TRUE);
 	add_header(&req, "Refer-To", referto);
 	add_header(&req, "Allow", ALLOWED_METHODS);
 	add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
@@ -5927,7 +5954,7 @@
 static int transmit_info_with_digit(struct sip_pvt *p, char digit)
 {
 	struct sip_request req;
-	reqprep(&req, p, SIP_INFO, 0, 1);
+	reqprep(&req, p, SIP_INFO, 0, TRUE);
 	add_digit(&req, digit);
 	return send_request(p, &req, 1, p->ocseq);
 }
@@ -9835,7 +9862,7 @@
 {
 	/* Go ahead and send bye at this point */
 	if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
-		transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
+		transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
 		ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
 		ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);	
 	} else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
@@ -9937,6 +9964,11 @@
 			if (p->owner->_state != AST_STATE_UP) {
 				ast_queue_control(p->owner, AST_CONTROL_ANSWER);
 			} else {	/* RE-invite */
+				/* Is this a 200 OK on a re-invite or something else? 
+				 	Could be a 200 OK on another branch than the one
+					we acted on.
+				*/
+				//if (SKREP
 				ast_queue_frame(p->owner, &ast_null_frame);
 			}
 		} else {
@@ -9947,13 +9979,13 @@
 				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
 		}
 		/* If I understand this right, the branch is different for a non-200 ACK only */
-		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, 1);
+		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, TRUE);
 		check_pendings(p);
 		break;
 	case 407: /* Proxy authentication */
 	case 401: /* Www auth */
 		/* First we ACK */
-		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, 0);
+		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
 		if (p->options)
 			p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
 
@@ -9973,7 +10005,7 @@
 		break;
 	case 403: /* Forbidden */
 		/* First we ACK */
-		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, 0);
+		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
 		ast_log(LOG_WARNING, "Received response: \"Forbidden\" from '%s'\n", get_header(&p->initreq, "From"));
 		if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner)
 			ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
@@ -9981,7 +10013,7 @@
 		ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
 		break;
 	case 404: /* Not found */
-		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, 0);
+		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
 		if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE))
 			ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
 		ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
@@ -9989,7 +10021,7 @@
 	case 481: /* Call leg does not exist */
 		/* Could be REFER or INVITE */
 		ast_log(LOG_WARNING, "Re-invite to non-existing call leg on other UA. SIP dialog '%s'. Giving up.\n", p->callid);
-		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, 0);
+		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
 		break;
 	case 491: /* Pending */
 		/* we have to wait a while, then retransmit */
@@ -10216,7 +10248,7 @@
 		if (peer->pokeexpire > -1)
 			ast_sched_del(sched, peer->pokeexpire);
 		if (sipmethod == SIP_INVITE)	/* Does this really happen? */
-			transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, 0);
+			transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
 		ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
 
 		/* Try again eventually */
@@ -10443,7 +10475,7 @@
 				}
 				/* ACK on invite */
 				if (sipmethod == SIP_INVITE) 
-					transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, 0);
+					transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
 				ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
 				if (!p->owner)
 					ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
@@ -11255,7 +11287,8 @@
 			transmit_notify_with_sipfrag(p, seqno, "200 OK");
 			/* Always increment on a BYE */
 			if (!nobye) {
-				transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
+				/*! \note XXX Should this really be a new branch?? */
+				transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
 				ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
 			}
 		}
@@ -11268,6 +11301,16 @@
 		
 	check_via(p, req);
 	ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+
+	if (p->owner && p->owner->_state == AST_STATE_UP) {
+		/* This call is up, cancel is not accepted, we need a bye */
+		transmit_response(p, "200 OK", req);
+		ast_log(LOG_NOTICE, "Got CANCEL on a call that is already up...Call-ID: %s\n", p->callid);
+		return 0;
+	}
+
+	if (p->owner)
+		ast_queue_hangup(p->owner);
 	if (p->rtp) {
 		/* Immediately stop RTP */
 		ast_rtp_stop(p->rtp);
@@ -11276,10 +11319,6 @@
 		/* Immediately stop VRTP */
 		ast_rtp_stop(p->vrtp);
 	}
-	if (p->owner)
-		ast_queue_hangup(p->owner);
-	else
-		ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
 	if (p->initreq.len > 0) {
 		transmit_response_reliable(p, "487 Request Terminated", &p->initreq);
 		transmit_response(p, "200 OK", req);
@@ -11695,9 +11734,27 @@
 		ast_log(LOG_DEBUG, "**** Received %s (%d) - Command in SIP %s\n", sip_methods[p->method].text, sip_methods[p->method].id, cmd); 
 
 	/* Check for loop in INVITE */
-	if (p->icseq && (p->icseq == seqno) && req->method == SIP_INVITE) {
+	if (p->icseq && p->icseq == seqno && req->method == SIP_INVITE) {
+		char *branch = ast_strdupa(req->via);
+		char *tag;
+		char *s;
+		int ok = FALSE;
+		if (ast_strlen_zero(branch)) {
+			ast_log(LOG_DEBUG, "**** NO VIA HEADER in req->via\n");
+			branch = ast_strdupa(get_header(req, "Via"));
+		}
+		tag = strcasestr(branch, ";branch=");
+		if (tag) {
+			if ((s = strchr(tag, ';')))
+				*s = '\0';
+			tag += 8;
+			ast_log(LOG_DEBUG, "### Comparing our branch %s with request branch %s\n", p->viabranchtag, tag);
+				
+		}
+		ok = TRUE;
 		//SKREP
 		ast_log(LOG_DEBUG, "**** Our initial VIA %s - This req VIA %s\n", p->initreq.via, req->via);
+		//if (strcasecmp(p->viabranchtag, ???? )
 	}
 
 	if (p->icseq && (p->icseq > seqno)) {



More information about the asterisk-commits mailing list