Ver Fonte

- 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 há 19 anos atrás
pai
commit
9ca82d2758
8 ficheiros alterados com 275 adições e 32 exclusões
  1. 1 1
      Makefile.defs
  2. 27 2
      NEWS
  3. 116 0
      modules/tm/doc/functions.xml
  4. 2 0
      modules/tm/h_table.h
  5. 13 6
      modules/tm/t_reply.c
  6. 9 23
      modules/tm/timer.c
  7. 103 0
      modules/tm/tm.c
  8. 4 0
      parser/msg_parser.h

+ 1 - 1
Makefile.defs

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

+ 27 - 2
NEWS

@@ -24,10 +24,12 @@ modules:
                 hashing after an uri (to, from or request uri)
                 hashing after an uri (to, from or request uri)
               - improved uri hashing (password is ignored, port is used only
               - improved uri hashing (password is ignored, port is used only
                 if != 5060 or 5061)
                 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)
              - migrated to the new timers (tm timers completely rewritten)
              - improved speed and less memory usage
              - improved speed and less memory usage
-             - much more precise reptransmissions timing
+             - much more precise retransmissions timing
              - params: - retr_timer1p1, retr_timer1p2, retr_timer1p3 removed
              - params: - retr_timer1p1, retr_timer1p2, retr_timer1p3 removed
                          and replaced by retr_timer1 and retr_timer2
                          and replaced by retr_timer1 and retr_timer2
                        - all timer values are now expressed in milliseconds
                        - all timer values are now expressed in milliseconds
@@ -39,6 +41,22 @@ modules:
                        - unix_tx_timeout expressed now in milliseconds; default
                        - unix_tx_timeout expressed now in milliseconds; default
                          value changed to 500 ms
                          value changed to 500 ms
              - functions:
              - 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
                        - new t_set_fr(timeout_fr_inv, timeout_fr) -- allows
                          changing the transaction timer from script, even if
                          changing the transaction timer from script, even if
                          the transaction was already created (see tm docs for
                          the transaction was already created (see tm docs for
@@ -183,6 +201,13 @@ tools:
                  , interactive mode, command line completion (if compiled with 
                  , interactive mode, command line completion (if compiled with 
                  libreadline) a.s.o.
                  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)
 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>
 	</example>
 	</section>
 	</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>
 </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_T2				0x02
 #define F_RB_RETR_DISABLED	0x04 /* retransmission disabled */
 #define F_RB_RETR_DISABLED	0x04 /* retransmission disabled */
 #define F_RB_FR_INV	0x08 /* timer switched to FR_INV */
 #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
 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,
 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
 	/* on_negative_reply faked msg now copied from shmem msg (as opposed
 	 * to zero-ing) -- more "read-only" actions (exec in particular) will
 	 * 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
 	/* msg->parsed_uri_ok must be reset since msg_parsed_uri is
 	 * not cloned (and cannot be cloned) */
 	 * not cloned (and cannot be cloned) */
 	faked_req->parsed_uri_ok = 0;
 	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 */
 	/* new_uri can change -- make a private copy */
 	if (shmem_msg->new_uri.s!=0 && shmem_msg->new_uri.len!=0) {
 	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);
 		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 */
 /* return 1 if a failure_route processes */
 static inline int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
 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;
 	static struct sip_msg faked_req;
 	struct sip_msg *shmem_msg = t->uas.request;
 	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;
 		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");
 		LOG(L_ERR, "ERROR: run_failure_handlers: fake_req failed\n");
 		return 0;
 		return 0;
 	}
 	}
@@ -757,6 +758,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 	int picked_code;
 	int picked_code;
 	int new_branch;
 	int new_branch;
 	int inv_through;
 	int inv_through;
+	int extra_flags;
 
 
 	/* note: this code never lets replies to CANCEL go through;
 	/* note: this code never lets replies to CANCEL go through;
 	   we generate always a local 200 for CANCEL; 200s are
 	   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) */
 		/* run ON_FAILURE handlers ( route and callbacks) */
 		if ( has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
 		if ( has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
 		|| Trans->on_negative ) {
 		|| 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,
 			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
 		/* 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.*/
 			 * retransmissions comes before retransmission timer is set.*/
 			/* set_final_timer(t) */
 			/* set_final_timer(t) */
 		}
 		}
-
 	}
 	}
+	uac->request.flags|=F_RB_REPLIED;
 
 
 	if (reply_status==RPS_ERROR)
 	if (reply_status==RPS_ERROR)
 		goto done;
 		goto done;

+ 9 - 23
modules/tm/timer.c

@@ -103,6 +103,10 @@
  *              it from the timer handle; timer_allow_del()  (andrei)
  *              it from the timer handle; timer_allow_del()  (andrei)
  *  2006-08-11  final_response_handler dns failover support for timeout-ed
  *  2006-08-11  final_response_handler dns failover support for timeout-ed
  *              invites (andrei)
  *              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"
 #include "defs.h"
@@ -321,7 +325,6 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
 											struct cell* t)
 											struct cell* t)
 {
 {
 	int silent;
 	int silent;
-	int reply_code;
 #ifdef USE_DNS_FAILOVER
 #ifdef USE_DNS_FAILOVER
 	/*int i; 
 	/*int i; 
 	int added_branches;
 	int added_branches;
@@ -395,12 +398,9 @@ inline static void final_response_handler(	struct retr_buf* r_buf,
 #ifdef EXTRA_DEBUG
 #ifdef EXTRA_DEBUG
 	DBG("DEBUG: final_response_handler:stop retr. and send CANCEL (%p)\n", t);
 	DBG("DEBUG: final_response_handler:stop retr. and send CANCEL (%p)\n", t);
 #endif
 #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
 #ifdef USE_DST_BLACKLIST
 		if (use_dst_blacklist)
 		if (use_dst_blacklist)
 			dst_blacklist_add( BLST_ERR_TIMEOUT, &r_buf->dst);
 			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;
 				prev_branch=branch_ret;
 				branch_ret=t_send_branch(t, branch_ret, t->uas.request , 0, 0);
 				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
 #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)
 							 (both timers disabled)
 							  a little race risk, but
 							  a little race risk, but
 							  nothing bad would happen */
 							  nothing bad would happen */
+		rbuf->flags|=F_RB_TIMEOUT;
 		timer_allow_del(); /* [optional] allow timer_dels, since we're done
 		timer_allow_del(); /* [optional] allow timer_dels, since we're done
 							  and there is no race risk */
 							  and there is no race risk */
 		final_response_handler(rbuf, t);
 		final_response_handler(rbuf, t);

+ 103 - 0
modules/tm/tm.c

@@ -77,6 +77,8 @@
  *              when fixing param #2
  *              when fixing param #2
  *  2005-12-09  added t_set_fr() (andrei)
  *  2005-12-09  added t_set_fr() (andrei)
  *  2006-02-07  named routes support (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);
 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_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_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;
 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 },
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
 	{"t_set_fr",          t_set_fr_all,             2, fixup_var_int_12,
 	{"t_set_fr",          t_set_fr_all,             2, fixup_var_int_12,
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
 			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 */
 	/* not applicable from the script */
 	{"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,   0, 0},
 	{"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[] = {
 static rpc_export_t tm_rpc[] = {
 	{"tm.cancel", rpc_cancel,   rpc_cancel_doc,   0},
 	{"tm.cancel", rpc_cancel,   rpc_cancel_doc,   0},
 	{"tm.reply",  rpc_reply,    rpc_reply_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_IP_AFS 4    /* SDP IP rewritten */
 #define FL_SDP_PORT_AFS 8  /* SDP port 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_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)                                  \
 #define IFISMETHOD(methodname,firstchar)                                  \