Bläddra i källkod

- cancel before invite fix attempt (experimental, treat with care)
This fix should handle delayed INVITEs (due to network or script), that arrive
after the CANCEL. The INV transaction will be created (it's needed for the
reply) but immediately canceled.

Andrei Pelinescu-Onciul 19 år sedan
förälder
incheckning
ec76200fbb
5 ändrade filer med 78 tillägg och 16 borttagningar
  1. 1 1
      Makefile.defs
  2. 2 0
      modules/tm/h_table.h
  3. 17 0
      modules/tm/t_fwd.c
  4. 56 14
      modules/tm/t_lookup.c
  5. 2 1
      modules/tm/t_lookup.h

+ 1 - 1
Makefile.defs

@@ -61,7 +61,7 @@ MAIN_NAME=ser
 VERSION = 0
 VERSION = 0
 PATCHLEVEL = 10
 PATCHLEVEL = 10
 SUBLEVEL =   99
 SUBLEVEL =   99
-EXTRAVERSION = -dev30-tm-timers
+EXTRAVERSION = -dev31-tm-cancel
 
 
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
 			$(SUBLEVEL) )
 			$(SUBLEVEL) )

+ 2 - 0
modules/tm/h_table.h

@@ -180,6 +180,8 @@ struct totag_elem {
 /* set to one if you want to disallow silent transaction
 /* set to one if you want to disallow silent transaction
    dropping when C timer hits */
    dropping when C timer hits */
 #define T_NOISY_CTIMER_FLAG  (1<<2)
 #define T_NOISY_CTIMER_FLAG  (1<<2)
+/* transaction canceled */
+#define T_CANCELED           (1<<3)
 
 
 #define T_IN_AGONY (1<<3) /* set if waiting to die (delete timer)
 #define T_IN_AGONY (1<<3) /* set if waiting to die (delete timer)
                              TODO: replace it with del on unref */
                              TODO: replace it with del on unref */

+ 17 - 0
modules/tm/t_fwd.c

@@ -45,6 +45,8 @@
  *  2005-08-04  msg->parsed_uri and parsed_uri_ok are no saved & restored
  *  2005-08-04  msg->parsed_uri and parsed_uri_ok are no saved & restored
  *               before & after handling the branches (andrei)
  *               before & after handling the branches (andrei)
  *  2005-12-11  onsend_route support added for forwarding (andrei)
  *  2005-12-11  onsend_route support added for forwarding (andrei)
+ *  2006-01-27  t_forward_no_ack will return error if a forward on an 
+ *              already canceled transaction is attempted (andrei)
  */
  */
 
 
 #include "defs.h"
 #include "defs.h"
@@ -373,6 +375,16 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 	cancel_bm=0;
 	cancel_bm=0;
 	lowest_error=0;
 	lowest_error=0;
 
 
+	/* first check if there are any branches */
+	if (t_invite->nr_of_outgoings==0){
+		t_invite->flags|=T_CANCELED;
+		/* no branches yet => force a reply to the invite */
+		t_reply( t_invite, t_invite->uas.request, 487, CANCELED );
+		DBG("DEBUG: e2e_cancel: e2e cancel -- no more pending branches\n");
+		t_reply( t_cancel, cancel_msg, 200, CANCEL_DONE );
+		return;
+	}
+	
 	backup_uri=cancel_msg->new_uri;
 	backup_uri=cancel_msg->new_uri;
 	backup_parsed_uri_ok=cancel_msg->parsed_uri_ok;
 	backup_parsed_uri_ok=cancel_msg->parsed_uri_ok;
 	backup_parsed_uri=cancel_msg->parsed_uri;
 	backup_parsed_uri=cancel_msg->parsed_uri;
@@ -476,6 +488,11 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 			return 1;
 			return 1;
 		}
 		}
 	}
 	}
+	if (t->flags & T_CANCELED){
+		DBG("t_forward_non_ack: no forwarding on canceled branch\n");
+		ser_error=E_CANCELED;
+		return -1;
+	}
 
 
 	/* backup current uri ... add_uac changes it */
 	/* backup current uri ... add_uac changes it */
 	backup_uri = p_msg->new_uri;
 	backup_uri = p_msg->new_uri;

+ 56 - 14
modules/tm/t_lookup.c

@@ -79,7 +79,10 @@
  * 2004-10-10: use of mhomed disabled for replies (jiri)
  * 2004-10-10: use of mhomed disabled for replies (jiri)
  * 2005-02-01: use the incoming request interface for sending the replies
  * 2005-02-01: use the incoming request interface for sending the replies
  *             - changes in init_rb() (bogdan)
  *             - changes in init_rb() (bogdan)
- *  2005-12-09  added t_set_fr()  (andrei)
+ * 2005-12-09  added t_set_fr()  (andrei)
+ * 2006-01-27  transaction lookup function will set up a cancel flag
+ *             if the searched transaction was pre-canceled (andrei)
+ * 
  */
  */
 
 
 #include "defs.h"
 #include "defs.h"
@@ -285,10 +288,11 @@ static inline int via_matching( struct via_body *inv_via,
 	 2 if e2e ACK for a proxied transaction found
 	 2 if e2e ACK for a proxied transaction found
      1  if found (covers ACK for local UAS)
      1  if found (covers ACK for local UAS)
 	 0  if not found (trans undefined)
 	 0  if not found (trans undefined)
+	It also sets *cancel if a cancel was found for the searched transaction
 */
 */
 
 
 static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
 static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
-			enum request_method skip_method)
+			enum request_method skip_method, int* cancel)
 {
 {
 	struct cell *p_cell;
 	struct cell *p_cell;
 	struct sip_msg  *t_msg;
 	struct sip_msg  *t_msg;
@@ -298,6 +302,7 @@ static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
 	int ret = 0;
 	int ret = 0;
 	struct cell *e2e_ack_trans;
 	struct cell *e2e_ack_trans;
 
 
+	*cancel=0;
 	e2e_ack_trans=0;
 	e2e_ack_trans=0;
 	via1=p_msg->via1;
 	via1=p_msg->via1;
 	is_ack=p_msg->REQ_METHOD==METHOD_ACK;
 	is_ack=p_msg->REQ_METHOD==METHOD_ACK;
@@ -311,7 +316,12 @@ static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
 	{
 	{
 		t_msg=p_cell->uas.request;
 		t_msg=p_cell->uas.request;
 		if (!t_msg) continue;  /* don't try matching UAC transactions */
 		if (!t_msg) continue;  /* don't try matching UAC transactions */
-		if (skip_method & t_msg->REQ_METHOD) continue;
+		/* we want to set *cancel for transaction for which there is
+		 * already a canceled transaction (e.g. re-ordered INV-CANCEL, or
+		 *  INV blocked in dns lookup); we don't care about ACKs */
+		if ((is_ack || (t_msg->REQ_METHOD!=METHOD_CANCEL)) && 
+				(skip_method & t_msg->REQ_METHOD)) 
+			continue;
 
 
 		/* here we do an exercise which will be removed from future code
 		/* here we do an exercise which will be removed from future code
 		   versions: we try to match end-2-end ACKs if they appear at our
 		   versions: we try to match end-2-end ACKs if they appear at our
@@ -351,6 +361,13 @@ static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
 	 	 * other requests */
 	 	 * other requests */
 		if (!via_matching(t_msg->via1 /* inv via */, via1 /* ack */ ))
 		if (!via_matching(t_msg->via1 /* inv via */, via1 /* ack */ ))
 			continue;
 			continue;
+		if (t_msg->REQ_METHOD==METHOD_CANCEL){
+			if ((p_msg->REQ_METHOD!=METHOD_CANCEL) && !is_ack){
+			/* found an existing cancel for the searched transaction */
+				*cancel=1;
+			}
+			if (skip_method & t_msg->REQ_METHOD) continue;
+		}
 		/* all matched -- we found the transaction ! */
 		/* all matched -- we found the transaction ! */
 		DBG("DEBUG: RFC3261 transaction matched, tid=%.*s\n",
 		DBG("DEBUG: RFC3261 transaction matched, tid=%.*s\n",
 			via1->tid.len, via1->tid.s);
 			via1->tid.len, via1->tid.s);
@@ -374,9 +391,11 @@ static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
  *      negative - transaction wasn't found
  *      negative - transaction wasn't found
  *			(-2 = possibly e2e ACK matched )
  *			(-2 = possibly e2e ACK matched )
  *      positive - transaction found
  *      positive - transaction found
+ * It also sets *cancel if a there is already a cancel transaction
  */
  */
 
 
-int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
+int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked,
+						int* cancel)
 {
 {
 	struct cell         *p_cell;
 	struct cell         *p_cell;
 	unsigned int       isACK;
 	unsigned int       isACK;
@@ -422,9 +441,10 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 		/* huhuhu! the cookie is there -- let's proceed fast */
 		/* huhuhu! the cookie is there -- let's proceed fast */
 		LOCK_HASH(p_msg->hash_index);
 		LOCK_HASH(p_msg->hash_index);
 		match_status=matching_3261(p_msg,&p_cell, 
 		match_status=matching_3261(p_msg,&p_cell, 
-				/* skip transactions with different method; otherwise CANCEL would 
-	 	 		 * match the previous INVITE trans.  */
-				isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD);
+				/* skip transactions with different method; otherwise CANCEL 
+				 * would  match the previous INVITE trans.  */
+				isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD, 
+				cancel);
 		switch(match_status) {
 		switch(match_status) {
 				case 0:	goto notfound;	/* no match */
 				case 0:	goto notfound;	/* no match */
 				case 1:	goto found; 	/* match */
 				case 1:	goto found; 	/* match */
@@ -436,7 +456,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 	 * a bit simplified to be fast -- we don't do all the comparisons
 	 * a bit simplified to be fast -- we don't do all the comparisons
 	 * of parsed uri, which was simply too bloated */
 	 * of parsed uri, which was simply too bloated */
 	DBG("DEBUG: proceeding to pre-RFC3261 transaction matching\n");
 	DBG("DEBUG: proceeding to pre-RFC3261 transaction matching\n");
-
+	*cancel=0;
 	/* lock the whole entry*/
 	/* lock the whole entry*/
 	LOCK_HASH(p_msg->hash_index);
 	LOCK_HASH(p_msg->hash_index);
 
 
@@ -449,9 +469,17 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 		if (!t_msg) continue; /* skip UAC transactions */
 		if (!t_msg) continue; /* skip UAC transactions */
 
 
 		if (!isACK) {	
 		if (!isACK) {	
+			/* for non-ACKs we want same method matching, we 
+			 * make an exception for pre-exisiting CANCELs because we
+			 * want to set *cancel */
+			if ((t_msg->REQ_METHOD!=p_msg->REQ_METHOD) &&
+					(t_msg->REQ_METHOD!=METHOD_CANCEL))
+					continue;
 			/* compare lengths first */ 
 			/* compare lengths first */ 
 			if (!EQ_LEN(callid)) continue;
 			if (!EQ_LEN(callid)) continue;
-			if (!EQ_LEN(cseq)) continue;
+			/* CSeq only the number without method ! */
+			if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
+				continue;
 			if (!EQ_LEN(from)) continue;
 			if (!EQ_LEN(from)) continue;
 			if (!EQ_LEN(to)) continue;
 			if (!EQ_LEN(to)) continue;
 			if (ruri_matching && !EQ_REQ_URI_LEN) continue;
 			if (ruri_matching && !EQ_REQ_URI_LEN) continue;
@@ -459,12 +487,20 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 
 
 			/* length ok -- move on */
 			/* length ok -- move on */
 			if (!EQ_STR(callid)) continue;
 			if (!EQ_STR(callid)) continue;
-			if (!EQ_STR(cseq)) continue;
+			if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
+				get_cseq(p_msg)->number.len)!=0) continue;
 			if (!EQ_STR(from)) continue;
 			if (!EQ_STR(from)) continue;
 			if (!EQ_STR(to)) continue;
 			if (!EQ_STR(to)) continue;
 			if (ruri_matching && !EQ_REQ_URI_STR) continue;
 			if (ruri_matching && !EQ_REQ_URI_STR) continue;
 			if (via1_matching && !EQ_VIA_STR(via1)) continue;
 			if (via1_matching && !EQ_VIA_STR(via1)) continue;
-
+			
+			if ((t_msg->REQ_METHOD==METHOD_CANCEL) &&
+				(p_msg->REQ_METHOD!=METHOD_CANCEL)){
+				/* we've matched an existing CANCEL */
+				*cancel=1;
+				continue;
+			}
+			
 			/* request matched ! */
 			/* request matched ! */
 			DBG("DEBUG: non-ACK matched\n");
 			DBG("DEBUG: non-ACK matched\n");
 			goto found;
 			goto found;
@@ -564,6 +600,7 @@ struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
 	unsigned int     hash_index;
 	unsigned int     hash_index;
 	struct sip_msg  *t_msg;
 	struct sip_msg  *t_msg;
 	struct via_param *branch;
 	struct via_param *branch;
+	int foo;
 	int ret;
 	int ret;
 
 
 
 
@@ -590,7 +627,7 @@ struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
 				/* we are seeking the original transaction --
 				/* we are seeking the original transaction --
 				 * skip CANCEL transactions during search
 				 * skip CANCEL transactions during search
 				 */
 				 */
-				METHOD_CANCEL);
+				METHOD_CANCEL, &foo);
 		if (ret==1) goto found; else goto notfound;
 		if (ret==1) goto found; else goto notfound;
 	}
 	}
 
 
@@ -869,6 +906,7 @@ nomatch2:
 int t_check( struct sip_msg* p_msg , int *param_branch )
 int t_check( struct sip_msg* p_msg , int *param_branch )
 {
 {
 	int local_branch;
 	int local_branch;
+	int canceled;
 
 
 	/* is T still up-to-date ? */
 	/* is T still up-to-date ? */
 	DBG("DEBUG: t_check: msg id=%d global id=%d T start=%p\n", 
 	DBG("DEBUG: t_check: msg id=%d global id=%d T start=%p\n", 
@@ -894,7 +932,8 @@ int t_check( struct sip_msg* p_msg , int *param_branch )
 				LOG(L_ERR, "ERROR: t_check: from parsing failed\n");
 				LOG(L_ERR, "ERROR: t_check: from parsing failed\n");
 				return -1;
 				return -1;
 			}
 			}
-			t_lookup_request( p_msg , 0 /* unlock before returning */ );
+			t_lookup_request( p_msg , 0 /* unlock before returning */,
+								&canceled);
 		} else {
 		} else {
 			/* we need Via for branch and Cseq method to distinguish
 			/* we need Via for branch and Cseq method to distinguish
 			   replies with the same branch/cseqNr (CANCEL)
 			   replies with the same branch/cseqNr (CANCEL)
@@ -1076,6 +1115,7 @@ static inline int new_t(struct sip_msg *p_msg)
 int t_newtran( struct sip_msg* p_msg )
 int t_newtran( struct sip_msg* p_msg )
 {
 {
 	int lret, my_err;
 	int lret, my_err;
+	int canceled;
 
 
 
 
 	/* is T still up-to-date ? */
 	/* is T still up-to-date ? */
@@ -1109,7 +1149,8 @@ int t_newtran( struct sip_msg* p_msg )
 	   it also calls check_transaction_quadruple -> it is
 	   it also calls check_transaction_quadruple -> it is
 	   safe to assume we have from/callid/cseq/to
 	   safe to assume we have from/callid/cseq/to
 	*/ 
 	*/ 
-	lret = t_lookup_request( p_msg, 1 /* leave locked if not found */ );
+	lret = t_lookup_request( p_msg, 1 /* leave locked if not found */,
+								&canceled );
 
 
 	/* on error, pass the error in the stack ... nothing is locked yet
 	/* on error, pass the error in the stack ... nothing is locked yet
 	   if 0 is returned */
 	   if 0 is returned */
@@ -1162,6 +1203,7 @@ int t_newtran( struct sip_msg* p_msg )
 		LOG(L_ERR, "ERROR: t_newtran: new_t failed\n");
 		LOG(L_ERR, "ERROR: t_newtran: new_t failed\n");
 		goto new_err;
 		goto new_err;
 	}
 	}
+	if (canceled) T->flags|=T_CANCELED; /* mark it for future ref. */
 
 
 
 
 	UNLOCK_HASH(p_msg->hash_index);
 	UNLOCK_HASH(p_msg->hash_index);

+ 2 - 1
modules/tm/t_lookup.h

@@ -55,7 +55,8 @@ void init_t();
 int init_rb( struct retr_buf *rb, struct sip_msg *msg );
 int init_rb( struct retr_buf *rb, struct sip_msg *msg );
 struct cell* t_lookupOriginalT( struct sip_msg* p_msg );
 struct cell* t_lookupOriginalT( struct sip_msg* p_msg );
 int t_reply_matching( struct sip_msg* , int* );
 int t_reply_matching( struct sip_msg* , int* );
-int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked );
+int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked,
+						int* canceled);
 int t_newtran( struct sip_msg* p_msg );
 int t_newtran( struct sip_msg* p_msg );
 
 
 int _add_branch_label( struct cell *trans,
 int _add_branch_label( struct cell *trans,