[asterisk-commits] dvossel: branch dvossel/sip_request_transaction_matching r275997 - in /team/d...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jul 13 12:02:03 CDT 2010


Author: dvossel
Date: Tue Jul 13 12:01:59 2010
New Revision: 275997

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=275997
Log:
store initial cseq number to match against possible forked requests

Modified:
    team/dvossel/sip_request_transaction_matching/channels/chan_sip.c
    team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h

Modified: team/dvossel/sip_request_transaction_matching/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/sip_request_transaction_matching/channels/chan_sip.c?view=diff&rev=275997&r1=275996&r2=275997
==============================================================================
--- team/dvossel/sip_request_transaction_matching/channels/chan_sip.c (original)
+++ team/dvossel/sip_request_transaction_matching/channels/chan_sip.c Tue Jul 13 12:01:59 2010
@@ -6913,8 +6913,12 @@
 		return NULL;
 	}
 
+	/* If this dialog is created as the result of an incoming Request. Lets store
+	 * some information about that request */
 	if (req) {
 		char *sent_by, *branch;
+		const char *cseq = get_header(req, "Cseq");
+		int seqno;
 		/* get branch parameter from initial Request that started this dialog */
 		get_viabranch(ast_strdupa(get_header(req, "Via")), &sent_by, &branch);
 		/* only store the branch if it begins with the magic prefix "z9hG4bK", otherwise
@@ -6922,6 +6926,12 @@
 		if (!ast_strlen_zero(branch) && !strncasecmp(branch, "z9hG4bK", 7)) {
 			ast_string_field_set(p, initviabranch, branch);
 			ast_string_field_set(p, initviasentby, sent_by);
+		}
+
+		/* Store initial incoming cseq. An error in sscanf here is ignored.  There is no approperiate
+		 * except not storing the number.  CSeq validation must take place before dialog creation in find_call */
+		if (!ast_strlen_zero(cseq) && (sscanf(cseq, "%30u", &seqno) == 1)) {
+			p->init_icseq = seqno;
 		}
 		set_socket_transport(&p->socket, req->socket.type); /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */
 	} else {
@@ -7042,12 +7052,14 @@
 	const char *from = get_header(req, "From");
 	const char *to = get_header(req, "To");
 	const char *cseq = get_header(req, "Cseq");
+	int seqno;
 	struct sip_pvt *sip_pvt_ptr;
 
 	/* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
 	/* get_header always returns non-NULL so we must use ast_strlen_zero() */
 	if (ast_strlen_zero(callid) || ast_strlen_zero(to) ||
-			ast_strlen_zero(from) || ast_strlen_zero(cseq)) {
+			ast_strlen_zero(from) || ast_strlen_zero(cseq) ||
+			(sscanf(cseq, "%30d", &seqno) != 1)) {
 
 		/* RFC 3261 section 24.4.1.   Send a 400 Bad Request if the request is malformed. */
 		if (intended_method != SIP_RESPONSE && intended_method != SIP_ACK) {
@@ -7092,7 +7104,7 @@
 			sip_pvt_lock(sip_pvt_ptr);
 			return sip_pvt_ptr;
 		}
-	} else { /* in pedantic mode! -- do the fancy linear search */
+	} else { /* in pedantic mode! -- do the fancy search */
 		struct sip_pvt tmp_dialog = {
 			.callid = callid,
 		};
@@ -7101,7 +7113,7 @@
 		while (iterator && (sip_pvt_ptr = ao2_iterator_next(iterator))) {
 			if (req->method == SIP_RESPONSE) {
 				/* MATCH RESPONSE with DIALOG */
-				/* check totag if we have one stored for this dialog */
+				/* Verify totag if we have one stored for this dialog */
 				if (!ast_strlen_zero(sip_pvt_ptr->theirtag)) {
 					if (ast_strlen_zero(totag)) {
 						/* missing totag when they already gave us one earlier */
@@ -7112,45 +7124,72 @@
 						goto not_a_match;
 					}
 				}
-				/* check fromtag of response matches the tag we gave them. */
+				/* Verify fromtag of response matches the tag we gave them. */
 				if (strcmp(fromtag, sip_pvt_ptr->tag)) {
 					/* fromtag from response does not match our tag */
 					goto not_a_match;
 				}
 			} else {
 				/* MATCH REQUEST with DIALOG */
+
 				/* Verify the fromtag of Request matches the tag they provided earlier. */
 				if (strcmp(fromtag, sip_pvt_ptr->theirtag)) {
 					/* their tag does not match the one was have stored for them */
 					goto not_a_match;
 				}
-				/* if totag is present in Request, verify it matches what we gave them as our tag earlier */
+
+				/* Verify if totag is present in Request, that it matches what we gave them as our tag earlier */
 				if (!ast_strlen_zero(totag) && (strcmp(totag, sip_pvt_ptr->tag))) {
 					/* totag from Request does not match our tag */
 					goto not_a_match;
 				}
-				/* If totag is NOT present in Request, compare branch parameters with initial Request */
-				if (ast_strlen_zero(totag) && !ast_strlen_zero(sip_pvt_ptr->initviabranch)) {
+
+				/* If totag is not present to match, and the CSeq is the same as our initial request,
+				 * go down the path of comparing branch parameters with initial Request to verify whether
+				 * this is a retransmit or a Forked Request */
+				if (ast_strlen_zero(totag) &&
+					(sip_pvt_ptr->init_icseq == seqno) &&
+					!ast_strlen_zero(sip_pvt_ptr->initviabranch)) {
 					char *sent_by, *branch;
-					/* get branch parameter from top VIA header of Request */
+
+					/* If the methods are different, then this does not match this dialog. */
+					if (sip_pvt_ptr->method != req->method) {
+						/* If the methods are not the same, then this is just a mismatch. */
+						goto not_a_match;
+					}
+
+					/* Compare this Requests VIA header with our initial Request's top Via header.
+					 * If they are the same, this is a retransmit and this dialog matches.*/
 					get_viabranch(ast_strdupa(get_header(req, "Via")), &sent_by, &branch);
 					if (ast_strlen_zero(branch) ||
 						strcmp(branch, sip_pvt_ptr->initviabranch) ||
 						ast_strlen_zero(sent_by) ||
 						strcmp(sent_by, sip_pvt_ptr->initviasentby)) {
 
-						/* If we made it in here, the branch and sent_by of top VIA did not match our initial Request */
-						if (sip_pvt_ptr->method != req->method) {
-							/* If the methods are not the same, then this is just a normal mismatch. */
-							goto not_a_match;
-						} else {
-							/* Loop Detected: everything is the EXACT same about this Request and the initial
-							 * request except the branch parameters are different in the TOP VIA. */
-							goto loop_detected;
-						}
+						/* If we are here, everything matches the initial Request except for the top Via */
+
+						/* FORK DETECTION CRITERIA
+						 *
+						 * ---Current Matches to Initial Request---
+						 * Call-id
+						 * their-tag
+						 * no totag present
+					 	 * method
+					 	 * cseq
+						 *
+					 	 * --- Does not Match Initial Request ---
+					 	 * Top Via
+						 *
+						 * Without the same Via, this can not match our initial transaction for this dialog,
+						 * but given that this Request matches everything else associated with that initial
+						 * Request this is most certainly a Forked request in which we have already received
+						 * part of the fork.
+					 	 */
+						goto loop_detected;
 					}
-				}
-			}
+				} /* end of Request Via check */
+			} /* end of Request/Response matching */
+
 			/* If we made it here, then this is a match. Leave the reference from the iterator */
 			sip_pvt_lock(sip_pvt_ptr);
 			ao2_iterator_destroy(iterator);
@@ -7160,16 +7199,16 @@
 			/* This is likely a forked Request that somehow resulted in us receiving multiple parts of the fork.
 			 * RFC 3261 section 8.2.2.2, Indicate that we want to merge requests by sending a 482 response. */
 			transmit_response_using_temp(callid, addr, 1, intended_method, req, "482 (Loop Detected)");
-			dialog_unref(sip_pvt_ptr, "This pvt did not match incomming SIP msg, unref pvt from find_call search.");
+			dialog_unref(sip_pvt_ptr, "This pvt did not match incoming SIP msg, unref pvt from find_call search.");
 			return NULL;
 not_a_match:
-			dialog_unref(sip_pvt_ptr, "This pvt did not match incomming SIP msg, unref pvt from find_call search.");
+			dialog_unref(sip_pvt_ptr, "This pvt did not match incoming SIP msg, unref pvt from find_call search.");
 		} /* end of while */
 
 		if (iterator) {
 			ao2_iterator_destroy(iterator);
 		}
-	}
+	} /* end of pedantic mode Request/Reponse to Dialog matching */
 
 	/* See if the method is capable of creating a dialog */
 	if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) {

Modified: team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h?view=diff&rev=275997&r1=275996&r2=275997
==============================================================================
--- team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h (original)
+++ team/dvossel/sip_request_transaction_matching/channels/sip/include/sip.h Tue Jul 13 12:01:59 2010
@@ -959,6 +959,7 @@
 	struct sip_socket socket;               /*!< The socket used for this dialog */
 	unsigned int ocseq;                     /*!< Current outgoing seqno */
 	unsigned int icseq;                     /*!< Current incoming seqno */
+	unsigned int init_icseq;                /*!< Initial incoming seqno from first request */
 	ast_group_t callgroup;                  /*!< Call group */
 	ast_group_t pickupgroup;                /*!< Pickup group */
 	int lastinvite;                         /*!< Last Cseq of invite */




More information about the asterisk-commits mailing list