2
0
Эх сурвалжийг харах

tm: detect blind uac branch to avoid generating cancel for it

Daniel-Constantin Mierla 9 жил өмнө
parent
commit
e36eebf36b

+ 5 - 4
modules/tm/h_table.h

@@ -183,9 +183,10 @@ typedef struct ua_server
 /* User Agent Client content */
 /* User Agent Client content */
 
 
 /* UAC internal flags */
 /* UAC internal flags */
-#define TM_UAC_FLAG_RR	1	/* Record-Route applied */
-#define TM_UAC_FLAG_R2	2	/* 2nd Record-Route applied */
-#define TM_UAC_FLAG_FB	4	/* Mark first entry in new branch set */
+#define TM_UAC_FLAG_RR	(1)		/* Record-Route applied */
+#define TM_UAC_FLAG_R2	(1<<1)	/* 2nd Record-Route applied */
+#define TM_UAC_FLAG_FB	(1<<2)	/* Mark first entry in new branch set */
+#define TM_UAC_FLAG_BLIND	(1<<3)	/* A blind uac */
 
 
 typedef struct ua_client
 typedef struct ua_client
 {
 {
@@ -194,7 +195,7 @@ typedef struct ua_client
 	char *end_reply;	/* pointer to end of sip_msg so we know the shm blocked used in clone...(used in async replies) */
 	char *end_reply;	/* pointer to end of sip_msg so we know the shm blocked used in clone...(used in async replies) */
 	struct retr_buf  request;
 	struct retr_buf  request;
 	/* we maintain a separate copy of cancel rather than
 	/* we maintain a separate copy of cancel rather than
-	   reuse the structure for original request; the 
+	   reuse the structure for original request; the
 	   original request is no longer needed but its delayed
 	   original request is no longer needed but its delayed
 	   timer may fire and interfere with whoever tries to
 	   timer may fire and interfere with whoever tries to
 	   rewrite it
 	   rewrite it

+ 7 - 2
modules/tm/t_cancel.h

@@ -103,9 +103,14 @@ inline short static prepare_cancel_branch( struct cell *t, int b, int noreply )
 	int last_received;
 	int last_received;
 	unsigned long old;
 	unsigned long old;
 
 
+	/* blind uac branch (e.g., suspend) without outgoing request */
+	if((t->uac[b].flags & TM_UAC_FLAG_BLIND)
+			&& t->uac[b].request.buffer==NULL)
+		return 0;
+
 	last_received=t->uac[b].last_received;
 	last_received=t->uac[b].last_received;
-	/* if noreply=1 cancel even if no reply received (in this case 
-	 * cancel_branch()  won't actually send the cancel but it will do the 
+	/* if noreply=1 cancel even if no reply received (in this case
+	 * cancel_branch()  won't actually send the cancel but it will do the
 	 * cleanup) */
 	 * cleanup) */
 	if (last_received<200 && (noreply || last_received>=100)){
 	if (last_received<200 && (noreply || last_received>=100)){
 		old=atomic_cmpxchg_long((void*)&t->uac[b].local_cancel.buffer, 0,
 		old=atomic_cmpxchg_long((void*)&t->uac[b].local_cancel.buffer, 0,

+ 15 - 2
modules/tm/t_fwd.c

@@ -711,6 +711,8 @@ int add_blind_uac( /*struct cell *t*/ )
 	t->flags |= T_NOISY_CTIMER_FLAG;
 	t->flags |= T_NOISY_CTIMER_FLAG;
 	membar_write(); /* to allow lockless prepare_to_cancel() we want to be sure
 	membar_write(); /* to allow lockless prepare_to_cancel() we want to be sure
 					   all the writes finished before updating branch number*/
 					   all the writes finished before updating branch number*/
+
+	t->uac[branch].flags |= TM_UAC_FLAG_BLIND;
 	t->nr_of_outgoings=(branch+1);
 	t->nr_of_outgoings=(branch+1);
 	t->async_backup.blind_uac = branch; /* whenever we create a blind UAC, lets save the current branch
 	t->async_backup.blind_uac = branch; /* whenever we create a blind UAC, lets save the current branch
 					 * this is used in async tm processing specifically to be able to route replies
 					 * this is used in async tm processing specifically to be able to route replies
@@ -1280,9 +1282,19 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 		t_reply( t_cancel, cancel_msg, 200, CANCEL_DONE );
 		t_reply( t_cancel, cancel_msg, 200, CANCEL_DONE );
 		return;
 		return;
 	}
 	}
-	
+
 	/* determine which branches to cancel ... */
 	/* determine which branches to cancel ... */
 	prepare_to_cancel(t_invite, &cancel_bm, 0);
 	prepare_to_cancel(t_invite, &cancel_bm, 0);
+
+	/* no branches to cancel (e.g., a suspended transaction with blind uac) */
+	if (cancel_bm==0){
+		/* no outgoing 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 active branches\n");
+		t_reply( t_cancel, cancel_msg, 200, CANCEL_DONE );
+		return;
+	}
+
 #ifdef E2E_CANCEL_HOP_BY_HOP
 #ifdef E2E_CANCEL_HOP_BY_HOP
 	/* we don't need to set t_cancel label to be the same as t_invite if
 	/* we don't need to set t_cancel label to be the same as t_invite if
 	 * we do hop by hop cancel. The cancel transaction will have a different 
 	 * we do hop by hop cancel. The cancel transaction will have a different 
@@ -1311,7 +1323,7 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 		}
 		}
 	}
 	}
 #endif /* CANCEL_REASON_SUPPORT */
 #endif /* CANCEL_REASON_SUPPORT */
-	for (i=0; i<t_invite->nr_of_outgoings; i++)
+	for (i=0; i<t_invite->nr_of_outgoings; i++) {
 		if (cancel_bm & (1<<i)) {
 		if (cancel_bm & (1<<i)) {
 			/* it's safe to get the reply lock since e2e_cancel is
 			/* it's safe to get the reply lock since e2e_cancel is
 			 * called with the cancel as the "current" transaction so
 			 * called with the cancel as the "current" transaction so
@@ -1330,6 +1342,7 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 			if (ret<0) cancel_bm &= ~(1<<i);
 			if (ret<0) cancel_bm &= ~(1<<i);
 			if (ret<lowest_error) lowest_error=ret;
 			if (ret<lowest_error) lowest_error=ret;
 		}
 		}
+	}
 #ifdef CANCEL_REASON_SUPPORT
 #ifdef CANCEL_REASON_SUPPORT
 	if (unlikely(free_reason)) {
 	if (unlikely(free_reason)) {
 		/* reason was not set as the global reason => free it */
 		/* reason was not set as the global reason => free it */