Browse code

- 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 authored on 08/03/2008 00:20:36
Showing 7 changed files
... ...
@@ -33,6 +33,7 @@
33 33
 #include "../../parser/msg_parser.h" /* method types */
34 34
 #include "timer.h"
35 35
 #include "t_fwd.h"
36
+#include "t_cancel.h" /* cancel_b_flags_fixup() */
36 37
 #include "config.h"
37 38
 
38 39
 struct cfg_group_tm	default_tm_cfg = {
... ...
@@ -86,6 +87,7 @@ struct cfg_group_tm	default_tm_cfg = {
86 86
 			 * timeouts by default */
87 87
 	~METHOD_BYE,	/* tm_blst_methods_lookup -- look-up the blacklist
88 88
 			 * for every method except BYE by default */
89
+	0	/* cancel_b_method used for e2e and 6xx cancels*/
89 90
 };
90 91
 
91 92
 void	*tm_cfg = &default_tm_cfg;
... ...
@@ -166,5 +168,8 @@ cfg_def_t	tm_cfg_def[] = {
166 166
 	{"blst_methods_lookup",	CFG_VAR_INT,	0, 0, 0, 0,
167 167
 		"Bitmap of method types that are looked-up in the blacklist "
168 168
 		"before statefull forwarding"},
169
+	{"cancel_b_method",	CFG_VAR_INT,	0, 2, cancel_b_flags_fixup, 0,
170
+		"How to cancel branches on which no replies were received: 0 - fake"
171
+		" reply, 1 - retransmitting the request, 2 - send cancel"},
169 172
 	{0, 0, 0, 0, 0, 0}
170 173
 };
... ...
@@ -126,6 +126,7 @@ struct cfg_group_tm {
126 126
 	int	tm_blst_503_max;
127 127
 	unsigned int	tm_blst_methods_add;
128 128
 	unsigned int	tm_blst_methods_lookup;
129
+	unsigned int	cancel_b_flags;
129 130
 };
130 131
 
131 132
 extern struct cfg_group_tm	default_tm_cfg;
... ...
@@ -38,6 +38,7 @@
38 38
  *             (it can be disabled with reparse_invite=0) (Miklos)
39 39
  * 2007-06-04  cancel_branch() can operate in lockless mode (with a lockless
40 40
  *              should_cancel()) (andrei)
41
+ * 2008-03-07  cancel_branch() takes a new flag: F_CANCEL_B_FORCE_RETR (andrei)
41 42
  */
42 43
 
43 44
 #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)
118 118
  *                      to all branches that haven't received any response
119 119
  *                      (>=100). It assumes the REPLY_LOCK is not held
120 120
  *                      (if it is => deadlock)
121
- *                  F_CANCEL_B_FORCE - will send a cancel (and create the 
121
+ *                  F_CANCEL_B_FORCE_C - will send a cancel (and create the 
122 122
  *                       corresp. local cancel rb) even if no reply was 
123 123
  *                       received; F_CANCEL_B_FAKE_REPLY will be ignored.
124
+ *                  F_CANCEL_B_FORCE_RETR - don't stop retransmission if no 
125
+ *                       reply was received on the branch; incompatible
126
+ *                       with F_CANCEL_B_FAKE_REPLY, F_CANCEL_B_FORCE_C and
127
+ *                       F_CANCEL_B_KILL (all of them take precedence) a
124 128
  *                  default: stop only the retransmissions for the branch
125 129
  *                      and leave it to timeout if it doesn't receive any
126 130
  *                      response to the CANCEL
... ...
@@ -128,7 +133,7 @@ int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
128 128
  *          1 - branch still active  (fr_timer)
129 129
  *         -1 - error
130 130
  * WARNING:
131
- *          - F_CANCEL_KILL_B should be used only if the transaction is killed
131
+ *          - F_CANCEL_B_KILL should be used only if the transaction is killed
132 132
  *            explicitly afterwards (since it might kill all the timers
133 133
  *            the transaction won't be able to "kill" itself => if not
134 134
  *            explicitly "put_on_wait" it might live forever)
... ...
@@ -162,7 +167,7 @@ int cancel_branch( struct cell *t, int branch, int flags )
162 162
 		stop_rb_timers( irb );
163 163
 		ret=0;
164 164
 		if ((t->uac[branch].last_received < 100) &&
165
-				!(flags & F_CANCEL_B_FORCE)) {
165
+				!(flags & F_CANCEL_B_FORCE_C)) {
166 166
 			DBG("DEBUG: cancel_branch: no response ever received: "
167 167
 			    "giving up on cancel\n");
168 168
 			/* remove BUSY_BUFFER -- mark cancel buffer as not used */
... ...
@@ -178,25 +183,28 @@ int cancel_branch( struct cell *t, int branch, int flags )
178 178
 			return ret;
179 179
 		}
180 180
 	}else{
181
-		stop_rb_retr(irb); /* stop retransmissions */
182
-		if ((t->uac[branch].last_received < 100) &&
183
-				!(flags & F_CANCEL_B_FORCE)) {
184
-			/* no response received => don't send a cancel on this branch,
185
-			 *  just drop it */
186
-			/* remove BUSY_BUFFER -- mark cancel buffer as not used */
187
-			atomic_set_long((void*)&crb->buffer, 0);
188
-			if (flags & F_CANCEL_B_FAKE_REPLY){
189
-				stop_rb_timers( irb ); /* stop even the fr timer */
190
-				LOCK_REPLIES(t);
191
-				if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_bm) == 
192
-										RPS_ERROR){
193
-					return -1;
181
+		if (t->uac[branch].last_received < 100){
182
+			if (!(flags & F_CANCEL_B_FORCE_C)) {
183
+				/* no response received => don't send a cancel on this branch,
184
+				 *  just drop it */
185
+				if (!(flags & F_CANCEL_B_FORCE_RETR))
186
+					stop_rb_retr(irb); /* stop retransmissions */
187
+				/* remove BUSY_BUFFER -- mark cancel buffer as not used */
188
+				atomic_set_long((void*)&crb->buffer, 0);
189
+				if (flags & F_CANCEL_B_FAKE_REPLY){
190
+					stop_rb_timers( irb ); /* stop even the fr timer */
191
+					LOCK_REPLIES(t);
192
+					if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_bm) == 
193
+											RPS_ERROR){
194
+						return -1;
195
+					}
196
+					return 0; /* should be inactive after the 487 */
194 197
 				}
195
-				return 0; /* should be inactive after the 487 */
198
+				/* do nothing, just wait for the final timeout */
199
+				return 1;
196 200
 			}
197
-			/* do nothing, just wait for the final timeout */
198
-			return 1;
199 201
 		}
202
+		stop_rb_retr(irb); /* stop retransmissions */
200 203
 	}
201 204
 
202 205
 	if (cfg_get(tm, tm_cfg, reparse_invite)) {
... ...
@@ -305,3 +313,50 @@ void rpc_cancel(rpc_t* rpc, void* c)
305 305
 	}
306 306
 	rpc->add(c, "ds", j, "branches remaining (waiting for timeout)");
307 307
 }
308
+
309
+
310
+
311
+/* returns <0 on error */
312
+int cancel_b_flags_get(unsigned int* f, int m)
313
+{
314
+	int ret;
315
+	
316
+	ret=0;
317
+	switch(m){
318
+		case 1:
319
+			*f=F_CANCEL_B_FORCE_RETR;
320
+			break;
321
+		case 0:
322
+			*f=F_CANCEL_B_FAKE_REPLY;
323
+			break;
324
+		case 2:
325
+			*f=F_CANCEL_B_FORCE_C;
326
+			break;
327
+		default:
328
+			*f=F_CANCEL_B_FAKE_REPLY;
329
+			ret=-1;
330
+	}
331
+	return ret;
332
+}
333
+
334
+
335
+
336
+/* fixup function for the default cancel branch method/flags
337
+ * (called by the configuration framework) */
338
+int cancel_b_flags_fixup(void* handle, str* name, void** val)
339
+{
340
+	unsigned int m,f;
341
+	int ret;
342
+	
343
+	m=(unsigned int)(long)(*val);
344
+	ret=cancel_b_flags_get(&f, m);
345
+	if (ret<0)
346
+		ERR("cancel_b_flags_fixup: invalid value for %.*s; %d\n",
347
+				name->len, name->s, m);
348
+	*val=(void*)(long)f;
349
+	return ret;
350
+}
351
+
352
+
353
+
354
+
... ...
@@ -64,8 +64,13 @@
64 64
 								 haven't received any response (>=100). It
65 65
 								 assumes the REPLY_LOCK is not held (if it is
66 66
 								 => deadlock) */
67
-#define F_CANCEL_B_FORCE 4 /* will send a cancel even if no reply was received;
68
-							  F_CANCEL_B_FAKE_REPLY will be ignored */
67
+#define F_CANCEL_B_FORCE_C 4 /* will send a cancel even if no reply was 
68
+								received; F_CANCEL_B_FAKE_REPLY will be 
69
+								ignored */
70
+#define F_CANCEL_B_FORCE_RETR 8  /* will not stop request retr. on a branch
71
+									if no provisional response was received;
72
+									F_CANCEL_B_FORCE_C, F_CANCEL_B_FAKE_REPLY
73
+									and F_CANCE_B_KILL take precedence */
69 74
 
70 75
 
71 76
 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 )
106 106
 
107 107
 const char* rpc_cancel_doc[2];
108 108
 void rpc_cancel(rpc_t* rpc, void* c);
109
+int cancel_b_flags_fixup(void* handle, str* name, void** val);
110
+int cancel_b_flags_get(unsigned int* f, int m);
109 111
 
110 112
 #endif
... ...
@@ -552,7 +552,7 @@ void e2e_cancel( struct sip_msg *cancel_msg,
552 552
 			 * called with the cancel as the "current" transaction so
553 553
 			 * at most t_cancel REPLY_LOCK is held in this process =>
554 554
 			 * no deadlock possibility */
555
-			ret=cancel_branch(t_invite, i, F_CANCEL_B_FAKE_REPLY);
555
+			ret=cancel_branch(t_invite, i, cfg_get(tm,tm_cfg, cancel_b_flags));
556 556
 			if (ret<0) cancel_bm &= ~(1<<i);
557 557
 			if (ret<lowest_error) lowest_error=ret;
558 558
 		}
... ...
@@ -597,14 +597,19 @@ void e2e_cancel( struct sip_msg *cancel_msg,
597 597
 			} else {
598 598
 				/* No provisional response received, stop
599 599
 				 * retransmission timers */
600
-				stop_rb_retr(&t_invite->uac[i].request);
600
+				if (!(cfg_get(tm, tm_cfg, cancel_b_flags) & 
601
+							F_CANCEL_B_FORCE_RETR))
602
+					stop_rb_retr(&t_invite->uac[i].request);
601 603
 				/* no need to stop fr, it will be stoped by relay_reply
602 604
 				 * put_on_wait -- andrei */
603 605
 				/* Generate faked reply */
604
-				LOCK_REPLIES(t_invite);
605
-				if (relay_reply(t_invite, FAKED_REPLY, i, 487, &tmp_bm) == 
606
-						RPS_ERROR) {
607
-					lowest_error = -1;
606
+				if (cfg_get(tm, tm_cfg, cancel_b_flags) &
607
+						F_CANCEL_B_FAKE_REPLY){
608
+					LOCK_REPLIES(t_invite);
609
+					if (relay_reply(t_invite, FAKED_REPLY, i, 487, &tmp_bm) == 
610
+							RPS_ERROR) {
611
+						lowest_error = -1;
612
+					}
608 613
 				}
609 614
 			}
610 615
 		}
... ...
@@ -1748,7 +1748,7 @@ int reply_received( struct sip_msg  *p_msg )
1748 1748
 				 * if BUSY or set just exit, a cancel will be (or was) sent 
1749 1749
 				 * shortly on this branch */
1750 1750
 				DBG("tm: reply_received: branch CANCEL created\n");
1751
-				cancel_branch(t, branch, F_CANCEL_B_FORCE);
1751
+				cancel_branch(t, branch, F_CANCEL_B_FORCE_C);
1752 1752
 			}
1753 1753
 			goto done; /* nothing to do */
1754 1754
 		}
... ...
@@ -380,6 +380,7 @@ static param_export_t params[]={
380 380
 	{"blst_503_max_timeout",PARAM_INT, &default_tm_cfg.tm_blst_503_max       },
381 381
 	{"blst_methods_add",    PARAM_INT, &default_tm_cfg.tm_blst_methods_add   },
382 382
 	{"blst_methods_lookup", PARAM_INT, &default_tm_cfg.tm_blst_methods_lookup},
383
+	{"cancel_b_method",     PARAM_INT, &default_tm_cfg.cancel_b_flags},
383 384
 	{0,0,0}
384 385
 };
385 386
 
... ...
@@ -596,12 +597,20 @@ static int mod_init(void)
596 596
 		return -1;
597 597
 	}
598 598
 
599
-	/* the defult timer values must be fixed-up before
599
+	/* the default timer values must be fixed-up before
600 600
 	 * declaring the configuration (Miklos) */
601 601
 	if (tm_init_timers()==-1) {
602 602
 		LOG(L_ERR, "ERROR: mod_init: timer init failed\n");
603 603
 		return -1;
604 604
 	}
605
+	
606
+	/* the cancel branch flags must be fixed before declaring the 
607
+	 * configuration */
608
+	if (cancel_b_flags_get(&default_tm_cfg.cancel_b_flags, 
609
+							default_tm_cfg.cancel_b_flags)<0){
610
+		LOG(L_ERR, "ERROR: mod_init: bad cancel branch method\n");
611
+		return -1;
612
+	}
605 613
 
606 614
 	/* declare the configuration */
607 615
 	if (cfg_declare("tm", tm_cfg_def, &default_tm_cfg, cfg_size(tm),