Browse Source

- request matching using tid (RFC3216) introduced

Jiri Kuthan 23 years ago
parent
commit
3bd0930b2c
7 changed files with 137 additions and 12 deletions
  1. 4 0
      modules/tm/config.h
  2. 3 0
      modules/tm/sip_msg.c
  3. 1 1
      modules/tm/t_funcs.c
  4. 124 9
      modules/tm/t_lookup.c
  5. 1 1
      modules/tm/timer.c
  6. 3 1
      parser/msg_parser.h
  7. 1 0
      parser/parse_via.h

+ 4 - 0
modules/tm/config.h

@@ -94,4 +94,8 @@
 */
 #undef ACK_FORKING_HACK
 
+/* magic cookie for transaction matching as defined in RFC3261 */
+#define MCOOKIE "z9hG4bK"
+#define MCOOKIE_LEN (sizeof(MCOOKIE)-1)
+
 #endif

+ 3 - 0
modules/tm/sip_msg.c

@@ -100,6 +100,9 @@ inline struct via_body* via_body_cloner( char* new_buf,
 			translate_pointer(new_buf,org_buf,org_via->port_str.s);
 		/* params (str type) */
 		new_via->params.s=translate_pointer(new_buf,org_buf,org_via->params.s);
+		/* transaction id */
+		new_via->tid.s=
+			translate_pointer(new_buf, org_buf, org_via->tid.s);
 		/* comment (str type) */
 		new_via->comment.s=
 			translate_pointer(new_buf,org_buf,org_via->comment.s);

+ 1 - 1
modules/tm/t_funcs.c

@@ -121,7 +121,7 @@ void put_on_wait(  struct cell  *Trans  )
 	}
 #endif
 #ifdef EXTRA_DEBUG
-	DBG("DEBUG: --- out on WAIT --- \n");
+	DBG("DEBUG: put on WAIT \n");
 #endif
 
 

+ 124 - 9
modules/tm/t_lookup.c

@@ -116,6 +116,60 @@ struct cell *get_t() { return T; }
 void init_t() {global_msg_id=0; T=T_UNDEFINED;}
 
 
+/* transaction matching a-la RFC-3261 using transaction ID in branch
+ * (the function assumes there is magic cookie in branch) */
+
+static struct cell *tid_matching( int hash_index, 
+		struct via_body *via1, 
+		enum request_method skip_method)
+{
+	struct cell *p_cell;
+	struct sip_msg  *t_msg;
+
+
+	/* update parsed tid */
+	via1->tid.s=via1->branch->value.s+MCOOKIE_LEN;
+	via1->tid.len=via1->branch->value.len-MCOOKIE_LEN;
+
+	for ( p_cell = get_tm_table()->entrys[hash_index].first_cell;
+		p_cell; p_cell = p_cell->next_cell ) 
+	{
+		t_msg=p_cell->uas.request;
+		if (skip_method & t_msg->REQ_METHOD)
+			continue;
+		if (t_msg->via1->tid.len!=via1->tid.len)
+			continue;
+		if (memcmp(t_msg->via1->tid.s, via1->tid.s,
+				via1->tid.len)!=0)
+			continue;
+		/* ok, tid matches -- now make sure that the
+		 * originater matches too to avoid confusion with
+		 * different senders generating the same tid
+		 */
+		if (via1->host.len!=t_msg->via1->host.len)
+			continue;
+		if (memcmp(via1->host.s, t_msg->via1->host.s,
+					via1->host.len)!=0)
+			continue;
+		if (via1->port!=t_msg->via1->port)
+			continue;
+		if (via1->transport.len!=t_msg->via1->transport.len)
+			continue;
+		if (memcmp(via1->transport.s, t_msg->via1->transport.s,
+					via1->transport.len)!=0)
+			continue;
+		/* all matched -- we found the transaction ! */
+		DBG("DEBUG: RFC3261 transaction matched, tid=%.*s\n",
+			via1->tid.len, via1->tid.s);
+
+		return p_cell;
+	}
+	/* :-( ... we didn't find any */
+	DBG("DEBUG: RFC3261 transaction matching failed\n");
+	return 0;
+}
+
+
 /* function returns:
  *      negative - transaction wasn't found
  *			(-2 = possibly e2e ACK matched )
@@ -128,6 +182,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 	unsigned int       isACK;
 	struct sip_msg  *t_msg;
 	int ret;
+	struct via_param *branch;
 
 	/* parse all*/
 	if (check_transaction_quadruple(p_msg)==0)
@@ -146,10 +201,37 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 	DBG("t_lookup_request: start searching: hash=%d, isACK=%d\n",
 		p_msg->hash_index,isACK);
 
+
 	/* asume not found */
 	ret=-1;
 
-	/* lock the hole entry*/
+	/* first of all, look if there is RFC3261 magic cookie in branch; if
+	 * so, we can do very quick matching and skip the old-RFC bizzar
+	 * comparison of many header fields
+	 */
+	if (!p_msg->via1) {
+		LOG(L_ERR, "ERROR: t_lookup_request: no via\n");
+		T=0;
+		return 0;
+	}
+	branch=p_msg->via1->branch;
+	if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN
+			&& memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) {
+		/* huhuhu! the cookie is there -- let's proceed fast */
+		LOCK_HASH(p_msg->hash_index);
+		p_cell=tid_matching(p_msg->hash_index, p_msg->via1, 
+				/* skip transactions with different
+				 * method; otherwise CANCEL would 
+				 * match the previous INVITE trans.
+				 */
+				isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD);
+		if (p_cell) goto found; else goto notfound;
+	}
+
+	/* ok -- it's ugly old-fashioned transaction matching */
+	DBG("DEBUG: proceeding to pre-RFC3261 transaction matching\n");
+
+	/* lock the whole entry*/
 	LOCK_HASH(p_msg->hash_index);
 
 	/* all the transactions from the entry are compared */
@@ -250,6 +332,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 		} /* ACK */
 	} /* synonym loop */
 
+notfound:
 	/* no transaction found */
 	T = 0;
 	if (!leave_new_locked) {
@@ -269,7 +352,8 @@ found:
 
 
 
-/* function returns:
+/* function lookups transaction being cancelled by CANCEL in p_msg;
+ * it returns:
  *       0 - transaction wasn't found
  *       T - transaction found
  */
@@ -278,13 +362,40 @@ struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
 	struct cell     *p_cell;
 	unsigned int     hash_index;
 	struct sip_msg  *t_msg;
+	struct via_param *branch;
 
 
 	/* start searching in the table */
 	hash_index = p_msg->hash_index;
-	LOCK_HASH(hash_index);
 	DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );
 
+
+	/* first of all, look if there is RFC3261 magic cookie in branch; if
+	 * so, we can do very quick matching and skip the old-RFC bizzar
+	 * comparison of many header fields
+	 */
+	if (!p_msg->via1) {
+		LOG(L_ERR, "ERROR: t_lookup_request: no via\n");
+		T=0;
+		return 0;
+	}
+	branch=p_msg->via1->branch;
+	if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN
+			&& memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) {
+		/* huhuhu! the cookie is there -- let's proceed fast */
+		LOCK_HASH(hash_index);
+		p_cell=tid_matching(hash_index, p_msg->via1, 
+				/* we are seeking the original transaction --
+				 * skip CANCEL transactions during search
+				 */
+				METHOD_CANCEL);
+		if (p_cell) goto found; else goto notfound;
+	}
+
+	/* no cookies --proceed to old-fashioned pre-3261 t-matching */
+
+	LOCK_HASH(hash_index);
+
 	/* all the transactions from the entry are compared */
 	for (p_cell=get_tm_table()->entrys[hash_index].first_cell;
 		p_cell; p_cell = p_cell->next_cell )
@@ -340,19 +451,23 @@ struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
 			continue;
 
 		/* found */
-		DBG("DEBUG: t_lookupOriginalT: canceled transaction"
-			" found (%p)! \n",p_cell );
-		REF_UNSAFE( p_cell );
-		UNLOCK_HASH(hash_index);
-		DBG("DEBUG: t_lookupOriginalT completed\n");
-		return p_cell;
+		goto found;
 	}
 
+notfound:
 	/* no transaction found */
 	DBG("DEBUG: t_lookupOriginalT: no CANCEL maching found! \n" );
 	UNLOCK_HASH(hash_index);
 	DBG("DEBUG: t_lookupOriginalT completed\n");
 	return 0;
+
+found:
+	DBG("DEBUG: t_lookupOriginalT: canceled transaction"
+		" found (%p)! \n",p_cell );
+	REF_UNSAFE( p_cell );
+	UNLOCK_HASH(hash_index);
+	DBG("DEBUG: t_lookupOriginalT completed\n");
+	return p_cell;
 }
 
 

+ 1 - 1
modules/tm/timer.c

@@ -397,7 +397,7 @@ inline static void wait_handler( void *attr)
 			" called from WAIT timer\n",p_cell);
 		abort();
 	}	
-	DBG("DEBUG: ---------- WAIT timer hit ------- \n");
+	DBG("DEBUG: WAIT timer hit\n");
 #endif
 
 	/* stop cancel timers if any running */

+ 3 - 1
parser/msg_parser.h

@@ -56,7 +56,9 @@
 #define REPLY_STATUS first_line.u.reply.statuscode
 #define REPLY_CLASS(_reply) ((_reply)->REPLY_STATUS/100)
 
-enum { METHOD_OTHER, METHOD_INVITE, METHOD_CANCEL, METHOD_ACK, METHOD_BYE };
+/* number methods as power of two to allow bitmap matching */
+enum request_method { METHOD_INVITE=1, METHOD_CANCEL=2, METHOD_ACK=4, 
+	METHOD_BYE=8, METHOD_OTHER=16 };
 
 #define IFISMETHOD(methodname,firstchar)                                  \
 if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \

+ 1 - 0
parser/parse_via.h

@@ -68,6 +68,7 @@ struct via_body {
 
 	     /* shortcuts to "important" params*/
 	struct via_param* branch;
+	str tid; /* transaction id, part of branch */
 	struct via_param* received;
 	
 	struct via_body* next; /* pointer to next via body string if