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

- 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 19 жил өмнө
parent
commit
9ca82d2758

+ 1 - 1
Makefile.defs

@@ -67,7 +67,7 @@ MAIN_NAME=ser
 VERSION = 0
 PATCHLEVEL = 10
 SUBLEVEL =   99
-EXTRAVERSION = -dev45-dns_cache
+EXTRAVERSION = -dev46-dns_cache
 
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
 			$(SUBLEVEL) )

+ 27 - 2
NEWS

@@ -24,10 +24,12 @@ modules:
                 hashing after an uri (to, from or request uri)
               - improved uri hashing (password is ignored, port is used only
                 if != 5060 or 5061)
- - tm        - dns failover and dst blacklist support
+ - tm        - special functions for checking for timeout, if a reply was
+               received or if the current transaction was canceled
+             - dns failover and dst blacklist support
              - migrated to the new timers (tm timers completely rewritten)
              - improved speed and less memory usage
-             - much more precise reptransmissions timing
+             - much more precise retransmissions timing
              - params: - retr_timer1p1, retr_timer1p2, retr_timer1p3 removed
                          and replaced by retr_timer1 and retr_timer2
                        - all timer values are now expressed in milliseconds
@@ -39,6 +41,22 @@ modules:
                        - unix_tx_timeout expressed now in milliseconds; default
                          value changed to 500 ms
              - functions:
+                       - t_branch_timeout() -- returns true if the failure
+                         route is executed for a branch that did timeout
+                         (failure_route only).
+                       - t_branch_replied() -- returns true if the failure 
+                         route is executed for a branch that did receive at
+                         least one reply (failure_route only).. It can be used
+                         together with t_branch_timeout() to distinguish 
+                         between a remote side that doesn't respond (some 
+                         provisional reply received) and one that is completely
+                          dead.
+                       - t_any_timeout() -- returns true if any of the current
+                         transaction branches did timeout.
+                       - t_any_replied() -- returns true if at least one branch
+                          of the current transaction received one reply.
+                       - t_is_canceled() -- returns true if the current 
+                         transaction  has been canceled.
                        - new t_set_fr(timeout_fr_inv, timeout_fr) -- allows
                          changing the transaction timer from script, even if
                          the transaction was already created (see tm docs for
@@ -183,6 +201,13 @@ tools:
                  , interactive mode, command line completion (if compiled with 
                  libreadline) a.s.o.
 
+WARNING: - older 0.10.99-dev version (< 0.10.99-dev46) returned a 480 reply
+ on invite transaction timeout, if a provisional reply was received. Newer
+ versions reverted to returning 408 on all timeouts (one can use 
+  t_branch_timeout() and t_branch_replied() to distinguish between the two
+  timeout types)
+
+
 
 0.9.4 fixes/improvements (0.9.4 is a bug fix release for 0.9.3)
  

+ 116 - 0
modules/tm/doc/functions.xml

@@ -412,4 +412,120 @@ branch_route[1] {
 	</example>
 	</section>
 
+	<section id="t_branch_timeout">
+	<title>
+	    <function>t_branch_timeout()</function>
+	</title>
+	<para>
+		Returns true if the failure route is executed for a branch that did
+		timeout. It can be used only from the 
+		<emphasis>failure_route</emphasis>.
+	</para>
+	<example>
+	    <title><function>t_branch_timeout</function> usage</title>
+	    <programlisting>
+...
+failure_route[0]{ 
+	if (t_branch_timeout()){
+		log("timeout\n");
+		# ... 
+	}
+} 
+	    </programlisting>
+	</example>
+	</section>
+
+<section id="t_branch_replied">
+	<title>
+	    <function>t_branch_replied()</function>
+	</title>
+	<para>
+		Returns true if the failure route is executed for a branch that did
+		receive at least one reply. It can be used only from the 
+		<emphasis>failure_route</emphasis>.
+	</para>
+	<example>
+	    <title><function>t_branch_replied</function> usage</title>
+	    <programlisting>
+...
+failure_route[0]{ 
+	if (t_branch_timeout()){
+		if (t_branch_replied())
+			log("timeout after receiving a reply (no answer?)\n");
+		else
+			log("timeout, remote side seems to be down\n");
+		# ... 
+	}
+} 
+	    </programlisting>
+	</example>
+	</section>
+
+<section id="t_any_timeout">
+	<title>
+	    <function>t_any_timeout()</function>
+	</title>
+	<para>
+		Returns true if at least one of the current transactions branches
+		did timeout.
+	</para>
+	<example>
+	    <title><function>t_any_timeout</function> usage</title>
+	    <programlisting>
+...
+failure_route[0]{ 
+	if (!t_branch_timeout()){
+		if (t_any_timeout()){
+			log("one branch did timeout\n");
+			sl_send_reply("408", "Timeout");
+		}
+	}
+} 
+	    </programlisting>
+	</example>
+	</section>
+
+<section id="t_any_replied">
+	<title>
+	    <function>t_any_replied()</function>
+	</title>
+	<para>
+		Returns true if at least one of the current transactions branches
+		did receive some reply.
+	</para>
+	<example>
+	    <title><function>t_any_replied</function> usage</title>
+	    <programlisting>
+...
+onreply_route[0]{ 
+	if (!t_any_replied()){
+		log("first reply received\n");
+		# ...
+	}
+} 
+	    </programlisting>
+	</example>
+	</section>
+
+<section id="t_is_canceled">
+	<title>
+	    <function>t_is_canceled()</function>
+	</title>
+	<para>
+		Returns true if the current transaction was canceled.
+	</para>
+	<example>
+	    <title><function>t_is_canceled</function> usage</title>
+	    <programlisting>
+...
+failure_route[0]{ 
+	if (t_is_canceled()){
+		log("transaction canceled\n");
+		# ...
+	}
+} 
+	    </programlisting>
+	</example>
+	</section>
+
 </section>

+ 2 - 0
modules/tm/h_table.h

@@ -107,6 +107,8 @@ enum kill_reason { REQ_FWDED=1, REQ_RPLD=2, REQ_RLSD=4, REQ_EXIST=8 };
 #define F_RB_T2				0x02
 #define F_RB_RETR_DISABLED	0x04 /* retransmission disabled */
 #define F_RB_FR_INV	0x08 /* timer switched to FR_INV */
+#define F_RB_TIMEOUT	0x10 /* timeout */
+#define F_RB_REPLIED	0x20 /* reply received */
 
 
 typedef struct retr_buf

+ 13 - 6
modules/tm/t_reply.c

@@ -565,7 +565,7 @@ static inline void faked_env( struct cell *t,struct sip_msg *msg)
 
 
 static inline int fake_req(struct sip_msg *faked_req,
-				struct sip_msg *shmem_msg)
+							struct sip_msg *shmem_msg, int extra_flags)
 {
 	/* on_negative_reply faked msg now copied from shmem msg (as opposed
 	 * 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,
 	/* msg->parsed_uri_ok must be reset since msg_parsed_uri is
 	 * not cloned (and cannot be cloned) */
 	faked_req->parsed_uri_ok = 0;
-
+	
+	faked_req->msg_flags|=extra_flags; /* set the extra tm flags */
 	/* new_uri can change -- make a private copy */
 	if (shmem_msg->new_uri.s!=0 && shmem_msg->new_uri.len!=0) {
 		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)
 
 /* return 1 if a failure_route processes */
 static inline int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
-																	int code)
+											int code, int extra_flags)
 {
 	static struct sip_msg faked_req;
 	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,
 		return 1;
 	}
 
-	if (!fake_req(&faked_req, shmem_msg)) {
+	if (!fake_req(&faked_req, shmem_msg, extra_flags)) {
 		LOG(L_ERR, "ERROR: run_failure_handlers: fake_req failed\n");
 		return 0;
 	}
@@ -757,6 +758,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 	int picked_code;
 	int new_branch;
 	int inv_through;
+	int extra_flags;
 
 	/* note: this code never lets replies to CANCEL go through;
 	   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,
 		/* run ON_FAILURE handlers ( route and callbacks) */
 		if ( has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
 		|| Trans->on_negative ) {
+			extra_flags=
+				((Trans->uac[picked_branch].request.flags & F_RB_TIMEOUT)?
+							FL_TIMEOUT:0) | 
+				((Trans->uac[picked_branch].request.flags & F_RB_REPLIED)?
+						 	FL_REPLIED:0);
 			run_failure_handlers( Trans, Trans->uac[picked_branch].reply,
-									picked_code);
+									picked_code, extra_flags);
 		}
 
 		/* now reset it; after the failure logic, the reply may
@@ -1437,8 +1444,8 @@ int reply_received( struct sip_msg  *p_msg )
 			 * retransmissions comes before retransmission timer is set.*/
 			/* set_final_timer(t) */
 		}
-
 	}
+	uac->request.flags|=F_RB_REPLIED;
 
 	if (reply_status==RPS_ERROR)
 		goto done;

+ 9 - 23
modules/tm/timer.c

@@ -103,6 +103,10 @@
  *              it from the timer handle; timer_allow_del()  (andrei)
  *  2006-08-11  final_response_handler dns failover support for timeout-ed
  *              invites (andrei)
+ *  2006-09-28  removed the 480 on fr_inv_timeout reply: on timeout always 
+ *               return a 408
+ *              set the corresponding "faked" failure route sip_msg->msg_flags 
+ *               on timeout or if the branch received a reply (andrei)
  */
 
 #include "defs.h"
@@ -321,7 +325,6 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
 											struct cell* t)
 {
 	int silent;
-	int reply_code;
 #ifdef USE_DNS_FAILOVER
 	/*int i; 
 	int added_branches;
@@ -395,12 +398,9 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
 #ifdef EXTRA_DEBUG
 	DBG("DEBUG: final_response_handler:stop retr. and send CANCEL (%p)\n", t);
 #endif
-	if (is_invite(t) && 
-	    r_buf->branch < MAX_BRANCHES && /* r_buf->branch is always >=0 */
-	    t->uac[r_buf->branch].last_received > 0) {
-		reply_code = 480; /* Temporarily Unavailable */
-	} else {
-		reply_code = 408; /* Request Timeout */
+	if ((r_buf->branch < MAX_BRANCHES) && /* r_buf->branch is always >=0 */
+			(t->uac[r_buf->branch].last_received==0)){
+		/* no reply received */
 #ifdef USE_DST_BLACKLIST
 		if (use_dst_blacklist)
 			dst_blacklist_add( BLST_ERR_TIMEOUT, &r_buf->dst);
@@ -419,25 +419,10 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
 				prev_branch=branch_ret;
 				branch_ret=t_send_branch(t, branch_ret, t->uas.request , 0, 0);
 			}
-#if 0
-			if (branch_ret>=0){
-				added_branches=1<<branch_ret;
-				/* success */
-				for (i=branch_ret; i<t->nr_of_outgoings; i++) {
-					if (added_branches & (1<<i)) {
-						branch_ret=t_send_branch(t, i, t->uas.request , 0, 0);
-						if ((branch_ret>=0) && (branch_ret!=i)){
-							/* no send, but new branch */
-							added_branches |= 1<<branch_ret;
-						}
-					}
-				}
-			}
-#endif
 		}
 #endif
 	}
-	fake_reply(t, r_buf->branch, reply_code );
+	fake_reply(t, r_buf->branch, 408);
 }
 
 
@@ -477,6 +462,7 @@ ticks_t retr_buf_handler(ticks_t ticks, struct timer_ln* tl, void *p)
 							 (both timers disabled)
 							  a little race risk, but
 							  nothing bad would happen */
+		rbuf->flags|=F_RB_TIMEOUT;
 		timer_allow_del(); /* [optional] allow timer_dels, since we're done
 							  and there is no race risk */
 		final_response_handler(rbuf, t);

+ 103 - 0
modules/tm/tm.c

@@ -77,6 +77,8 @@
  *              when fixing param #2
  *  2005-12-09  added t_set_fr() (andrei)
  *  2006-02-07  named routes support (andrei)
+ *  2006-09-28  added t_branch_replied, t_branch_timeout, t_any_replied, 
+ *               t_any_timeout, t_is_canceled (andrei)
  */
 
 
@@ -181,6 +183,11 @@ inline static int w_t_on_reply(struct sip_msg* msg, char *go_to, char *foo );
 inline static int t_check_status(struct sip_msg* msg, char *regexp, char *foo);
 static int t_set_fr_inv(struct sip_msg* msg, char* fr_inv, char* foo);
 static int t_set_fr_all(struct sip_msg* msg, char* fr_inv, char* fr);
+static int t_branch_timeout(struct sip_msg* msg, char*, char*);
+static int t_branch_replied(struct sip_msg* msg, char*, char*);
+static int t_any_timeout(struct sip_msg* msg, char*, char*);
+static int t_any_replied(struct sip_msg* msg, char*, char*);
+static int t_is_canceled(struct sip_msg* msg, char*, char*);
 
 
 static char *fr_timer_param = FR_TIMER_AVP;
@@ -265,6 +272,14 @@ static cmd_export_t cmds[]={
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
 	{"t_set_fr",          t_set_fr_all,             2, fixup_var_int_12,
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"t_branch_timeout",  t_branch_timeout,         0, 0,  FAILURE_ROUTE},
+	{"t_branch_replied",  t_branch_replied,         0, 0,  FAILURE_ROUTE},
+	{"t_any_timeout",     t_any_timeout,            0, 0, 
+			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"t_any_replied",     t_any_replied,            0, 0, 
+			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+	{"t_is_canceled",     t_is_canceled,            0, 0,
+			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
 
 	/* not applicable from the script */
 	{"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)
 }
 
 
+
+/* script function, FAILURE_ROUTE only, returns true if the 
+ * choosed "failure" branch failed because of a timeout, 
+ * -1 otherwise */
+int t_branch_timeout(struct sip_msg* msg, char* foo, char* bar)
+{
+	return (msg->msg_flags & FL_TIMEOUT)?1:-1;
+}
+
+
+
+/* script function, FAILURE_ROUTE only, returns true if the 
+ * choosed "failure" branch ever received a reply, -1 otherwise */
+int t_branch_replied(struct sip_msg* msg, char* foo, char* bar)
+{
+	return (msg->msg_flags & FL_REPLIED)?1:-1;
+}
+
+
+
+/* script function, returns: 1 if the transaction was canceled, -1 if not */
+int t_is_canceled(struct sip_msg* msg, char* foo, char* bar)
+{
+	struct cell *t;
+	int ret;
+	
+	
+	if (t_check( msg , 0 )==-1) return -1;
+	t=get_t();
+	if ((t==0) || (t==T_UNDEFINED)){
+		LOG(L_ERR, "ERROR: t_is_canceled: cannot check a message "
+			"for which no T-state has been established\n");
+		ret=-1;
+	}else{
+		ret=(t->flags & T_CANCELED)?1:-1;
+	}
+	return ret;
+}
+
+
+
+/* script function, returns: 1 if any of the branches did timeout, -1 if not */
+int t_any_timeout(struct sip_msg* msg, char* foo, char* bar)
+{
+	struct cell *t;
+	int r;
+	
+	if (t_check( msg , 0 )==-1) return -1;
+	t=get_t();
+	if ((t==0) || (t==T_UNDEFINED)){
+		LOG(L_ERR, "ERROR: t_any_timeout: cannot check a message "
+			"for which no T-state has been established\n");
+		return -1;
+	}else{
+		for (r=0; r<t->nr_of_outgoings; r++){
+			if (t->uac[r].request.flags & F_RB_TIMEOUT)
+				return 1;
+		}
+	}
+	return -1;
+}
+
+
+
+/* script function, returns: 1 if any of the branches received at leat one
+ * reply, -1 if not */
+int t_any_replied(struct sip_msg* msg, char* foo, char* bar)
+{
+	struct cell *t;
+	int r;
+	
+	if (t_check( msg , 0 )==-1) return -1;
+	t=get_t();
+	if ((t==0) || (t==T_UNDEFINED)){
+		LOG(L_ERR, "ERROR: t_any_replied: cannot check a message "
+			"for which no T-state has been established\n");
+		return -1;
+	}else{
+		for (r=0; r<t->nr_of_outgoings; r++){
+			if (t->uac[r].request.flags & F_RB_REPLIED)
+				return 1;
+		}
+	}
+	return -1;
+}
+
+
+
 static rpc_export_t tm_rpc[] = {
 	{"tm.cancel", rpc_cancel,   rpc_cancel_doc,   0},
 	{"tm.reply",  rpc_reply,    rpc_reply_doc,    0},

+ 4 - 0
parser/msg_parser.h

@@ -76,6 +76,10 @@ enum request_method { METHOD_UNDEF=0, METHOD_INVITE=1, METHOD_CANCEL=2, METHOD_A
 #define FL_SDP_IP_AFS 4    /* SDP IP rewritten */
 #define FL_SDP_PORT_AFS 8  /* SDP port rewritten */
 #define FL_SHM_CLONE   16  /* msg cloned in SHM as a single chunk */
+#define FL_TIMEOUT     32  /* message belongs to an "expired" branch
+                               (for failure route use) */
+#define FL_REPLIED     64  /* message branch received at least one reply
+                                (for failure route use) */
 
 
 #define IFISMETHOD(methodname,firstchar)                                  \