Browse code

- reverted to the old behaviour for the transaction timeout reply: now 408 is returned always; before 480 was returned on invite timeout after a provisional reply. - added new script functions: t_branch_timeout() and t_branch_replied(), which can be used to distinguish between a 408 received from the network (if (!t_branch_timeout() && t_check_status("408")) ... ), a local transaction timeout w/o any reply being received (if (t_branch_timeout() && ! t_branch_replied()) ...) and a local timeout after some provsional reply ( if (t_branch_timeout() && t_branch_replied()) ...) - even more script functions: - t_any_timeout() -- true if any of the transaction branches did timeout - t_any_replied() -- true if at least one branch received a reply (when used from an on_reply route it will ignore the "current" reply) - t_is_canceled() -- true if the current transaction has been canceled (for more info see NEWS or tm docs)

Andrei Pelinescu-Onciul authored on 28/09/2006 21:10:43
Showing 8 changed files
... ...
@@ -67,7 +67,7 @@ MAIN_NAME=ser
67 67
 VERSION = 0
68 68
 PATCHLEVEL = 10
69 69
 SUBLEVEL =   99
70
-EXTRAVERSION = -dev45-dns_cache
70
+EXTRAVERSION = -dev46-dns_cache
71 71
 
72 72
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
73 73
 			$(SUBLEVEL) )
... ...
@@ -24,10 +24,12 @@ modules:
24 24
                 hashing after an uri (to, from or request uri)
25 25
               - improved uri hashing (password is ignored, port is used only
26 26
                 if != 5060 or 5061)
27
- - tm        - dns failover and dst blacklist support
27
+ - tm        - special functions for checking for timeout, if a reply was
28
+               received or if the current transaction was canceled
29
+             - dns failover and dst blacklist support
28 30
              - migrated to the new timers (tm timers completely rewritten)
29 31
              - improved speed and less memory usage
30
-             - much more precise reptransmissions timing
32
+             - much more precise retransmissions timing
31 33
              - params: - retr_timer1p1, retr_timer1p2, retr_timer1p3 removed
32 34
                          and replaced by retr_timer1 and retr_timer2
33 35
                        - all timer values are now expressed in milliseconds
... ...
@@ -39,6 +41,22 @@ modules:
39 39
                        - unix_tx_timeout expressed now in milliseconds; default
40 40
                          value changed to 500 ms
41 41
              - functions:
42
+                       - t_branch_timeout() -- returns true if the failure
43
+                         route is executed for a branch that did timeout
44
+                         (failure_route only).
45
+                       - t_branch_replied() -- returns true if the failure 
46
+                         route is executed for a branch that did receive at
47
+                         least one reply (failure_route only).. It can be used
48
+                         together with t_branch_timeout() to distinguish 
49
+                         between a remote side that doesn't respond (some 
50
+                         provisional reply received) and one that is completely
51
+                          dead.
52
+                       - t_any_timeout() -- returns true if any of the current
53
+                         transaction branches did timeout.
54
+                       - t_any_replied() -- returns true if at least one branch
55
+                          of the current transaction received one reply.
56
+                       - t_is_canceled() -- returns true if the current 
57
+                         transaction  has been canceled.
42 58
                        - new t_set_fr(timeout_fr_inv, timeout_fr) -- allows
43 59
                          changing the transaction timer from script, even if
44 60
                          the transaction was already created (see tm docs for
... ...
@@ -183,6 +201,13 @@ tools:
183 183
                  , interactive mode, command line completion (if compiled with 
184 184
                  libreadline) a.s.o.
185 185
 
186
+WARNING: - older 0.10.99-dev version (< 0.10.99-dev46) returned a 480 reply
187
+ on invite transaction timeout, if a provisional reply was received. Newer
188
+ versions reverted to returning 408 on all timeouts (one can use 
189
+  t_branch_timeout() and t_branch_replied() to distinguish between the two
190
+  timeout types)
191
+
192
+
186 193
 
187 194
 0.9.4 fixes/improvements (0.9.4 is a bug fix release for 0.9.3)
188 195
  
... ...
@@ -412,4 +412,120 @@ branch_route[1] {
412 412
 	</example>
413 413
 	</section>
414 414
 
415
+	<section id="t_branch_timeout">
416
+	<title>
417
+	    <function>t_branch_timeout()</function>
418
+	</title>
419
+	<para>
420
+		Returns true if the failure route is executed for a branch that did
421
+		timeout. It can be used only from the 
422
+		<emphasis>failure_route</emphasis>.
423
+	</para>
424
+	<example>
425
+	    <title><function>t_branch_timeout</function> usage</title>
426
+	    <programlisting>
427
+...
428
+failure_route[0]{ 
429
+	if (t_branch_timeout()){
430
+		log("timeout\n");
431
+		# ... 
432
+	}
433
+} 
434
+	    </programlisting>
435
+	</example>
436
+	</section>
437
+
438
+<section id="t_branch_replied">
439
+	<title>
440
+	    <function>t_branch_replied()</function>
441
+	</title>
442
+	<para>
443
+		Returns true if the failure route is executed for a branch that did
444
+		receive at least one reply. It can be used only from the 
445
+		<emphasis>failure_route</emphasis>.
446
+	</para>
447
+	<example>
448
+	    <title><function>t_branch_replied</function> usage</title>
449
+	    <programlisting>
450
+...
451
+failure_route[0]{ 
452
+	if (t_branch_timeout()){
453
+		if (t_branch_replied())
454
+			log("timeout after receiving a reply (no answer?)\n");
455
+		else
456
+			log("timeout, remote side seems to be down\n");
457
+		# ... 
458
+	}
459
+} 
460
+	    </programlisting>
461
+	</example>
462
+	</section>
463
+
464
+<section id="t_any_timeout">
465
+	<title>
466
+	    <function>t_any_timeout()</function>
467
+	</title>
468
+	<para>
469
+		Returns true if at least one of the current transactions branches
470
+		did timeout.
471
+	</para>
472
+	<example>
473
+	    <title><function>t_any_timeout</function> usage</title>
474
+	    <programlisting>
475
+...
476
+failure_route[0]{ 
477
+	if (!t_branch_timeout()){
478
+		if (t_any_timeout()){
479
+			log("one branch did timeout\n");
480
+			sl_send_reply("408", "Timeout");
481
+		}
482
+	}
483
+} 
484
+	    </programlisting>
485
+	</example>
486
+	</section>
487
+
488
+<section id="t_any_replied">
489
+	<title>
490
+	    <function>t_any_replied()</function>
491
+	</title>
492
+	<para>
493
+		Returns true if at least one of the current transactions branches
494
+		did receive some reply.
495
+	</para>
496
+	<example>
497
+	    <title><function>t_any_replied</function> usage</title>
498
+	    <programlisting>
499
+...
500
+onreply_route[0]{ 
501
+	if (!t_any_replied()){
502
+		log("first reply received\n");
503
+		# ...
504
+	}
505
+} 
506
+	    </programlisting>
507
+	</example>
508
+	</section>
509
+
510
+<section id="t_is_canceled">
511
+	<title>
512
+	    <function>t_is_canceled()</function>
513
+	</title>
514
+	<para>
515
+		Returns true if the current transaction was canceled.
516
+	</para>
517
+	<example>
518
+	    <title><function>t_is_canceled</function> usage</title>
519
+	    <programlisting>
520
+...
521
+failure_route[0]{ 
522
+	if (t_is_canceled()){
523
+		log("transaction canceled\n");
524
+		# ...
525
+	}
526
+} 
527
+	    </programlisting>
528
+	</example>
529
+	</section>
530
+
415 531
 </section>
... ...
@@ -107,6 +107,8 @@ enum kill_reason { REQ_FWDED=1, REQ_RPLD=2, REQ_RLSD=4, REQ_EXIST=8 };
107 107
 #define F_RB_T2				0x02
108 108
 #define F_RB_RETR_DISABLED	0x04 /* retransmission disabled */
109 109
 #define F_RB_FR_INV	0x08 /* timer switched to FR_INV */
110
+#define F_RB_TIMEOUT	0x10 /* timeout */
111
+#define F_RB_REPLIED	0x20 /* reply received */
110 112
 
111 113
 
112 114
 typedef struct retr_buf
... ...
@@ -565,7 +565,7 @@ static inline void faked_env( struct cell *t,struct sip_msg *msg)
565 565
 
566 566
 
567 567
 static inline int fake_req(struct sip_msg *faked_req,
568
-				struct sip_msg *shmem_msg)
568
+							struct sip_msg *shmem_msg, int extra_flags)
569 569
 {
570 570
 	/* on_negative_reply faked msg now copied from shmem msg (as opposed
571 571
 	 * to zero-ing) -- more "read-only" actions (exec in particular) will
... ...
@@ -580,7 +580,8 @@ static inline int fake_req(struct sip_msg *faked_req,
580 580
 	/* msg->parsed_uri_ok must be reset since msg_parsed_uri is
581 581
 	 * not cloned (and cannot be cloned) */
582 582
 	faked_req->parsed_uri_ok = 0;
583
-
583
+	
584
+	faked_req->msg_flags|=extra_flags; /* set the extra tm flags */
584 585
 	/* new_uri can change -- make a private copy */
585 586
 	if (shmem_msg->new_uri.s!=0 && shmem_msg->new_uri.len!=0) {
586 587
 		faked_req->new_uri.s=pkg_malloc(shmem_msg->new_uri.len+1);
... ...
@@ -648,7 +649,7 @@ void inline static free_faked_req(struct sip_msg *faked_req, struct cell *t)
648 648
 
649 649
 /* return 1 if a failure_route processes */
650 650
 static inline int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
651
-																	int code)
651
+											int code, int extra_flags)
652 652
 {
653 653
 	static struct sip_msg faked_req;
654 654
 	struct sip_msg *shmem_msg = t->uas.request;
... ...
@@ -670,7 +671,7 @@ static inline int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
670 670
 		return 1;
671 671
 	}
672 672
 
673
-	if (!fake_req(&faked_req, shmem_msg)) {
673
+	if (!fake_req(&faked_req, shmem_msg, extra_flags)) {
674 674
 		LOG(L_ERR, "ERROR: run_failure_handlers: fake_req failed\n");
675 675
 		return 0;
676 676
 	}
... ...
@@ -757,6 +758,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
757 757
 	int picked_code;
758 758
 	int new_branch;
759 759
 	int inv_through;
760
+	int extra_flags;
760 761
 
761 762
 	/* note: this code never lets replies to CANCEL go through;
762 763
 	   we generate always a local 200 for CANCEL; 200s are
... ...
@@ -834,8 +836,13 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
834 834
 		/* run ON_FAILURE handlers ( route and callbacks) */
835 835
 		if ( has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
836 836
 		|| Trans->on_negative ) {
837
+			extra_flags=
838
+				((Trans->uac[picked_branch].request.flags & F_RB_TIMEOUT)?
839
+							FL_TIMEOUT:0) | 
840
+				((Trans->uac[picked_branch].request.flags & F_RB_REPLIED)?
841
+						 	FL_REPLIED:0);
837 842
 			run_failure_handlers( Trans, Trans->uac[picked_branch].reply,
838
-									picked_code);
843
+									picked_code, extra_flags);
839 844
 		}
840 845
 
841 846
 		/* now reset it; after the failure logic, the reply may
... ...
@@ -1437,8 +1444,8 @@ int reply_received( struct sip_msg  *p_msg )
1437 1437
 			 * retransmissions comes before retransmission timer is set.*/
1438 1438
 			/* set_final_timer(t) */
1439 1439
 		}
1440
-
1441 1440
 	}
1441
+	uac->request.flags|=F_RB_REPLIED;
1442 1442
 
1443 1443
 	if (reply_status==RPS_ERROR)
1444 1444
 		goto done;
... ...
@@ -103,6 +103,10 @@
103 103
  *              it from the timer handle; timer_allow_del()  (andrei)
104 104
  *  2006-08-11  final_response_handler dns failover support for timeout-ed
105 105
  *              invites (andrei)
106
+ *  2006-09-28  removed the 480 on fr_inv_timeout reply: on timeout always 
107
+ *               return a 408
108
+ *              set the corresponding "faked" failure route sip_msg->msg_flags 
109
+ *               on timeout or if the branch received a reply (andrei)
106 110
  */
107 111
 
108 112
 #include "defs.h"
... ...
@@ -321,7 +325,6 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
321 321
 											struct cell* t)
322 322
 {
323 323
 	int silent;
324
-	int reply_code;
325 324
 #ifdef USE_DNS_FAILOVER
326 325
 	/*int i; 
327 326
 	int added_branches;
... ...
@@ -395,12 +398,9 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
395 395
 #ifdef EXTRA_DEBUG
396 396
 	DBG("DEBUG: final_response_handler:stop retr. and send CANCEL (%p)\n", t);
397 397
 #endif
398
-	if (is_invite(t) && 
399
-	    r_buf->branch < MAX_BRANCHES && /* r_buf->branch is always >=0 */
400
-	    t->uac[r_buf->branch].last_received > 0) {
401
-		reply_code = 480; /* Temporarily Unavailable */
402
-	} else {
403
-		reply_code = 408; /* Request Timeout */
398
+	if ((r_buf->branch < MAX_BRANCHES) && /* r_buf->branch is always >=0 */
399
+			(t->uac[r_buf->branch].last_received==0)){
400
+		/* no reply received */
404 401
 #ifdef USE_DST_BLACKLIST
405 402
 		if (use_dst_blacklist)
406 403
 			dst_blacklist_add( BLST_ERR_TIMEOUT, &r_buf->dst);
... ...
@@ -419,25 +419,10 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
419 419
 				prev_branch=branch_ret;
420 420
 				branch_ret=t_send_branch(t, branch_ret, t->uas.request , 0, 0);
421 421
 			}
422
-#if 0
423
-			if (branch_ret>=0){
424
-				added_branches=1<<branch_ret;
425
-				/* success */
426
-				for (i=branch_ret; i<t->nr_of_outgoings; i++) {
427
-					if (added_branches & (1<<i)) {
428
-						branch_ret=t_send_branch(t, i, t->uas.request , 0, 0);
429
-						if ((branch_ret>=0) && (branch_ret!=i)){
430
-							/* no send, but new branch */
431
-							added_branches |= 1<<branch_ret;
432
-						}
433
-					}
434
-				}
435
-			}
436
-#endif
437 422
 		}
438 423
 #endif
439 424
 	}
440
-	fake_reply(t, r_buf->branch, reply_code );
425
+	fake_reply(t, r_buf->branch, 408);
441 426
 }
442 427
 
443 428
 
... ...
@@ -477,6 +462,7 @@ ticks_t retr_buf_handler(ticks_t ticks, struct timer_ln* tl, void *p)
477 477
 							 (both timers disabled)
478 478
 							  a little race risk, but
479 479
 							  nothing bad would happen */
480
+		rbuf->flags|=F_RB_TIMEOUT;
480 481
 		timer_allow_del(); /* [optional] allow timer_dels, since we're done
481 482
 							  and there is no race risk */
482 483
 		final_response_handler(rbuf, t);
... ...
@@ -77,6 +77,8 @@
77 77
  *              when fixing param #2
78 78
  *  2005-12-09  added t_set_fr() (andrei)
79 79
  *  2006-02-07  named routes support (andrei)
80
+ *  2006-09-28  added t_branch_replied, t_branch_timeout, t_any_replied, 
81
+ *               t_any_timeout, t_is_canceled (andrei)
80 82
  */
81 83
 
82 84
 
... ...
@@ -181,6 +183,11 @@ inline static int w_t_on_reply(struct sip_msg* msg, char *go_to, char *foo );
181 181
 inline static int t_check_status(struct sip_msg* msg, char *regexp, char *foo);
182 182
 static int t_set_fr_inv(struct sip_msg* msg, char* fr_inv, char* foo);
183 183
 static int t_set_fr_all(struct sip_msg* msg, char* fr_inv, char* fr);
184
+static int t_branch_timeout(struct sip_msg* msg, char*, char*);
185
+static int t_branch_replied(struct sip_msg* msg, char*, char*);
186
+static int t_any_timeout(struct sip_msg* msg, char*, char*);
187
+static int t_any_replied(struct sip_msg* msg, char*, char*);
188
+static int t_is_canceled(struct sip_msg* msg, char*, char*);
184 189
 
185 190
 
186 191
 static char *fr_timer_param = FR_TIMER_AVP;
... ...
@@ -265,6 +272,14 @@ static cmd_export_t cmds[]={
265 265
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
266 266
 	{"t_set_fr",          t_set_fr_all,             2, fixup_var_int_12,
267 267
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
268
+	{"t_branch_timeout",  t_branch_timeout,         0, 0,  FAILURE_ROUTE},
269
+	{"t_branch_replied",  t_branch_replied,         0, 0,  FAILURE_ROUTE},
270
+	{"t_any_timeout",     t_any_timeout,            0, 0, 
271
+			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
272
+	{"t_any_replied",     t_any_replied,            0, 0, 
273
+			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
274
+	{"t_is_canceled",     t_is_canceled,            0, 0,
275
+			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
268 276
 
269 277
 	/* not applicable from the script */
270 278
 	{"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,   0, 0},
... ...
@@ -1108,6 +1123,94 @@ static int t_set_fr_inv(struct sip_msg* msg, char* fr_inv, char* foo)
1108 1108
 }
1109 1109
 
1110 1110
 
1111
+
1112
+/* script function, FAILURE_ROUTE only, returns true if the 
1113
+ * choosed "failure" branch failed because of a timeout, 
1114
+ * -1 otherwise */
1115
+int t_branch_timeout(struct sip_msg* msg, char* foo, char* bar)
1116
+{
1117
+	return (msg->msg_flags & FL_TIMEOUT)?1:-1;
1118
+}
1119
+
1120
+
1121
+
1122
+/* script function, FAILURE_ROUTE only, returns true if the 
1123
+ * choosed "failure" branch ever received a reply, -1 otherwise */
1124
+int t_branch_replied(struct sip_msg* msg, char* foo, char* bar)
1125
+{
1126
+	return (msg->msg_flags & FL_REPLIED)?1:-1;
1127
+}
1128
+
1129
+
1130
+
1131
+/* script function, returns: 1 if the transaction was canceled, -1 if not */
1132
+int t_is_canceled(struct sip_msg* msg, char* foo, char* bar)
1133
+{
1134
+	struct cell *t;
1135
+	int ret;
1136
+	
1137
+	
1138
+	if (t_check( msg , 0 )==-1) return -1;
1139
+	t=get_t();
1140
+	if ((t==0) || (t==T_UNDEFINED)){
1141
+		LOG(L_ERR, "ERROR: t_is_canceled: cannot check a message "
1142
+			"for which no T-state has been established\n");
1143
+		ret=-1;
1144
+	}else{
1145
+		ret=(t->flags & T_CANCELED)?1:-1;
1146
+	}
1147
+	return ret;
1148
+}
1149
+
1150
+
1151
+
1152
+/* script function, returns: 1 if any of the branches did timeout, -1 if not */
1153
+int t_any_timeout(struct sip_msg* msg, char* foo, char* bar)
1154
+{
1155
+	struct cell *t;
1156
+	int r;
1157
+	
1158
+	if (t_check( msg , 0 )==-1) return -1;
1159
+	t=get_t();
1160
+	if ((t==0) || (t==T_UNDEFINED)){
1161
+		LOG(L_ERR, "ERROR: t_any_timeout: cannot check a message "
1162
+			"for which no T-state has been established\n");
1163
+		return -1;
1164
+	}else{
1165
+		for (r=0; r<t->nr_of_outgoings; r++){
1166
+			if (t->uac[r].request.flags & F_RB_TIMEOUT)
1167
+				return 1;
1168
+		}
1169
+	}
1170
+	return -1;
1171
+}
1172
+
1173
+
1174
+
1175
+/* script function, returns: 1 if any of the branches received at leat one
1176
+ * reply, -1 if not */
1177
+int t_any_replied(struct sip_msg* msg, char* foo, char* bar)
1178
+{
1179
+	struct cell *t;
1180
+	int r;
1181
+	
1182
+	if (t_check( msg , 0 )==-1) return -1;
1183
+	t=get_t();
1184
+	if ((t==0) || (t==T_UNDEFINED)){
1185
+		LOG(L_ERR, "ERROR: t_any_replied: cannot check a message "
1186
+			"for which no T-state has been established\n");
1187
+		return -1;
1188
+	}else{
1189
+		for (r=0; r<t->nr_of_outgoings; r++){
1190
+			if (t->uac[r].request.flags & F_RB_REPLIED)
1191
+				return 1;
1192
+		}
1193
+	}
1194
+	return -1;
1195
+}
1196
+
1197
+
1198
+
1111 1199
 static rpc_export_t tm_rpc[] = {
1112 1200
 	{"tm.cancel", rpc_cancel,   rpc_cancel_doc,   0},
1113 1201
 	{"tm.reply",  rpc_reply,    rpc_reply_doc,    0},
... ...
@@ -76,6 +76,10 @@ enum request_method { METHOD_UNDEF=0, METHOD_INVITE=1, METHOD_CANCEL=2, METHOD_A
76 76
 #define FL_SDP_IP_AFS 4    /* SDP IP rewritten */
77 77
 #define FL_SDP_PORT_AFS 8  /* SDP port rewritten */
78 78
 #define FL_SHM_CLONE   16  /* msg cloned in SHM as a single chunk */
79
+#define FL_TIMEOUT     32  /* message belongs to an "expired" branch
80
+                               (for failure route use) */
81
+#define FL_REPLIED     64  /* message branch received at least one reply
82
+                                (for failure route use) */
79 83
 
80 84
 
81 85
 #define IFISMETHOD(methodname,firstchar)                                  \