s/reply_route/failure_route, onreply_route introduced
authorJiri Kuthan <jiri@iptel.org>
Mon, 7 Apr 2003 06:36:56 +0000 (06:36 +0000)
committerJiri Kuthan <jiri@iptel.org>
Mon, 7 Apr 2003 06:36:56 +0000 (06:36 +0000)
15 files changed:
NEWS
cfg.lex
cfg.y
config.h
examples/onr.cfg
modules/tm/h_table.h
modules/tm/t_fwd.c
modules/tm/t_lookup.c
modules/tm/t_reply.c
modules/tm/t_reply.h
modules/tm/tm.c
modules/tm/uac.c
route.c
route.h
sr_module.h

diff --git a/NEWS b/NEWS
index 73a8996..8714d09 100644 (file)
--- a/NEWS
+++ b/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)
diff --git a/cfg.lex b/cfg.lex
index 588df80..1742c28 100644 (file)
--- a/cfg.lex
+++ b/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; }
diff --git a/cfg.y b/cfg.y
index 3c58127..d6f86ad 100644 (file)
--- a/cfg.y
+++ b/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; }
index b7e99c5..c707b5f 100644 (file)
--- a/config.h
+++ b/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 */
index ef04271..822368d 100644 (file)
@@ -39,20 +39,20 @@ route{
        seturi("sip:nobody@iptel.org");
        append_branch("sip:parallel@iptel.org: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:nonsense@iptel.org");
        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:foo@iptel.org");
        log(1, "second redirection\n");
index 808739a..f865cb6 100644 (file)
@@ -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
        */
index 72cfd98..7686039 100644 (file)
@@ -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 */
index 1a0a4d1..b04140a 100644 (file)
@@ -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();
 
                        }
 
index 4dea563..ac3853c 100644 (file)
@@ -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 );
index 1b2ae44..af0979b 100644 (file)
@@ -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 );
 
index f347121..4bade4f 100644 (file)
@@ -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;
 }
 
 
index 36dd178..3d89cb2 100644 (file)
@@ -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;
        }
 
diff --git a/route.c b/route.c
index 8c0b7d9..8915c63 100644 (file)
--- a/route.c
+++ b/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");
diff --git a/route.h b/route.h
index 6ba5414..6d0b5c5 100644 (file)
--- a/route.h
+++ b/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);
index f742c95..5d403a0 100644 (file)
@@ -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 */