- return [val] support (returns from the current route with value val, by
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 12 Dec 2005 23:47:56 +0000 (23:47 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 12 Dec 2005 23:47:56 +0000 (23:47 +0000)
 default 1)
- exit [val] support (exits the script with code val, where 0 means drop,
 >0 means do default actions and <0 means error)
- drop is now equivalent to exit 0
- drop should be faster when used to exit deep routes
- break is now equivalent with return 1
- the return code can be checked with $?, e.g.:
   if ($?==1) {...} else if ($?==-1){...} else {...}.

NEWS
action.c
action.h
cfg.lex
cfg.y
route.c
route_struct.h

diff --git a/NEWS b/NEWS
index cfcc46b..fc2b19d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -41,6 +41,15 @@ modules:
               Vias a.s.o) and not on the original message
  
 core:
+ - added return [val] which returns from a route. if no value is specified, or
+   a route reaches its end without executing a return statement, it returns 1.
+   If return is used in the top level route is equivalent with exit [val].
+ - drop /exit [n] now will end the script execution
+   exit n will exit with code n (usefull in onreply/onsend routes where
+   if script code !=0 a reply is generated/the message is sent or to force
+   script errors)
+ - added $? which can be used to check the return code of the last executed
+   route{} (e.g. route(1); if ($?==1){ /* ... */}else if ($?==2) ... )
  - onsend_route added: special route executed before a request is sent.
                        Only a limited number of commands are allowed (drop, if
                        + all the checks, msg flag manipulations, send(), log(),
index 928e7ff..d81cf3e 100644 (file)
--- a/action.c
+++ b/action.c
@@ -37,6 +37,7 @@
  *  2003-10-02  added SET_ADV_ADDR_T & SET_ADV_PORT_T (andrei)
  *  2003-10-29  added FORCE_TCP_ALIAS_T (andrei)
  *  2004-11-30  added FORCE_SEND_SOCKET_T (andrei)
+ *  2005-12-12  return & drop/exit differentiation (andrei)
  */
 
 
 #include <arpa/inet.h>
 #include <string.h>
 
+#define USE_LONGJMP
+
+#ifdef USE_LONGJMP
+#include <setjmp.h>
+#endif
+
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
 
 
 struct onsend_info* p_onsend=0; /* onsend route send info */
+static unsigned int run_flags=0;
+int last_retcode=0; /* last return from a route() */
 
 /* ret= 0! if action -> end of list(e.g DROP), 
       > 0 to continue processing next actions
@@ -108,7 +117,11 @@ int do_action(struct action* a, struct sip_msg* msg)
        ret=E_BUG;
        switch ((unsigned char)a->type){
                case DROP_T:
-                               ret=0;
+                               if (a->p1_type==RETCODE_ST)
+                                       ret=last_retcode;
+                               else
+                                       ret=(int)a->p1.number;
+                               run_flags|=(unsigned int)a->p2.number;
                        break;
                case FORWARD_T:
 #ifdef USE_TCP
@@ -385,7 +398,10 @@ int do_action(struct action* a, struct sip_msg* msg)
                                ret=E_CFG;
                                break;
                        }
-                       ret=((ret=run_actions(rlist[a->p1.number], msg))<0)?ret:1;
+                       /*ret=((ret=run_actions(rlist[a->p1.number], msg))<0)?ret:1;*/
+                       ret=run_actions(rlist[a->p1.number], msg);
+                       last_retcode=ret;
+                       run_flags&=~RETURN_R_F; /* absorb returns */
                        break;
                case EXEC_T:
                        if (a->p1_type!=STRING_ST){
@@ -597,6 +613,7 @@ int do_action(struct action* a, struct sip_msg* msg)
                                /* if null expr => ignore if? */
                                if ((a->p1_type==EXPR_ST)&&a->p1.data){
                                        v=eval_expr((struct expr*)a->p1.data, msg);
+#if 0
                                        if (v<0){
                                                if (v==EXPR_DROP){ /* hack to quit on DROP*/
                                                        ret=0;
@@ -606,7 +623,12 @@ int do_action(struct action* a, struct sip_msg* msg)
                                                                                "error in expression\n");
                                                }
                                        }
-                                       
+#endif
+                                       if (run_flags & EXIT_R_F){
+                                               ret=0;
+                                               break;
+                                       }
+                                       run_flags &= ~RETURN_R_F; /* catch returns in expr */
                                        ret=1;  /*default is continue */
                                        if (v>0) {
                                                if ((a->p2_type==ACTIONS_ST)&&a->p2.data){
@@ -622,6 +644,7 @@ int do_action(struct action* a, struct sip_msg* msg)
                                        ((a->p2_type==STRING_ST)&&a->p2.data)*/ ){
                                ret=((cmd_function)(a->p1.data))(msg, (char*)a->p2.data,
                                                                                                          (char*)a->p3.data);
+                               if (ret==0) run_flags|=EXIT_R_F;
                        }else{
                                LOG(L_CRIT,"BUG: do_action: bad module call\n");
                        }
@@ -787,6 +810,7 @@ int run_actions(struct action* a, struct sip_msg* msg)
        struct action* t;
        int ret=E_UNSPEC;
        static int rec_lev=0;
+       static jmp_buf jmp_env;
        struct sr_module *mod;
 
        rec_lev++;
@@ -796,6 +820,15 @@ int run_actions(struct action* a, struct sip_msg* msg)
                ret=E_UNSPEC;
                goto error;
        }
+       if (rec_lev==1){
+               run_flags=0;
+               last_retcode=0;
+               if (setjmp(jmp_env)){
+                       rec_lev=0;
+                       ret=last_retcode;
+                       goto end;
+               }
+       }
                
        if (a==0){
                LOG(L_ERR, "WARNING: run_actions: null action list (rec_level=%d)\n", 
@@ -805,12 +838,18 @@ int run_actions(struct action* a, struct sip_msg* msg)
 
        for (t=a; t!=0; t=t->next){
                ret=do_action(t, msg);
-               if(ret==0) break;
-               /* ignore errors */
-               /*else if (ret<0){ ret=-1; goto error; }*/
+               if (run_flags & (RETURN_R_F|EXIT_R_F)){
+                       if (run_flags & EXIT_R_F){
+                               last_retcode=ret;
+                               longjmp(jmp_env, ret);
+                       }
+                       break;
+               }
+               /* ignore error returns */
        }
        
        rec_lev--;
+end:
        /* process module onbreak handlers if present */
        if (rec_lev==0 && ret==0) 
                for (mod=modules;mod;mod=mod->next) 
index a05ed3a..759bfd2 100644 (file)
--- a/action.h
+++ b/action.h
@@ -33,6 +33,8 @@
 #include "parser/msg_parser.h"
 #include "route_struct.h"
 
+extern int last_retcode;
+
 int do_action(struct action* a, struct sip_msg* msg);
 int run_actions(struct action* a, struct sip_msg* msg);
 
diff --git a/cfg.lex b/cfg.lex
index 318cca9..7fb3599 100644 (file)
--- a/cfg.lex
+++ b/cfg.lex
@@ -58,6 +58,7 @@
  *              dns_try_ipv6 (andrei)
  *  2005-12-11  added onsend_route, snd_{ip,port,proto,af},
  *              to_{ip,port} (andrei)
+ *  2005-12-12  separated drop, exit, break, return, added RETCODE (andrei)
  */
 
 
@@ -108,7 +109,9 @@ FORWARD     forward
 FORWARD_TCP    forward_tcp
 FORWARD_UDP    forward_udp
 FORWARD_TLS    forward_tls
-DROP   "drop"|"break"
+DROP   "drop"|"exit"
+RETURN "return"
+BREAK  "break"
 SEND   send
 SEND_TCP       send_tcp
 LOG            log
@@ -171,6 +174,7 @@ PROTO       proto
 AF             af
 MYSELF myself
 MSGLEN                 "msg:len"
+RETCODE        \$\?|\$retcode
 /* operators */
 EQUAL  =
 EQUAL_T        ==
@@ -323,6 +327,8 @@ EAT_ABLE    [\ \t\b\r]
 <INITIAL>{FORWARD_TLS} {count(); yylval.strval=yytext; return FORWARD_TLS; }
 <INITIAL>{FORWARD_UDP} {count(); yylval.strval=yytext; return FORWARD_UDP; }
 <INITIAL>{DROP}        { count(); yylval.strval=yytext; return DROP; }
+<INITIAL>{RETURN}      { count(); yylval.strval=yytext; return RETURN; }
+<INITIAL>{BREAK}       { count(); yylval.strval=yytext; return BREAK; }
 <INITIAL>{SEND}        { count(); yylval.strval=yytext; return SEND; }
 <INITIAL>{SEND_TCP}    { count(); yylval.strval=yytext; return SEND_TCP; }
 <INITIAL>{LOG} { count(); yylval.strval=yytext; return LOG_TOK; }
@@ -331,6 +337,7 @@ EAT_ABLE    [\ \t\b\r]
 <INITIAL>{RESETFLAG}   { count(); yylval.strval=yytext; return RESETFLAG; }
 <INITIAL>{ISFLAGSET}   { count(); yylval.strval=yytext; return ISFLAGSET; }
 <INITIAL>{MSGLEN}      { count(); yylval.strval=yytext; return MSGLEN; }
+<INITIAL>{RETCODE}     { count(); yylval.strval=yytext; return RETCODE; }
 <INITIAL>{ROUTE}       { count(); yylval.strval=yytext; return ROUTE; }
 <INITIAL>{ROUTE_ONREPLY}       { count(); yylval.strval=yytext;
                                                                return ROUTE_ONREPLY; }
diff --git a/cfg.y b/cfg.y
index 6dc1bfc..f4f6ab9 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -150,6 +150,8 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token SEND
 %token SEND_TCP
 %token DROP
+%token RETURN 
+%token BREAK
 %token LOG_TOK
 %token ERROR
 %token ROUTE
@@ -200,6 +202,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token AF
 %token MYSELF
 %token MSGLEN 
+%token RETCODE 
 %token UDP
 %token TCP
 %token TLS
@@ -1055,6 +1058,13 @@ exp_elem:        METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
                | MSGLEN intop error { $$=0; yyerror("number expected"); }
                | MSGLEN error { $$=0; yyerror("equal/!= operator expected"); }
 
+               | RETCODE intop NUMBER  { $$=mk_elem($2, RETCODE_O, 0,
+                                                                                               NUMBER_ST, (void *) $3 ); }
+               | RETCODE intop attr_id { $$=mk_elem($2, RETCODE_O, 0,
+                                                                                               AVP_ST, (void *) $3 ); }
+               | RETCODE intop error { $$=0; yyerror("number expected"); }
+               | RETCODE error { $$=0; yyerror("equal/!= operator expected"); }
+
                | SRCIP equalop ipnet   { $$=mk_elem($2, SRCIP_O, 0, NET_ST, $3); }
                | SRCIP strop STRING    {       s_tmp.s=$3;
                                                                        s_tmp.len=strlen($3);
@@ -1742,8 +1752,24 @@ cmd:             FORWARD LPAREN host RPAREN      { $$=mk_action( FORWARD_T,
                | SEND_TCP error { $$=0; yyerror("missing '(' or ')' ?"); }
                | SEND_TCP LPAREN error RPAREN { $$=0; yyerror("bad send_tcp"
                                                                                                        "argument"); }
-               | DROP LPAREN RPAREN    {$$=mk_action(DROP_T,0, 0, 0, 0); }
-               | DROP                                  {$$=mk_action(DROP_T,0, 0, 0, 0); }
+               | DROP LPAREN RPAREN    {$$=mk_action(DROP_T,0, 0,
+                                                                                               0, (void*)EXIT_R_F); }
+               | DROP LPAREN NUMBER RPAREN     {$$=mk_action(DROP_T,0, 0,
+                                                                                               (void*)$3, (void*)EXIT_R_F); }
+               | DROP NUMBER                   {$$=mk_action(DROP_T,0, 0,
+                                                                                               (void*)$2, (void*)EXIT_R_F); }
+               | DROP RETCODE                  {$$=mk_action(DROP_T, RETCODE_ST, 0,
+                                                                                                       0, (void*)EXIT_R_F); }
+               | DROP                                  {$$=mk_action(DROP_T,0, 0,
+                                                                                               0, (void*)EXIT_R_F); }
+               | RETURN                                {$$=mk_action(DROP_T,0, 0,
+                                                                                               (void*)1, (void*)RETURN_R_F); }
+               | RETURN NUMBER                 {$$=mk_action(DROP_T,0, 0, 
+                                                                                               (void*)$2, (void*)RETURN_R_F);}
+               | RETURN RETCODE                {$$=mk_action(DROP_T, RETCODE_ST, 0, 
+                                                                                                               0, (void*)RETURN_R_F);}
+               | BREAK                                 {$$=mk_action(DROP_T,0, 0,
+                                                                                               0, (void*)RETURN_R_F); }
                | LOG_TOK LPAREN STRING RPAREN  {$$=mk_action(  LOG_T, NUMBER_ST, 
                                                                                                        STRING_ST,(void*)4,$3);
                                                                        }
diff --git a/route.c b/route.c
index 7bcac23..2cc2e98 100644 (file)
--- a/route.c
+++ b/route.c
@@ -40,6 +40,7 @@
  *              the ip with all the addresses (andrei)
  *  2003-10-10  added more operators support to comp_* (<,>,<=,>=,!=) (andrei)
  *  2004-10-19  added from_uri & to_uri (andrei)
+ *  2005-12-12  added retcode support (anrei)
  */
 
  
@@ -640,7 +641,7 @@ error_op:
 }
 
 
-/* returns: 0/1 (false/true) or -1 on error, -127 EXPR_DROP */
+/* returns: 0/1 (false/true) or -1 on error */
 static int eval_elem(struct expr* e, struct sip_msg* msg)
 {
        struct sip_uri uri;
@@ -757,7 +758,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 
        case ACTION_O:
                ret=run_actions( (struct action*)e->r.param, msg);
-               if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
+               if (ret<=0) ret=0;
                else ret=1;
                break;
                
@@ -831,6 +832,10 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
                }
                break;
 
+       case RETCODE_O:
+               ret=comp_num(e->op, last_retcode, e->r_type, &e->r);
+               break;
+
        case AVP_O:
                ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r);
                break;
@@ -846,7 +851,7 @@ error:
 
 
 
-/* ret= 0/1 (true/false) ,  -1 on error or EXPR_DROP (-127)  */
+/* ret= 0/1 (true/false) ,  -1 on error */
 int eval_expr(struct expr* e, struct sip_msg* msg)
 {
        static int rec_lev=0;
index 5b52e57..5f9048d 100644 (file)
@@ -62,7 +62,7 @@ enum { EQUAL_OP=10, MATCH_OP, GT_OP, LT_OP, GTE_OP, LTE_OP, DIFF_OP, NO_OP };
 enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O,
           DSTIP_O, DSTPORT_O, PROTO_O, AF_O, MSGLEN_O, DEFAULT_O, ACTION_O,
           NUMBER_O, AVP_O, SNDIP_O, SNDPORT_O, TOIP_O, TOPORT_O, SNDPROTO_O, 
-          SNDAF_O};
+          SNDAF_O, RETCODE_O};
 
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
                SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, 
@@ -88,7 +88,12 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
 };
 enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
                EXPR_ST, ACTIONS_ST, CMDF_ST, MODFIXUP_ST, URIHOST_ST, URIPORT_ST,
-               MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST };
+               MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST,
+               RETCODE_ST};
+
+/* run flags */
+#define EXIT_R_F   1
+#define RETURN_R_F 2
 
 
 /* Expression operand */