Selaa lähdekoodia

s/reply_route/failure_route, onreply_route introduced

Jiri Kuthan 22 vuotta sitten
vanhempi
commit
87405423a6
15 muutettua tiedostoa jossa 483 lisäystä ja 267 poistoa
  1. 28 1
      NEWS
  2. 10 3
      cfg.lex
  3. 20 6
      cfg.y
  4. 2 1
      config.h
  5. 4 4
      examples/onr.cfg
  6. 2 0
      modules/tm/h_table.h
  7. 15 3
      modules/tm/t_fwd.c
  8. 4 0
      modules/tm/t_lookup.c
  9. 254 221
      modules/tm/t_reply.c
  10. 5 3
      modules/tm/t_reply.h
  11. 103 13
      modules/tm/tm.c
  12. 3 0
      modules/tm/uac.c
  13. 27 9
      route.c
  14. 2 1
      route.h
  15. 4 2
      sr_module.h

+ 28 - 1
NEWS

@@ -35,10 +35,13 @@ New features
 - improved tm/FIFO (external applications, such as
   click-to-dial can now better initiate transactions)
   [tm module]
+- nathelper utility for Cisco/ATA NAT traversal
 - powerpc fast locking support
 - netbsd support
 - 64 bits arch. support (e.g. netbsd/sparc64).
 - tcp2udp and udp2tcp stateless forwarding (see forward_udp & forward_tcp)
+- rich access control lists [module permissions]
+
 
 Changes to use of ser scripts
 =============================
@@ -47,6 +50,8 @@ Changes to use of ser scripts
 core
 ----
 XXX TCP
+- reply_route has been renamed to failure_route -- the old name caused
+  too much confusion
 
 acc module:
 -----------
@@ -94,4 +99,26 @@ tm module:
 ----------
 - t_reply_unsafe, used in former versions within reply_routes,
   is deprecated; now t_reply is used from any places in script
-- XXX t_uac/FIFO
+- t_on_negative is renamed to t_on_failure -- the old name just
+  caused too much confusion
+- FIFO t_uac used by some applications (like serweb) has been
+  replaced with t_uac_dlg (which allows easier use by dialog-
+  oriented applications, like click-to-dial) 
+- if you wish to do forward to another destination from 
+  failure_route (reply_route formerly), you need to call t_relay
+  or t_relay_to explicitely now
+
+List of new modules:
+--------------------
+- dbtext -- flat-file database
+- domain -- automated domain management
+- enum -- ENUM support
+- nathelper -- utility for NAT traversal for Cisco ATAs
+- pa -- presence agent
+- permissions -- ACLs
+- vm -- voicemail interface
+
+List of deprecated modules:
+---------------------------
+- im (t_uac_dlg is used for sending messages)
+- radius_acc (radius accounting now part of acc module)

+ 10 - 3
cfg.lex

@@ -32,6 +32,7 @@
  *  2003-01-23  mhomed added (jiri)
  *  2003-03-19  replaced all the mallocs/frees w/ pkg_malloc/pkg_free (andrei)
  *  2003-04-01  added dst_port, proto (tcp, udp, tls), af(inet, inet6) (andrei)
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
  */
 
 
@@ -78,7 +79,8 @@ SEND_TCP	send_tcp
 LOG		log
 ERROR	error
 ROUTE	route
-REPL_ROUTE reply_route
+FAILURE_ROUTE failure_route
+ONREPLY_ROUTE onreply_route
 EXEC	exec
 SETFLAG		setflag
 RESETFLAG	resetflag
@@ -106,7 +108,11 @@ MAX_LEN			"max_len"
 
 /* condition keywords */
 METHOD	method
-URI		uri
+/* hack -- the second element in first line is referrable
+   as either uri or status; it only would makes sense to
+   call it "uri" from route{} and status from onreply_route{}
+*/
+URI		"uri"|"status"
 SRCIP	src_ip
 SRCPORT	src_port
 DSTIP	dst_ip
@@ -206,7 +212,8 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{ISFLAGSET}	{ count(); yylval.strval=yytext; return ISFLAGSET; }
 <INITIAL>{LEN_GT}	{ count(); yylval.strval=yytext; return LEN_GT; }
 <INITIAL>{ROUTE}	{ count(); yylval.strval=yytext; return ROUTE; }
-<INITIAL>{REPL_ROUTE}	{ count(); yylval.strval=yytext; return REPL_ROUTE; }
+<INITIAL>{ONREPLY_ROUTE}	{ count(); yylval.strval=yytext; return ONREPLY_ROUTE; }
+<INITIAL>{FAILURE_ROUTE}	{ count(); yylval.strval=yytext; return FAILURE_ROUTE; }
 <INITIAL>{EXEC}	{ count(); yylval.strval=yytext; return EXEC; }
 <INITIAL>{SET_HOST}	{ count(); yylval.strval=yytext; return SET_HOST; }
 <INITIAL>{SET_HOSTPORT}	{ count(); yylval.strval=yytext; return SET_HOSTPORT; }

+ 20 - 6
cfg.y

@@ -35,6 +35,7 @@
  * 2003-03-19  Added support for route type in find_export (janakj)
  * 2003-03-20  Regex support in modparam (janakj)
  * 2003-04-01  added dst_port, proto , af (andrei)
+ * 2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
  */
 
 
@@ -106,7 +107,8 @@ int rt;  /* Type of route block for find_export */
 %token LOG_TOK
 %token ERROR
 %token ROUTE
-%token REPL_ROUTE
+%token FAILURE_ROUTE
+%token ONREPLY_ROUTE
 %token EXEC
 %token SET_HOST
 %token SET_HOSTPORT
@@ -221,7 +223,8 @@ statements:	statements statement {}
 statement:	assign_stm 
 		| module_stm
 		| {rt=REQUEST_ROUTE;} route_stm 
-		| {rt=REPLY_ROUTE;} reply_route_stm
+		| {rt=FAILURE_ROUTE;} failure_route_stm
+		| {rt=ONREPLY_ROUTE;} onreply_route_stm
 
 		| CR	/* null statement*/
 	;
@@ -463,15 +466,26 @@ route_stm:  ROUTE LBRACE actions RBRACE { push($3, &rlist[DEFAULT_RT]); }
 		| ROUTE error { yyerror("invalid  route  statement"); }
 	;
 
-reply_route_stm: REPL_ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
-										if (($3<REPLY_RT_NO)&&($3>=1)){
-											push($6, &reply_rlist[$3]);
+failure_route_stm: FAILURE_ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
+										if (($3<FAILURE_RT_NO)&&($3>=1)){
+											push($6, &failure_rlist[$3]);
 										} else {
 											yyerror("invalid reply routing"
 												"table number");
 											YYABORT; }
 										}
-		| REPL_ROUTE error { yyerror("invalid reply_route statement"); }
+		| FAILURE_ROUTE error { yyerror("invalid failure_route statement"); }
+	;
+
+onreply_route_stm: ONREPLY_ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
+										if (($3<ONREPLY_RT_NO)&&($3>=1)){
+											push($6, &onreply_rlist[$3]);
+										} else {
+											yyerror("invalid reply routing"
+												"table number");
+											YYABORT; }
+										}
+		| ONREPLY_ROUTE error { yyerror("invalid failure_route statement"); }
 	;
 /*
 rules:	rules rule { push($2, &$1); $$=$1; }

+ 2 - 1
config.h

@@ -50,7 +50,8 @@
 #define CHILD_NO    8
 
 #define RT_NO 10 /* routing tables number */
-#define REPLY_RT_NO 10 /* reply routing tables number */
+#define FAILURE_RT_NO RT_NO /* on_failure routing tables number */
+#define ONREPLY_RT_NO RT_NO /* on_reply routing tables number */
 #define DEFAULT_RT 0 /* default routing table */
 
 #define MAX_REC_LEV 100 /* maximum number of recursive calls */

+ 4 - 4
examples/onr.cfg

@@ -39,20 +39,20 @@ route{
 	seturi("sip:[email protected]");
 	append_branch("sip:[email protected]:9");
 	# if we do not get a positive reply, continue at reply_route[1]
-	t_on_negative("1");
+	t_on_failure("1");
 	# forward the request to all destinations in destination set now 
 	t_relay();
 }
 
-reply_route[1] {
+failure_route[1] {
 	# forwarding failed -- try again at another destination 
 	append_branch("sip:[email protected]");
 	log(1,"first redirection\n");
 	# if this alternative destination fails too, proceed to reply_route[2] 
-	t_on_negative("2");
+	t_on_failure("2");
 }
 
-reply_route[2] {
+failure_route[2] {
 	# try out the last resort destination
 	append_branch("sip:[email protected]");
 	log(1, "second redirection\n");

+ 2 - 0
modules/tm/h_table.h

@@ -225,6 +225,8 @@ typedef struct cell
 
 	/* the route to take if no final positive reply arrived */
 	unsigned int on_negative;
+	/* the onreply_route to be processed if registered to do so */
+	unsigned int on_reply;
 	/* set to one if you want to disallow silent transaction
 	   dropping when C timer hits
 	*/

+ 15 - 3
modules/tm/t_fwd.c

@@ -386,6 +386,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 	int i;
 	struct cell *t_invite;
 	int success_branch;
+	int try_new;
 
 	/* make -Wall happy */
 	current_uri.s=0;
@@ -414,15 +415,17 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 	   is in additional branches (which may be continuously refilled
 	*/
 	if (first_branch==0) {
+		try_new=1;
 		branch_ret=add_uac( t, p_msg, &GET_RURI(p_msg), &GET_NEXT_HOP(p_msg), proxy, proto );
 		if (branch_ret>=0) 
 			added_branches |= 1<<branch_ret;
 		else
 			lowest_ret=branch_ret;
-	}
+	} else try_new=0;
 
 	init_branch_iterator();
 	while((current_uri.s=next_branch( &current_uri.len))) {
+		try_new++;
 		branch_ret=add_uac( t, p_msg, &current_uri, 
 				    (p_msg->dst_uri.len) ? (&p_msg->dst_uri) : &current_uri, 
 				    proxy, proto);
@@ -444,10 +447,19 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 	/* don't forget to clear all branches processed so far */
 
 	/* things went wrong ... no new branch has been fwd-ed at all */
-	if (added_branches==0)
+	if (added_branches==0) {
+		if (try_new==0) {
+			LOG(L_ERR, "ERROR: t_forward_nonack: no branched for fwding\n");
+			return -1;
+		}
+		LOG(L_ERR, "ERROR: t_forward_nonack: failure to add branches\n");
 		return lowest_ret;
+	}
 
-	/* if someone set on_negative, store in in T-context */
+	/* store script processing value of failure route to transactional
+	   context; if currently 0, this forwarding attempt will no longer 
+	   result in failure_route on error
+	*/
 	t->on_negative=get_on_negative();
 
 	/* send them out now */

+ 4 - 0
modules/tm/t_lookup.c

@@ -67,6 +67,8 @@
  * 2003-03-30  set_kr for requests only (jiri)
  * 2003-04-04  bug_fix: RESPONSE_IN callback not called for local
  *             UAC transactions (jiri)
+ * 2003-04-07  new transactions inherit on_negative and on_relpy from script
+ *             variables on instatntiation (jiri)
  */
 
 
@@ -1023,6 +1025,8 @@ int t_newtran( struct sip_msg* p_msg )
 
 				new_cell->method=new_cell->uas.request->first_line.u.request.method;
 				new_cell->is_invite=p_msg->REQ_METHOD==METHOD_INVITE;
+				new_cell->on_negative=get_on_negative();
+				new_cell->on_reply=get_on_reply();
 
 			}
 

+ 254 - 221
modules/tm/t_reply.c

@@ -41,6 +41,7 @@
  *  2003-03-16  removed _TOTAG (jiri)
  *  2003-03-31  200 for INVITE/UAS resent even for UDP (jiri)
  *  2003-03-31  removed msg->repl_add_rm (andrei)
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
  */
 
 
@@ -82,6 +83,8 @@ static char *tm_tag_suffix;
 
 /* where to go if there is no positive reply */
 static int goto_on_negative=0;
+/* where to go on receipt of reply */
+static int goto_on_reply=0;
 
 
 /* we store the reply_route # in private memory which is
@@ -94,10 +97,14 @@ static int goto_on_negative=0;
 */
   
   
-int t_on_negative( unsigned int go_to )
+void t_on_negative( unsigned int go_to )
 {
 	goto_on_negative=go_to;
-	return 1;
+}
+
+void t_on_reply( unsigned int go_to )
+{
+	goto_on_reply=go_to;
 }
 
 
@@ -105,6 +112,10 @@ unsigned int get_on_negative()
 {
 	return goto_on_negative;
 }
+unsigned int get_on_reply()
+{
+	return goto_on_reply;
+}
 
 void tm_init_tags()
 {
@@ -141,6 +152,16 @@ int unmatched_totag(struct cell *t, struct sip_msg *ack)
 	return 1;
 }
 
+static inline void update_local_tags(struct cell *trans, 
+				struct bookmark *bm, char *dst_buffer,
+				char *src_buffer /* to which bm refers */)
+{
+	if (bm->to_tag_val.s) {
+		trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer;
+		trans->uas.local_totag.len=bm->to_tag_val.len;
+	}
+}
+
 
 /* append a newly received tag from a 200/INVITE to 
  * transaction's set; (only safe if called from within
@@ -213,6 +234,141 @@ static char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch,
         ACK, ACK_LEN, &to );
 }
 
+static int _reply_light( struct cell *trans, char* buf, unsigned int len,
+			 unsigned int code, char * text, 
+			 char *to_tag, unsigned int to_tag_len, int lock,
+			 struct bookmark *bm	)
+{
+	struct retr_buf *rb;
+	unsigned int buf_len;
+	branch_bm_t cancel_bitmap;
+
+	if (!buf)
+	{
+		DBG("DEBUG: t_reply: response building failed\n");
+		/* determine if there are some branches to be cancelled */
+		if (trans->is_invite) {
+			if (lock) LOCK_REPLIES( trans );
+			which_cancel(trans, &cancel_bitmap );
+			if (lock) UNLOCK_REPLIES( trans );
+		}
+		/* and clean-up, including cancellations, if needed */
+		goto error;
+	}
+
+	cancel_bitmap=0;
+	if (lock) LOCK_REPLIES( trans );
+	if (trans->is_invite) which_cancel(trans, &cancel_bitmap );
+	if (trans->uas.status>=200) {
+		LOG( L_ERR, "ERROR: t_reply: can't generate %d reply"
+			" when a final %d was sent out\n", code, trans->uas.status);
+		goto error2;
+	}
+
+
+	rb = & trans->uas.response;
+	rb->activ_type=code;
+
+	trans->uas.status = code;
+	buf_len = rb->buffer ? len : len + REPLY_OVERBUFFER_LEN;
+	rb->buffer = (char*)shm_resize( rb->buffer, buf_len );
+	/* puts the reply's buffer to uas.response */
+	if (! rb->buffer ) {
+			LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n");
+			goto error3;
+	}
+	update_local_tags(trans, bm, rb->buffer, buf);
+
+	rb->buffer_len = len ;
+	memcpy( rb->buffer , buf , len );
+	/* needs to be protected too because what timers are set depends
+	   on current transactions status */
+	/* t_update_timers_after_sending_reply( rb ); */
+	update_reply_stats( code );
+	trans->relaied_reply_branch=-2;
+	tm_stats->replied_localy++;
+	if (lock) UNLOCK_REPLIES( trans );
+	
+	/* do UAC cleanup procedures in case we generated
+	   a final answer whereas there are pending UACs */
+	if (code>=200) {
+		if (trans->local) {
+			DBG("DEBUG: local transaction completed from _reply\n");
+			callback_event( TMCB_LOCAL_COMPLETED, trans, FAKED_REPLY, code );
+			if (trans->completion_cb) 
+				trans->completion_cb( trans, FAKED_REPLY, code, 0 /* empty param */);
+		} else {
+			callback_event( TMCB_RESPONSE_OUT, trans, FAKED_REPLY, code );
+		}
+
+		cleanup_uac_timers( trans );
+		if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
+		set_final_timer(  trans );
+	}
+
+	/* send it out */
+	/* first check if we managed to resolve topmost Via -- if
+	   not yet, don't try to retransmit
+	*/
+	if (!trans->uas.response.dst.send_sock) {
+		LOG(L_ERR, "ERROR: _reply: no resolved dst to send reply to\n");
+	} else {
+		SEND_PR_BUFFER( rb, buf, len );
+		DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n", 
+			buf, buf, rb->buffer, rb->buffer );
+	}
+	pkg_free( buf ) ;
+	DBG("DEBUG: t_reply: finished\n");
+	return 1;
+
+error3:
+error2:
+	if (lock) UNLOCK_REPLIES( trans );
+	pkg_free ( buf );
+error:
+	/* do UAC cleanup */
+	cleanup_uac_timers( trans );
+	if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
+	/* we did not succeed -- put the transaction on wait */
+	put_on_wait(trans);
+	return -1;
+}
+
+
+/* send a UAS reply
+ * returns 1 if everything was OK or -1 for error
+ */
+static int _reply( struct cell *trans, struct sip_msg* p_msg, 
+	unsigned int code, char * text, int lock )
+{
+	unsigned int len;
+	char * buf;
+	struct bookmark bm;
+
+	if (code>=200) set_kr(REQ_RPLD);
+	/* compute the buffer in private memory prior to entering lock;
+	 * create to-tag if needed */
+	if (code>=180 && p_msg->to 
+				&& (get_to(p_msg)->tag_value.s==0 
+			    || get_to(p_msg)->tag_value.len==0)) {
+		calc_crc_suffix( p_msg, tm_tag_suffix );
+		buf = build_res_buf_from_sip_req(code,text, 
+				tm_tags, TOTAG_VALUE_LEN, 
+				p_msg,&len, &bm);
+
+		return _reply_light(trans,buf,len,code,text,
+				    tm_tags, TOTAG_VALUE_LEN,
+				    lock, &bm);
+	} else {
+		buf = build_res_buf_from_sip_req(code,text, 0,0, /* no to-tag */
+			p_msg,&len, &bm);
+
+		return _reply_light(trans,buf,len,code,text,
+				    0,0, /* no to-tag */
+				    lock, &bm);
+	}
+}
+
 
 /* create a temporary faked message environment in which a conserved
  * t->uas.request in shmem is partially duplicated to pkgmem
@@ -257,7 +413,7 @@ static int faked_env(struct sip_msg *fake,
 	 * for example t_reply needs to know that
 	 */
 	backup_mode=rmode;
-	rmode=MODE_ONREPLY_REQUEST;
+	rmode=MODE_ONFAILURE;
 	/* also, tm actions look in beginning whether tranaction is
 	 * set -- whether we are called from a reply-processing 
 	 * or a timer process, we need to set current transaction;
@@ -309,11 +465,68 @@ restore:
 	return 0;
 }
 
+/* return 1 if a failure_route processes */
+int failure_route(struct cell *t)
+{
+	struct sip_msg faked_msg;
+
+	/* don't do anything if we don't have to */
+	if (!t->on_negative) return 0;
+
+	/* if fake message creation failes, return error too */
+	if (!faked_env(&faked_msg, t, t->uas.request, 0 /* create fake */ )) {
+		LOG(L_ERR, "ERROR: on_negative_reply: faked_env failed\n");
+		return 0;
+	}
+
+	/* avoid recursion -- if failure_route forwards, and does not 
+	 * set next failure route, failure_route will not be rentered
+	 * on failure */
+	t_on_negative(0);
+	/* run a reply_route action if some was marked */
+	if (run_actions(failure_rlist[t->on_negative], &faked_msg)<0)
+		LOG(L_ERR, "ERROR: on_negative_reply: "
+			"Error in do_action\n");
+	/* restore original environment */
+	faked_env(&faked_msg, 0, 0, 1 );
+	return 1;
+}
 
 
-/* the main code of stateful replying */
-static int _reply( struct cell *t, struct sip_msg* p_msg, unsigned int code,
-    char * text, int lock );
+/* select a branch for forwarding; returns:
+ * 0..X ... branch number
+ * -1   ... error
+ * -2   ... can't decide yet -- incomplete branches present
+ */
+static int pick_branch( int inc_branch, int inc_code, 
+			struct cell *t, int *res_code)
+{
+	int lowest_b, lowest_s, b;
+
+	lowest_b=-1; lowest_s=999;
+	for ( b=0; b<t->nr_of_outgoings ; b++ ) {
+		/* "fake" for the currently processed branch */
+		if (b==inc_branch) {
+			if (inc_code<lowest_s) {
+				lowest_b=b;
+				lowest_s=inc_code;
+			}
+			continue;
+		}
+		/* skip 'empty branches' */
+		if (!t->uac[b].request.buffer) continue;
+		/* there is still an unfinished UAC transaction; wait now! */
+		if ( t->uac[b].last_received<200 ) 
+			return -2;
+		if ( t->uac[b].last_received<lowest_s ) {
+			lowest_b =b;
+			lowest_s = t->uac[b].last_received;
+		}
+	} /* find lowest branch */
+
+	*res_code=lowest_s;
+	return lowest_b;
+}
 
 /* This is the neuralgical point of reply processing -- called
  * from within a REPLY_LOCK, t_should_relay_response decides
@@ -330,9 +543,10 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 	int branch , int *should_store, int *should_relay,
 	branch_bm_t *cancel_bitmap, struct sip_msg *reply )
 {
-	int b, lowest_b, lowest_s, dummy;
-	struct sip_msg faked_msg, *origin_rq;
-	unsigned int on_neg;
+	
+	int branch_cnt;
+	int picked_branch;
+	int picked_code;
 
 	/* note: this code never lets replies to CANCEL go through;
 	   we generate always a local 200 for CANCEL; 200s are
@@ -378,63 +592,31 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 		}
 
 		Trans->uac[branch].last_received=new_code;
+
+
 		/* if all_final return lowest */
-		lowest_b=-1; lowest_s=999;
-		for ( b=0; b<Trans->nr_of_outgoings ; b++ ) {
-			/* "fake" for the currently processed branch */
-			if (b==branch) {
-				if (new_code<lowest_s) {
-					lowest_b=b;
-					lowest_s=new_code;
-				}
-				continue;
-			}
-			/* skip 'empty branches' */
-			if (!Trans->uac[b].request.buffer) continue;
-			/* there is still an unfinished UAC transaction; wait now! */
-			if ( Trans->uac[b].last_received<200 ) {
-				*should_store=1;	
-				*should_relay=-1;
-				return RPS_STORE;
-			}
-			if ( Trans->uac[b].last_received<lowest_s )
-			{
-				lowest_b =b;
-				lowest_s = Trans->uac[b].last_received;
-			}
-		} /* find lowest branch */
-		if (lowest_b==-1) {
+		picked_branch=pick_branch(branch,new_code, Trans, &picked_code);
+		if (picked_branch==-2) { /* branches open yet */
+			*should_store=1;	
+			*should_relay=-1;
+			return RPS_STORE;
+		}
+		if (picked_branch==-1) {
 			LOG(L_CRIT, "ERROR: t_should_relay_response: lowest==-1\n");
+			goto error;
 		}
+
 		/* no more pending branches -- try if that changes after
-		   a callback
+		   a callback; save banch count to be able to determine
+		   later if new branches were initiated
 		*/
+		branch_cnt=Trans->nr_of_outgoings;
 		callback_event( TMCB_ON_FAILURE, Trans, 
-			lowest_b==branch?reply:Trans->uac[lowest_b].reply, 
-			lowest_s );
-
+			picked_branch==branch?reply:Trans->uac[picked_branch].reply, 
+			picked_code);
 		/* here, we create a faked environment, from which we
 		 * return to request processing, if marked to do so */
-		origin_rq=Trans->uas.request;
-		on_neg=Trans->on_negative;
-		if (on_neg) {
-			DBG("DBG: on_negative_reply processed for transaction %p\n", 
-					Trans);
-			if (faked_env(&faked_msg, Trans, Trans->uas.request, 
-									0 /* create fake */ )) 
-			{
-				/* use the faked message later in forwarding */
-				origin_rq=&faked_msg;
-	  		 	/* run a reply_route action if some was marked */
-				if (run_actions(reply_rlist[on_neg], &faked_msg )<0)
-					LOG(L_ERR, "ERROR: on_negative_reply: "
-						"Error in do_action\n");
-			} else { /* faked_env creation error */
-				LOG(L_ERR, "ERROR: on_negative_reply: faked_env failed\n");
-				on_neg=0;
-			} 
-		} /* if (on_neg) */
-
+		failure_route(Trans);
 
 		/* look if the callback perhaps replied transaction; it also
 		   covers the case in which a transaction is replied localy
@@ -450,34 +632,19 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 			   put it on wait again; perhaps splitting put_on_wait
 			   from send_reply or a new RPS_ code would be healthy
 			*/
-			if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
 			return RPS_COMPLETED;
 		}
-		/* look if the callback introduced new branches ... */
-		init_branch_iterator();
-		if (next_branch(&dummy)) {
-			if (t_forward_nonack(Trans, origin_rq,
-						(struct proxy_l *) 0,
-						Trans->uas.response.dst.proto)<0) {
-				/* error ... behave as if we did not try to
-				   add a new branch */
-				*should_store=0;
-				*should_relay=lowest_b;
-				if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
-				return RPS_COMPLETED;
-			}
-			/* we succeded to launch new branches -- await
-			   result
-			*/
+		/* look if the callback/failure_route introduced new branches ... */
+		if (branch_cnt<Trans->nr_of_outgoings)  {
+			/* await then result of new branches */
 			*should_store=1;
 			*should_relay=-1;
-			if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
 			return RPS_STORE;
 		}
+
 		/* really no more pending branches -- return lowest code */
 		*should_store=0;
-		*should_relay=lowest_b;
-		if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
+		*should_relay=picked_branch;
 		/* we dont need 'which_cancel' here -- all branches 
 		   known to have completed */
 		/* which_cancel( Trans, cancel_bitmap ); */
@@ -496,6 +663,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 		} else return RPS_PROVISIONAL;
 	}
 
+error:
 	/* reply_status didn't match -- it must be something weird */
 	LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay %d\n",
 		new_code);
@@ -567,150 +735,8 @@ int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code,
 }
 
 
-static inline void update_local_tags(struct cell *trans, 
-				struct bookmark *bm, char *dst_buffer,
-				char *src_buffer /* to which bm refers */)
-{
-	if (bm->to_tag_val.s) {
-		trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer;
-		trans->uas.local_totag.len=bm->to_tag_val.len;
-	}
-}
-
-
-static int _reply_light( struct cell *trans, char* buf, unsigned int len,
-			 unsigned int code, char * text, 
-			 char *to_tag, unsigned int to_tag_len, int lock,
-			 struct bookmark *bm	)
-{
-	struct retr_buf *rb;
-	unsigned int buf_len;
-	branch_bm_t cancel_bitmap;
-
-	if (!buf)
-	{
-		DBG("DEBUG: t_reply: response building failed\n");
-		/* determine if there are some branches to be cancelled */
-		if (trans->is_invite) {
-			if (lock) LOCK_REPLIES( trans );
-			which_cancel(trans, &cancel_bitmap );
-			if (lock) UNLOCK_REPLIES( trans );
-		}
-		/* and clean-up, including cancellations, if needed */
-		goto error;
-	}
-
-	cancel_bitmap=0;
-	if (lock) LOCK_REPLIES( trans );
-	if (trans->is_invite) which_cancel(trans, &cancel_bitmap );
-	if (trans->uas.status>=200) {
-		LOG( L_ERR, "ERROR: t_reply: can't generate %d reply"
-			" when a final %d was sent out\n", code, trans->uas.status);
-		goto error2;
-	}
-
 
-	rb = & trans->uas.response;
-	rb->activ_type=code;
 
-	trans->uas.status = code;
-	buf_len = rb->buffer ? len : len + REPLY_OVERBUFFER_LEN;
-	rb->buffer = (char*)shm_resize( rb->buffer, buf_len );
-	/* puts the reply's buffer to uas.response */
-	if (! rb->buffer ) {
-			LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n");
-			goto error3;
-	}
-	update_local_tags(trans, bm, rb->buffer, buf);
-
-	rb->buffer_len = len ;
-	memcpy( rb->buffer , buf , len );
-	/* needs to be protected too because what timers are set depends
-	   on current transactions status */
-	/* t_update_timers_after_sending_reply( rb ); */
-	update_reply_stats( code );
-	trans->relaied_reply_branch=-2;
-	tm_stats->replied_localy++;
-	if (lock) UNLOCK_REPLIES( trans );
-	
-	/* do UAC cleanup procedures in case we generated
-	   a final answer whereas there are pending UACs */
-	if (code>=200) {
-		if (trans->local) {
-			DBG("DEBUG: local transaction completed from _reply\n");
-			callback_event( TMCB_LOCAL_COMPLETED, trans, FAKED_REPLY, code );
-			if (trans->completion_cb) 
-				trans->completion_cb( trans, FAKED_REPLY, code, 0 /* empty param */);
-		} else {
-			callback_event( TMCB_RESPONSE_OUT, trans, FAKED_REPLY, code );
-		}
-
-		cleanup_uac_timers( trans );
-		if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
-		set_final_timer(  trans );
-	}
-
-	/* send it out */
-	/* first check if we managed to resolve topmost Via -- if
-	   not yet, don't try to retransmit
-	*/
-	if (!trans->uas.response.dst.send_sock) {
-		LOG(L_ERR, "ERROR: _reply: no resolved dst to send reply to\n");
-	} else {
-		SEND_PR_BUFFER( rb, buf, len );
-		DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n", 
-			buf, buf, rb->buffer, rb->buffer );
-	}
-	pkg_free( buf ) ;
-	DBG("DEBUG: t_reply: finished\n");
-	return 1;
-
-error3:
-error2:
-	if (lock) UNLOCK_REPLIES( trans );
-	pkg_free ( buf );
-error:
-	/* do UAC cleanup */
-	cleanup_uac_timers( trans );
-	if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
-	/* we did not succeed -- put the transaction on wait */
-	put_on_wait(trans);
-	return -1;
-}
-
-/* send a UAS reply
- * returns 1 if everything was OK or -1 for error
- */
-static int _reply( struct cell *trans, struct sip_msg* p_msg, 
-	unsigned int code, char * text, int lock )
-{
-	unsigned int len;
-	char * buf;
-	struct bookmark bm;
-
-	if (code>=200) set_kr(REQ_RPLD);
-	/* compute the buffer in private memory prior to entering lock;
-	 * create to-tag if needed */
-	if (code>=180 && p_msg->to 
-				&& (get_to(p_msg)->tag_value.s==0 
-			    || get_to(p_msg)->tag_value.len==0)) {
-		calc_crc_suffix( p_msg, tm_tag_suffix );
-		buf = build_res_buf_from_sip_req(code,text, 
-				tm_tags, TOTAG_VALUE_LEN, 
-				p_msg,&len, &bm);
-
-		return _reply_light(trans,buf,len,code,text,
-				    tm_tags, TOTAG_VALUE_LEN,
-				    lock, &bm);
-	} else {
-		buf = build_res_buf_from_sip_req(code,text, 0,0, /* no to-tag */
-			p_msg,&len, &bm);
-
-		return _reply_light(trans,buf,len,code,text,
-				    0,0, /* no to-tag */
-				    lock, &bm);
-	}
-}
 
 void set_final_timer( /* struct s_table *h_table, */ struct cell *t )
 {
@@ -1017,7 +1043,7 @@ error:
   *  Returns :   0 - core router stops
   *              1 - core router relay statelessly
   */
-int t_on_reply( struct sip_msg  *p_msg )
+int reply_received( struct sip_msg  *p_msg )
 {
 
 	int msg_status;
@@ -1068,6 +1094,13 @@ int t_on_reply( struct sip_msg  *p_msg )
 	if ( msg_status >= 200 )
 		reset_timer( &uac->request.fr_timer);
 
+	/* processing of on_reply block */
+	if (t->on_reply) {
+		rmode=MODE_ONREPLY;
+	 	if (run_actions(onreply_rlist[t->on_reply], p_msg)<0) 
+			LOG(L_ERR, "ERROR: on_reply processing failed\n");
+	}
+
 	LOCK_REPLIES( t );
 	if (t->local) {
 		reply_status=local_reply( t, p_msg, branch, msg_status, &cancel_bitmap );

+ 5 - 3
modules/tm/t_reply.h

@@ -51,7 +51,7 @@ enum rps {
 	RPS_PROVISIONAL
 };
 
-enum route_mode { MODE_REQUEST=1, MODE_ONREPLY_REQUEST };
+enum route_mode { MODE_REQUEST=1, MODE_ONREPLY, MODE_ONFAILURE };
 extern enum route_mode rmode;
 
 /* has this to-tag been never seen in previous 200/INVs? */
@@ -74,7 +74,7 @@ typedef int (*treply_wb_f)( struct cell* trans,
  * Returns :   0 - core router stops
  *             1 - core router relay statelessly
  */
-int t_on_reply( struct sip_msg  *p_msg ) ;
+int reply_received( struct sip_msg  *p_msg ) ;
 
 
 /* Retransmits the last sent inbound reply.
@@ -126,8 +126,10 @@ void on_negative_reply( struct cell* t, struct sip_msg* msg,
 /* set which 'reply' structure to take if only negative
    replies arrive 
 */
-int t_on_negative( unsigned int go_to );
+void t_on_negative( unsigned int go_to );
 unsigned int get_on_negative();
+void t_on_reply( unsigned int go_to );
+unsigned int get_on_reply();
 
 int t_retransmit_reply( struct cell *t );
 

+ 103 - 13
modules/tm/tm.c

@@ -62,6 +62,7 @@
  *  2003-03-16  flags export parameter added (janakj)
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
  *  2003-03-30  set_kr for requests only (jiri)
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
  */
 
 
@@ -125,6 +126,7 @@ inline static int w_t_forward_nonack_udp(struct sip_msg* msg, char* str,char*);
 inline static int w_t_forward_nonack_tcp(struct sip_msg* msg, char* str,char*);
 inline static int fixup_hostport2proxy(void** param, int param_no);
 inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo );
+inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo );
 
 
 static int mod_init(void);
@@ -135,23 +137,29 @@ static int child_init(int rank);
 static cmd_export_t cmds[]={
 	{"t_newtran",          w_t_newtran,             0, 0,                    REQUEST_ROUTE},
 	{"t_lookup_request",   w_t_check,               0, 0,                    REQUEST_ROUTE},
-	{T_REPLY,              w_t_reply,               2, fixup_t_send_reply,   REQUEST_ROUTE},
+	{T_REPLY,              w_t_reply,               2, fixup_t_send_reply,   
+			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"t_retransmit_reply", w_t_retransmit_reply,    0, 0,                    REQUEST_ROUTE},
 	{"t_release",          w_t_release,             0, 0,                    REQUEST_ROUTE},
-	{T_RELAY_TO,           w_t_relay_to,            2, fixup_hostport2proxy, REQUEST_ROUTE},
+	{T_RELAY_TO,           w_t_relay_to,            2, fixup_hostport2proxy, 
+			REQUEST_ROUTE | FAILURE_ROUTE },
 	{T_RELAY_TO_UDP,       w_t_relay_to_udp,        2, fixup_hostport2proxy, REQUEST_ROUTE},
 	{T_RELAY_TO_TCP,       w_t_relay_to_tcp,        2, fixup_hostport2proxy, REQUEST_ROUTE},
 	{"t_replicate",        w_t_replicate,           2, fixup_hostport2proxy, REQUEST_ROUTE},
 	{"t_replicate_udp",    w_t_replicate_udp,       2, fixup_hostport2proxy, REQUEST_ROUTE},
 	{"t_replicate_tcp",    w_t_replicate_tcp,       2, fixup_hostport2proxy, REQUEST_ROUTE},
-	{T_RELAY,              w_t_relay,               0, 0,                    REQUEST_ROUTE},
+	{T_RELAY,              w_t_relay,               0, 0,                    
+			REQUEST_ROUTE | FAILURE_ROUTE },
 	{T_RELAY_UDP,          w_t_relay_udp,           0, 0,                    REQUEST_ROUTE},
 	{T_RELAY_TCP,          w_t_relay_tcp,           0, 0,                    REQUEST_ROUTE},
 	{T_FORWARD_NONACK,     w_t_forward_nonack,      2, fixup_hostport2proxy, REQUEST_ROUTE},
 	{T_FORWARD_NONACK_UDP, w_t_forward_nonack_udp,  2, fixup_hostport2proxy, REQUEST_ROUTE},
 	{T_FORWARD_NONACK_TCP, w_t_forward_nonack_tcp,  2, fixup_hostport2proxy, REQUEST_ROUTE},
-	{"t_on_negative",      w_t_on_negative,         1, fixup_str2int,        REQUEST_ROUTE},
-	/* not applicable from the script -- ugly hack */
+	{"t_on_failure",       w_t_on_negative,         1, fixup_str2int,
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
+	{"t_on_reply",         w_t_on_reply,            1, fixup_str2int,
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
+	/* not applicable from the script */
 	{"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,     0, 0},
 	{T_UAC_DLG,            (cmd_function)t_uac_dlg,         NO_SCRIPT,     0, 0},
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,     0, 0},
@@ -191,7 +199,7 @@ struct module_exports exports= {
 	params,
 	
 	mod_init, /* module initialization function */
-	(response_function) t_on_reply,
+	(response_function) reply_received,
 	(destroy_function) tm_shutdown,
 	0, /* w_onbreak, */
 	child_init /* per-child init function */
@@ -234,9 +242,12 @@ static int script_init( struct sip_msg *foo, void *bar)
 	   		message's t_on_negative value
 		*/
 		t_on_negative( 0 );
-
+		t_on_reply(0);
 		/* reset the kr status */
 		set_kr(0);
+		/* set request mode so that multiple-mode actions know
+		 * how to behave */
+		rmode=MODE_REQUEST;
 	}
 
 	return 1;
@@ -456,11 +467,14 @@ inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2)
 	 * is called; we are already in a mutex and another mutex in
 	 * the safe version would lead to a deadlock
 	 */
-	if (rmode==MODE_ONREPLY_REQUEST) { 
+	if (rmode==MODE_ONFAILURE) { 
 		DBG("DEBUG: t_reply_unsafe called from w_t_reply\n");
 		return t_reply_unsafe(t, msg, (unsigned int)(long) str, str2);
-	} else {
+	} else if (rmode==MODE_REQUEST) {
 		return t_reply( t, msg, (unsigned int)(long) str, str2);
+	} else {
+		LOG(L_CRIT, "BUG: w_t_reply entered in unsupported mode\n");
+		return -1;
 	}
 }
 
@@ -516,15 +530,74 @@ inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar )
 
 inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo )
 {
-	return t_on_negative( (unsigned int )(long) go_to );
+	struct cell *t;
+
+	if (rmode==MODE_REQUEST || rmode==MODE_ONFAILURE) {
+		t_on_negative( (unsigned int )(long) go_to );
+		return 1;
+	}
+	if (rmode==MODE_ONREPLY ) {
+		/* transaction state is established */
+		t=get_t();
+		if (!t || t==T_UNDEFINED) {
+			LOG(L_CRIT, "BUG: w_t_on_negative entered without t\n");
+			return -1;
+		}
+		t->on_negative=(unsigned int)(long)go_to;
+		return 1;
+	}
+	LOG(L_CRIT, "BUG: w_t_on_negative entered in unsupported mode\n");
+	return -1;
+}
+inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo )
+{
+	struct cell *t;
+
+	if (rmode==MODE_REQUEST) {
+		/* it's still in initial request processing stage, transaction
+		 * state is not estabslihed yet, store it in private memory ...
+		 * it will be copied to transaction state when it is set up */
+		t_on_reply( (unsigned int )(long) go_to );
+		return 1;
+	}
+	if (rmode==MODE_ONREPLY || rmode==MODE_ONFAILURE) {
+		/* transaction state is established */
+		t=get_t();
+		if (!t || t==T_UNDEFINED) {
+			LOG(L_CRIT, "BUG: w_t_on_reply entered without t\n");
+			return -1;
+		}
+		t->on_reply=(unsigned int) (long)go_to;
+		return 1;
+	}
+	LOG(L_CRIT, "BUG: w_t_on_reply entered in unsupported mode\n");
+	return -1;
 }
 
 inline static int w_t_relay_to( struct sip_msg  *p_msg , 
 	char *proxy, /* struct proxy_l *proxy expected */
 	char *_foo       /* nothing expected */ )
 {
-	return t_relay_to( p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto,
-	0 /* no replication */ );
+	struct cell *t;
+
+	if (rmode==MODE_ONFAILURE) { 
+		t=get_t();
+		if (!t || t==T_UNDEFINED) {
+			LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
+			return -1;
+		}
+		if (t_forward_nonack(t, p_msg, 
+				( struct proxy_l *) proxy, p_msg->rcv.proto)<=0 ) {
+			LOG(L_ERR, "ERROR: failure_route: t_relay_to failed\n");
+			return -1;
+		}
+		return 1;
+	}
+	if (rmode==MODE_REQUEST) 
+		return t_relay_to( p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto,
+			0 /* no replication */ );
+	LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
+	return 0;
 }
 
 inline static int w_t_relay_to_udp( struct sip_msg  *p_msg , 
@@ -571,9 +644,26 @@ inline static int w_t_replicate_tcp( struct sip_msg  *p_msg ,
 inline static int w_t_relay( struct sip_msg  *p_msg , 
 						char *_foo, char *_bar)
 {
-	return t_relay_to( p_msg, 
+	struct cell *t;
+
+	if (rmode==MODE_ONFAILURE) { 
+		t=get_t();
+		if (!t || t==T_UNDEFINED) {
+			LOG(L_CRIT, "BUG: w_t_relay: undefined T\n");
+			return -1;
+		} 
+		if (t_forward_nonack(t, p_msg, ( struct proxy_l *) 0, p_msg->rcv.proto)<=0) {
+			LOG(L_ERR, "ERROR: w_t_relay (failure mode): forwarding failed\n");
+			return -1;
+		}
+		return 1;
+	}
+	if (rmode==MODE_REQUEST) 
+		return t_relay_to( p_msg, 
 		(struct proxy_l *) 0 /* no proxy */, p_msg->rcv.proto,
 		0 /* no replication */ );
+	LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
+	return 0;
 }
 
 

+ 3 - 0
modules/tm/uac.c

@@ -322,6 +322,9 @@ int t_uac_dlg(str* msg,                     /* Type of the message - MESSAGE, OP
 				|| !to || !to->s ) {
 		LOG(L_ERR, "ERROR: t_uac_dlg: invalid parameters\n");
 		ser_error = ret = E_INVALID_PARAMS;
+#ifdef XL_DEBUG
+		abort();
+#endif
 		goto done;
 	}
 

+ 27 - 9
route.c

@@ -35,6 +35,7 @@
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
  *  2003-04-01  added dst_port, proto, af; renamed comp_port to comp_no,
  *               inlined all the comp_* functions (andrei)
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
  */
 
  
@@ -63,7 +64,8 @@
 /* main routing script table  */
 struct action* rlist[RT_NO];
 /* reply routing table */
-struct action* reply_rlist[REPLY_RT_NO];
+struct action* onreply_rlist[ONREPLY_RT_NO];
+struct action* failure_rlist[FAILURE_RT_NO];
 
 
 static int fix_actions(struct action* a); /*fwd declaration*/
@@ -559,9 +561,16 @@ int fix_rls()
 			}
 		}
 	}
-	for(i=0;i<REPLY_RT_NO;i++){
-		if(reply_rlist[i]){
-			if ((ret=fix_actions(reply_rlist[i]))!=0){
+	for(i=0;i<ONREPLY_RT_NO;i++){
+		if(onreply_rlist[i]){
+			if ((ret=fix_actions(onreply_rlist[i]))!=0){
+				return ret;
+			}
+		}
+	}
+	for(i=0;i<FAILURE_RT_NO;i++){
+		if(failure_rlist[i]){
+			if ((ret=fix_actions(failure_rlist[i]))!=0){
 				return ret;
 			}
 		}
@@ -587,13 +596,22 @@ void print_rl()
 		}
 		DBG("\n");
 	}
-	for(j=0; j<REPLY_RT_NO; j++){
-		if (reply_rlist[j]==0){
-			if (j==0) DBG("WARNING: the main reply routing table is empty\n");
+	for(j=0; j<ONREPLY_RT_NO; j++){
+		if (onreply_rlist[j]==0){
 			continue;
 		}
-		DBG("routing table %d:\n",j);
-		for (t=reply_rlist[j],i=0; t; i++, t=t->next){
+		DBG("onreply routing table %d:\n",j);
+		for (t=onreply_rlist[j],i=0; t; i++, t=t->next){
+			print_action(t);
+		}
+		DBG("\n");
+	}
+	for(j=0; j<FAILURE_RT_NO; j++){
+		if (failure_rlist[j]==0){
+			continue;
+		}
+		DBG("failure routing table %d:\n",j);
+		for (t=failure_rlist[j],i=0; t; i++, t=t->next){
 			print_action(t);
 		}
 		DBG("\n");

+ 2 - 1
route.h

@@ -44,7 +44,8 @@
 /* main "script table" */
 extern struct action* rlist[RT_NO];
 /* main reply route table */
-extern struct action* reply_rlist[RT_NO];
+extern struct action* onreply_rlist[RT_NO];
+extern struct action* failure_rlist[RT_NO];
 
 
 void push(struct action* a, struct action** head);

+ 4 - 2
sr_module.h

@@ -32,6 +32,7 @@
  *  2003-03-10  changed module exports interface: added struct cmd_export
  *               and param_export (andrei)
  *  2003-03-16  Added flags field to cmd_export_ (janakj)
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
  */
 
 
@@ -55,8 +56,9 @@ typedef enum {
 	INT_PARAM,  /* Integer parameter type */
 } modparam_t;       /* Allowed types of parameters */
 
-#define REQUEST_ROUTE 1         /* Function can be used in request route blocks */
-#define REPLY_ROUTE 2           /* Function can be used in reply route blocks */
+#define REQUEST_ROUTE 1  /* Function can be used in request route blocks */
+#define FAILURE_ROUTE 2  /* Function can be used in reply route blocks */
+#define ONREPLY_ROUTE 4  /* Function can be used in on_reply */
 
 /* Macros - used as rank in child_init function */
 #define PROC_MAIN      0  /* Main ser process */