Browse Source

- return [val] support (returns from the current route with value val, by
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 {...}.

Andrei Pelinescu-Onciul 20 years ago
parent
commit
01dea12497
7 changed files with 107 additions and 14 deletions
  1. 9 0
      NEWS
  2. 45 6
      action.c
  3. 2 0
      action.h
  4. 8 1
      cfg.lex
  5. 28 2
      cfg.y
  6. 8 3
      route.c
  7. 7 2
      route_struct.h

+ 9 - 0
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(),

+ 45 - 6
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)
  */
 
 
@@ -70,12 +71,20 @@
 #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) 

+ 2 - 0
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);
 

+ 8 - 1
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; }

+ 28 - 2
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);
 									}

+ 8 - 3
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;

+ 7 - 2
route_struct.h

@@ -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 */