浏览代码

- added a new tm parameter (cancel_b_method) that selects between 3 different
behaviours when attempting to cancel a branch where no reply was received:
0 (default) - stop request retransmission and send back a fake 487 (old ser
behaviour) ;
1 - keep retransmitting the request until a reply is received or the final
reply timeout kicks in ;
2 - stop request retransmission and send and retransmit a cancel on the
branch (this is not rfc conformant, but IMHO it wouldn't hurt) .

Andrei Pelinescu-Onciul 17 年之前
父节点
当前提交
68d3acafc6
共有 7 个文件被更改,包括 111 次插入29 次删除
  1. 5 0
      modules/tm/config.c
  2. 1 0
      modules/tm/config.h
  3. 74 19
      modules/tm/t_cancel.c
  4. 9 2
      modules/tm/t_cancel.h
  5. 11 6
      modules/tm/t_fwd.c
  6. 1 1
      modules/tm/t_reply.c
  7. 10 1
      modules/tm/tm.c

+ 5 - 0
modules/tm/config.c

@@ -33,6 +33,7 @@
 #include "../../parser/msg_parser.h" /* method types */
 #include "timer.h"
 #include "t_fwd.h"
+#include "t_cancel.h" /* cancel_b_flags_fixup() */
 #include "config.h"
 
 struct cfg_group_tm	default_tm_cfg = {
@@ -86,6 +87,7 @@ struct cfg_group_tm	default_tm_cfg = {
 			 * timeouts by default */
 	~METHOD_BYE,	/* tm_blst_methods_lookup -- look-up the blacklist
 			 * for every method except BYE by default */
+	0	/* cancel_b_method used for e2e and 6xx cancels*/
 };
 
 void	*tm_cfg = &default_tm_cfg;
@@ -166,5 +168,8 @@ cfg_def_t	tm_cfg_def[] = {
 	{"blst_methods_lookup",	CFG_VAR_INT,	0, 0, 0, 0,
 		"Bitmap of method types that are looked-up in the blacklist "
 		"before statefull forwarding"},
+	{"cancel_b_method",	CFG_VAR_INT,	0, 2, cancel_b_flags_fixup, 0,
+		"How to cancel branches on which no replies were received: 0 - fake"
+		" reply, 1 - retransmitting the request, 2 - send cancel"},
 	{0, 0, 0, 0, 0, 0}
 };

+ 1 - 0
modules/tm/config.h

@@ -126,6 +126,7 @@ struct cfg_group_tm {
 	int	tm_blst_503_max;
 	unsigned int	tm_blst_methods_add;
 	unsigned int	tm_blst_methods_lookup;
+	unsigned int	cancel_b_flags;
 };
 
 extern struct cfg_group_tm	default_tm_cfg;

+ 74 - 19
modules/tm/t_cancel.c

@@ -38,6 +38,7 @@
  *             (it can be disabled with reparse_invite=0) (Miklos)
  * 2007-06-04  cancel_branch() can operate in lockless mode (with a lockless
  *              should_cancel()) (andrei)
+ * 2008-03-07  cancel_branch() takes a new flag: F_CANCEL_B_FORCE_RETR (andrei)
  */
 
 #include <stdio.h> /* for FILE* in fifo_uac_cancel */
@@ -118,9 +119,13 @@ int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
  *                      to all branches that haven't received any response
  *                      (>=100). It assumes the REPLY_LOCK is not held
  *                      (if it is => deadlock)
- *                  F_CANCEL_B_FORCE - will send a cancel (and create the 
+ *                  F_CANCEL_B_FORCE_C - will send a cancel (and create the 
  *                       corresp. local cancel rb) even if no reply was 
  *                       received; F_CANCEL_B_FAKE_REPLY will be ignored.
+ *                  F_CANCEL_B_FORCE_RETR - don't stop retransmission if no 
+ *                       reply was received on the branch; incompatible
+ *                       with F_CANCEL_B_FAKE_REPLY, F_CANCEL_B_FORCE_C and
+ *                       F_CANCEL_B_KILL (all of them take precedence) a
  *                  default: stop only the retransmissions for the branch
  *                      and leave it to timeout if it doesn't receive any
  *                      response to the CANCEL
@@ -128,7 +133,7 @@ int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
  *          1 - branch still active  (fr_timer)
  *         -1 - error
  * WARNING:
- *          - F_CANCEL_KILL_B should be used only if the transaction is killed
+ *          - F_CANCEL_B_KILL should be used only if the transaction is killed
  *            explicitly afterwards (since it might kill all the timers
  *            the transaction won't be able to "kill" itself => if not
  *            explicitly "put_on_wait" it might live forever)
@@ -162,7 +167,7 @@ int cancel_branch( struct cell *t, int branch, int flags )
 		stop_rb_timers( irb );
 		ret=0;
 		if ((t->uac[branch].last_received < 100) &&
-				!(flags & F_CANCEL_B_FORCE)) {
+				!(flags & F_CANCEL_B_FORCE_C)) {
 			DBG("DEBUG: cancel_branch: no response ever received: "
 			    "giving up on cancel\n");
 			/* remove BUSY_BUFFER -- mark cancel buffer as not used */
@@ -178,25 +183,28 @@ int cancel_branch( struct cell *t, int branch, int flags )
 			return ret;
 		}
 	}else{
-		stop_rb_retr(irb); /* stop retransmissions */
-		if ((t->uac[branch].last_received < 100) &&
-				!(flags & F_CANCEL_B_FORCE)) {
-			/* no response received => don't send a cancel on this branch,
-			 *  just drop it */
-			/* remove BUSY_BUFFER -- mark cancel buffer as not used */
-			atomic_set_long((void*)&crb->buffer, 0);
-			if (flags & F_CANCEL_B_FAKE_REPLY){
-				stop_rb_timers( irb ); /* stop even the fr timer */
-				LOCK_REPLIES(t);
-				if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_bm) == 
-										RPS_ERROR){
-					return -1;
+		if (t->uac[branch].last_received < 100){
+			if (!(flags & F_CANCEL_B_FORCE_C)) {
+				/* no response received => don't send a cancel on this branch,
+				 *  just drop it */
+				if (!(flags & F_CANCEL_B_FORCE_RETR))
+					stop_rb_retr(irb); /* stop retransmissions */
+				/* remove BUSY_BUFFER -- mark cancel buffer as not used */
+				atomic_set_long((void*)&crb->buffer, 0);
+				if (flags & F_CANCEL_B_FAKE_REPLY){
+					stop_rb_timers( irb ); /* stop even the fr timer */
+					LOCK_REPLIES(t);
+					if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_bm) == 
+											RPS_ERROR){
+						return -1;
+					}
+					return 0; /* should be inactive after the 487 */
 				}
-				return 0; /* should be inactive after the 487 */
+				/* do nothing, just wait for the final timeout */
+				return 1;
 			}
-			/* do nothing, just wait for the final timeout */
-			return 1;
 		}
+		stop_rb_retr(irb); /* stop retransmissions */
 	}
 
 	if (cfg_get(tm, tm_cfg, reparse_invite)) {
@@ -305,3 +313,50 @@ void rpc_cancel(rpc_t* rpc, void* c)
 	}
 	rpc->add(c, "ds", j, "branches remaining (waiting for timeout)");
 }
+
+
+
+/* returns <0 on error */
+int cancel_b_flags_get(unsigned int* f, int m)
+{
+	int ret;
+	
+	ret=0;
+	switch(m){
+		case 1:
+			*f=F_CANCEL_B_FORCE_RETR;
+			break;
+		case 0:
+			*f=F_CANCEL_B_FAKE_REPLY;
+			break;
+		case 2:
+			*f=F_CANCEL_B_FORCE_C;
+			break;
+		default:
+			*f=F_CANCEL_B_FAKE_REPLY;
+			ret=-1;
+	}
+	return ret;
+}
+
+
+
+/* fixup function for the default cancel branch method/flags
+ * (called by the configuration framework) */
+int cancel_b_flags_fixup(void* handle, str* name, void** val)
+{
+	unsigned int m,f;
+	int ret;
+	
+	m=(unsigned int)(long)(*val);
+	ret=cancel_b_flags_get(&f, m);
+	if (ret<0)
+		ERR("cancel_b_flags_fixup: invalid value for %.*s; %d\n",
+				name->len, name->s, m);
+	*val=(void*)(long)f;
+	return ret;
+}
+
+
+
+

+ 9 - 2
modules/tm/t_cancel.h

@@ -64,8 +64,13 @@
 								 haven't received any response (>=100). It
 								 assumes the REPLY_LOCK is not held (if it is
 								 => deadlock) */
-#define F_CANCEL_B_FORCE 4 /* will send a cancel even if no reply was received;
-							  F_CANCEL_B_FAKE_REPLY will be ignored */
+#define F_CANCEL_B_FORCE_C 4 /* will send a cancel even if no reply was 
+								received; F_CANCEL_B_FAKE_REPLY will be 
+								ignored */
+#define F_CANCEL_B_FORCE_RETR 8  /* will not stop request retr. on a branch
+									if no provisional response was received;
+									F_CANCEL_B_FORCE_C, F_CANCEL_B_FAKE_REPLY
+									and F_CANCE_B_KILL take precedence */
 
 
 void which_cancel( struct cell *t, branch_bm_t *cancel_bm );
@@ -106,5 +111,7 @@ inline short static should_cancel_branch( struct cell *t, int b, int noreply )
 
 const char* rpc_cancel_doc[2];
 void rpc_cancel(rpc_t* rpc, void* c);
+int cancel_b_flags_fixup(void* handle, str* name, void** val);
+int cancel_b_flags_get(unsigned int* f, int m);
 
 #endif

+ 11 - 6
modules/tm/t_fwd.c

@@ -552,7 +552,7 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 			 * called with the cancel as the "current" transaction so
 			 * at most t_cancel REPLY_LOCK is held in this process =>
 			 * no deadlock possibility */
-			ret=cancel_branch(t_invite, i, F_CANCEL_B_FAKE_REPLY);
+			ret=cancel_branch(t_invite, i, cfg_get(tm,tm_cfg, cancel_b_flags));
 			if (ret<0) cancel_bm &= ~(1<<i);
 			if (ret<lowest_error) lowest_error=ret;
 		}
@@ -597,14 +597,19 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 			} else {
 				/* No provisional response received, stop
 				 * retransmission timers */
-				stop_rb_retr(&t_invite->uac[i].request);
+				if (!(cfg_get(tm, tm_cfg, cancel_b_flags) & 
+							F_CANCEL_B_FORCE_RETR))
+					stop_rb_retr(&t_invite->uac[i].request);
 				/* no need to stop fr, it will be stoped by relay_reply
 				 * put_on_wait -- andrei */
 				/* Generate faked reply */
-				LOCK_REPLIES(t_invite);
-				if (relay_reply(t_invite, FAKED_REPLY, i, 487, &tmp_bm) == 
-						RPS_ERROR) {
-					lowest_error = -1;
+				if (cfg_get(tm, tm_cfg, cancel_b_flags) &
+						F_CANCEL_B_FAKE_REPLY){
+					LOCK_REPLIES(t_invite);
+					if (relay_reply(t_invite, FAKED_REPLY, i, 487, &tmp_bm) == 
+							RPS_ERROR) {
+						lowest_error = -1;
+					}
 				}
 			}
 		}

+ 1 - 1
modules/tm/t_reply.c

@@ -1748,7 +1748,7 @@ int reply_received( struct sip_msg  *p_msg )
 				 * if BUSY or set just exit, a cancel will be (or was) sent 
 				 * shortly on this branch */
 				DBG("tm: reply_received: branch CANCEL created\n");
-				cancel_branch(t, branch, F_CANCEL_B_FORCE);
+				cancel_branch(t, branch, F_CANCEL_B_FORCE_C);
 			}
 			goto done; /* nothing to do */
 		}

+ 10 - 1
modules/tm/tm.c

@@ -380,6 +380,7 @@ static param_export_t params[]={
 	{"blst_503_max_timeout",PARAM_INT, &default_tm_cfg.tm_blst_503_max       },
 	{"blst_methods_add",    PARAM_INT, &default_tm_cfg.tm_blst_methods_add   },
 	{"blst_methods_lookup", PARAM_INT, &default_tm_cfg.tm_blst_methods_lookup},
+	{"cancel_b_method",     PARAM_INT, &default_tm_cfg.cancel_b_flags},
 	{0,0,0}
 };
 
@@ -596,12 +597,20 @@ static int mod_init(void)
 		return -1;
 	}
 
-	/* the defult timer values must be fixed-up before
+	/* the default timer values must be fixed-up before
 	 * declaring the configuration (Miklos) */
 	if (tm_init_timers()==-1) {
 		LOG(L_ERR, "ERROR: mod_init: timer init failed\n");
 		return -1;
 	}
+	
+	/* the cancel branch flags must be fixed before declaring the 
+	 * configuration */
+	if (cancel_b_flags_get(&default_tm_cfg.cancel_b_flags, 
+							default_tm_cfg.cancel_b_flags)<0){
+		LOG(L_ERR, "ERROR: mod_init: bad cancel branch method\n");
+		return -1;
+	}
 
 	/* declare the configuration */
 	if (cfg_declare("tm", tm_cfg_def, &default_tm_cfg, cfg_size(tm),