ソースを参照

- new config style: if expr cmd else cmd;
- expr can now contain commands (e.g: forward("proxy") && src_ip==1.2.3.4)
- introduced boolean values in expr. (yes/no; true/false; on/off; 1/0)
e.g.: if ( true ) log("...");
- changed name to ser, ser.cfg
- bumped ver. no (0.7)

Andrei Pelinescu-Onciul 24 年 前
コミット
f20a56a2b7
12 ファイル変更308 行追加201 行削除
  1. 2 2
      Makefile
  2. 5 3
      TODO
  3. 23 13
      action.c
  4. 6 2
      cfg.lex
  5. 90 37
      cfg.y
  6. 1 1
      config.h
  7. 8 2
      main.c
  8. 3 13
      receive.c
  9. 85 99
      route.c
  10. 7 21
      route.h
  11. 65 1
      route_struct.c
  12. 13 7
      route_struct.h

+ 2 - 2
Makefile

@@ -12,7 +12,7 @@ $(yacc_f)
 objs= $(sources:.c=.o)
 depends= $(sources:.c=.d)
 
-NAME=sip_router
+NAME=ser
 
 # compile-time options
 # NOCR disables seeking for CRs -- breaks standard but is fast
@@ -29,7 +29,7 @@ ARCH = $(shell uname -s)
 ifeq ($(ARCH), Linux)
 
 CC=gcc
-CFLAGS=-O2 -Wcast-align #-Wmissing-prototypes  -Wall
+CFLAGS=-O2 -Wcast-align #-Wmissing-prototypes 
 LEX=flex
 YACC=bison
 YACC_FLAGS=-d -b cfg

+ 5 - 3
TODO

@@ -1,19 +1,21 @@
 $Id$
 
+( - todo, x - done)
+
 - better Via parsing (handle ' ' in uri, eg: foo.bar : 1234 ; received=) and
  ipv6 addresses ([fec0:aa::01]).
 
 High priority:
-- if () {} else {}
+x if () {} else {}
+- ipv6 support
 - reply ("response line")
-- default route ?
 - drop ACKs for our replies
 - icmp error handling
-- ipv6 support
 - add To-tag (for the replies)
 - add User-Agent (for the replies)
 
 Low priority:
+- command line switch for checking the config file syntax
 - config file version (a la sendmail)
 - loop detection
 - cfg. file reload

+ 23 - 13
action.c

@@ -32,9 +32,9 @@
 int do_action(struct action* a, struct sip_msg* msg)
 {
 	int ret;
+	int v;
 	struct sockaddr_in* to;
 	struct proxy_l* p;
-	struct route_elem* re;
 	char* tmp;
 	char *new_uri, *end, *crt;
 	int len;
@@ -126,14 +126,7 @@ int do_action(struct action* a, struct sip_msg* msg)
 				ret=E_CFG;
 				break;
 			}
-			re=route_match(msg, &rlist[a->p1.number]);
-			if (re==0){
-				LOG(L_INFO, "WARNING: do_action: route(%d): no new route"
-						" found\n", a->p1.number);
-				ret=1;
-				break;
-			}
-			ret=((ret=run_actions(re->actions, msg))<0)?ret:1;
+			ret=((ret=run_actions(rlist[a->p1.number], msg))<0)?ret:1;
 			break;
 		case EXEC_T:
 			if (a->p1_type!=STRING_ST){
@@ -178,7 +171,6 @@ int do_action(struct action* a, struct sip_msg* msg)
 					ret=1;
 					break;
 				}
-
 				if (msg->new_uri) tmp=msg->new_uri;
 				else tmp=msg->first_line.u.request.uri;
 				if (parse_uri(tmp, strlen(tmp), &uri)<0){
@@ -264,7 +256,24 @@ int do_action(struct action* a, struct sip_msg* msg)
 				msg->new_uri=new_uri;
 				ret=1;
 				break;
-
+		case IF_T:
+				/* if null expr => ignore if? */
+				if ((a->p1_type==EXPR_ST)&&a->p1.data){
+					v=eval_expr((struct expr*)a->p1.data, msg);
+					if (v<0){
+						LOG(L_WARN,"WARNING: do_action:"
+									"error in expression\n");
+					}
+					ret=1; /* default is continue */
+					if (v==1){
+						if ((a->p2_type==ACTIONS_ST)&&a->p2.data){
+							ret=run_actions((struct action*)a->p2.data, msg);
+						}
+					}else if ((a->p3_type==ACTIONS_ST)&&a->p3.data){
+							ret=run_actions((struct action*)a->p3.data, msg);
+					}
+				}
+			break;
 		default:
 			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
 	}
@@ -278,7 +287,8 @@ error_uri:
 
 
 
-/* returns: 0 on success, -1 on error */
+/* returns: 0, or 1 on success, <0 on error */
+/* (0 if drop or break encountered, 1 if not ) */
 int run_actions(struct action* a, struct sip_msg* msg)
 {
 	struct action* t;
@@ -305,7 +315,7 @@ int run_actions(struct action* a, struct sip_msg* msg)
 	}
 	
 	rec_lev--;
-	return 0;
+	return ret;
 	
 
 error:

+ 6 - 2
cfg.lex

@@ -40,7 +40,7 @@
 
 /* action keywords */
 FORWARD	forward
-DROP	drop
+DROP	"drop"|"break"
 SEND	send
 LOG		log
 ERROR	error
@@ -52,6 +52,8 @@ SET_USER		"rewriteuser"|"setuser"|"setu"
 SET_USERPASS	"rewriteuserpass"|"setuserpass"|"setup"
 SET_PORT		"rewriteport"|"setport"|"setp"
 SET_URI			"rewriteuri"|"seturi"
+IF				"if"
+ELSE			"else"
 
 
 /* condition keywords */
@@ -127,6 +129,8 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{SET_USERPASS}	{ count(); yylval.strval=yytext; return SET_USERPASS; }
 <INITIAL>{SET_PORT}	{ count(); yylval.strval=yytext; return SET_PORT; }
 <INITIAL>{SET_URI}	{ count(); yylval.strval=yytext; return SET_URI; }
+<INITIAL>{IF}	{ count(); yylval.strval=yytext; return IF; }
+<INITIAL>{ELSE}	{ count(); yylval.strval=yytext; return ELSE; }
 
 <INITIAL>{METHOD}	{ count(); yylval.strval=yytext; return METHOD; }
 <INITIAL>{URI}	{ count(); yylval.strval=yytext; return URI; }
@@ -166,7 +170,7 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{SLASH}	{ count(); return SLASH; }
 <INITIAL>{DOT}		{ count(); return DOT; }
 <INITIAL>\\{CR}		{count(); } /* eat the escaped CR */
-<INITIAL>{CR}		{ count(); return CR; }
+<INITIAL>{CR}		{ count();/* return CR;*/ }
 
 
 <INITIAL>{QUOTES} { count(); state=STRING_S; BEGIN(STRING1); }

+ 90 - 37
cfg.y

@@ -12,6 +12,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <string.h>
 #include "route_struct.h"
 #include "globals.h"
 #include "route.h"
@@ -33,7 +34,6 @@ char* tmp;
 	struct expr* expr;
 	struct action* action;
 	struct net* net;
-	struct route_elem* route_el;
 }
 
 /* terminals */
@@ -53,6 +53,8 @@ char* tmp;
 %token SET_USERPASS
 %token SET_PORT
 %token SET_URI
+%token IF
+%token ELSE
 
 %token METHOD
 %token URI
@@ -100,13 +102,14 @@ char* tmp;
 
 
 /*non-terminals */
-%type <expr> exp, condition,  exp_elem
-%type <action> action, actions, cmd
+%type <expr> exp, exp_elem /*, condition*/
+%type <action> action, actions, cmd, if_cmd, stm
 %type <uval> ipv4
 %type <net> net4
 %type <strval> host
-%type <route_el> rules;
-%type <route_el> rule;
+/*%type <route_el> rules;
+  %type <route_el> rule;
+*/
 
 
 
@@ -145,43 +148,55 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
 		| LISTEN EQUAL ipv4  {
 								if (addresses_no < MAX_LISTEN){
 									tmp=inet_ntoa(*(struct in_addr*)&$3);
-									names[addresses_no]=(char*)malloc(strlen(tmp)+1);
+									names[addresses_no]=
+												(char*)malloc(strlen(tmp)+1);
 									if (names[addresses_no]==0){
-										LOG(L_CRIT, "ERROR: cfg. parser: out of memory.\n");
+										LOG(L_CRIT, "ERROR: cfg. parser: "
+														"out of memory.\n");
 									}else{
-										strncpy(names[addresses_no], tmp, strlen(tmp)+1);
+										strncpy(names[addresses_no], tmp,
+												strlen(tmp)+1);
 										addresses_no++;
 									}
 								}else{
-									LOG(L_CRIT, "ERROR: cfg. parser: too many listen addresses"
+									LOG(L_CRIT, "ERROR: cfg. parser:"
+												" too many listen addresses"
 												"(max. %d).\n", MAX_LISTEN);
 								}
 							  }
 		| LISTEN EQUAL ID	 {
 								if (addresses_no < MAX_LISTEN){
-									names[addresses_no]=(char*)malloc(strlen($3)+1);
+									names[addresses_no]=
+												(char*)malloc(strlen($3)+1);
 									if (names[addresses_no]==0){
-										LOG(L_CRIT, "ERROR: cfg. parser: out of memory.\n");
+										LOG(L_CRIT, "ERROR: cfg. parser:"
+														" out of memory.\n");
 									}else{
-										strncpy(names[addresses_no], $3, strlen($3)+1);
+										strncpy(names[addresses_no], $3,
+													strlen($3)+1);
 										addresses_no++;
 									}
 								}else{
-									LOG(L_CRIT, "ERROR: cfg. parser: too many listen addresses"
+									LOG(L_CRIT, "ERROR: cfg. parser: "
+												"too many listen addresses"
 												"(max. %d).\n", MAX_LISTEN);
 								}
 							  }
 		| LISTEN EQUAL STRING {
 								if (addresses_no < MAX_LISTEN){
-									names[addresses_no]=(char*)malloc(strlen($3)+1);
+									names[addresses_no]=
+										(char*)malloc(strlen($3)+1);
 									if (names[addresses_no]==0){
-										LOG(L_CRIT, "ERROR: cfg. parser: out of memory.\n");
+										LOG(L_CRIT, "ERROR: cfg. parser:"
+													" out of memory.\n");
 									}else{
-										strncpy(names[addresses_no], $3, strlen($3)+1);
+										strncpy(names[addresses_no], $3,
+												strlen($3)+1);
 										addresses_no++;
 									}
 								}else{
-									LOG(L_CRIT, "ERROR: cfg. parser: too many listen addresses"
+									LOG(L_CRIT, "ERROR: cfg. parser: "
+												"too many listen addresses"
 												"(max. %d).\n", MAX_LISTEN);
 								}
 							  }
@@ -206,9 +221,9 @@ ipv4:	NUMBER DOT NUMBER DOT NUMBER DOT NUMBER {
 												}
 	;
 
-route_stm:	ROUTE LBRACE rules RBRACE { push($3, &rlist[DEFAULT_RT]); }
+route_stm:	ROUTE LBRACE actions RBRACE { push($3, &rlist[DEFAULT_RT]); }
 
-		| ROUTE LBRACK NUMBER RBRACK LBRACE rules RBRACE { 
+		| ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE { 
 										if (($3<RT_NO) && ($3>=0)){
 											push($6, &rlist[$3]);
 										}else{
@@ -218,7 +233,7 @@ route_stm:	ROUTE LBRACE rules RBRACE { push($3, &rlist[DEFAULT_RT]); }
 										}
 		| ROUTE error { yyerror("invalid  route  statement"); }
 	;
-
+/*
 rules:	rules rule { push($2, &$1); $$=$1; }
 	| rule {$$=$1; }
 	| rules error { $$=0; yyerror("invalid rule"); }
@@ -231,12 +246,12 @@ rule:	condition	actions CR {
 									YYABORT;
 								}
 							  }
-	| CR  /* null rule */		{ $$=0;}
+	| CR		{ $$=0;}
 	| condition error { $$=0; yyerror("bad actions in rule"); }
 	;
 
 condition:	exp {$$=$1;}
-	;
+*/
 
 exp:	exp AND exp 	{ $$=mk_exp(AND_OP, $1, $3); }
 	| exp OR  exp		{ $$=mk_exp(OR_OP, $1, $3);  }
@@ -319,6 +334,8 @@ exp_elem:	METHOD EQUAL_T STRING	{$$= mk_elem(	EQUAL_OP, STRING_ST,
 		| DSTIP MATCH error  { $$=0; yyerror ( "hostname  expected" ); }
 		| DSTIP error { $$=0; 
 						yyerror("invalid operator, == or =~ expected");}
+		| stm				{ $$=mk_elem( NO_OP, ACTIONS_ST, ACTION_O, $1 ); }
+		| NUMBER		{$$=mk_elem( NO_OP, NUMBER_ST, NUMBER_O, (void*)$1 ); }
 	;
 
 net4:	ipv4 SLASH ipv4	{ $$=mk_net($1, $3); } 
@@ -326,7 +343,8 @@ net4:	ipv4 SLASH ipv4	{ $$=mk_net($1, $3); }
 								yyerror("invalid bit number in netmask");
 								$$=0;
 							}else{
-								$$=mk_net($1, htonl( ($3)?~( (1<<32-$3)-1 ):0 ) );
+								$$=mk_net($1, 
+										htonl( ($3)?~( (1<<(32-$3))-1 ):0 ) );
 							}
 						}
 	| ipv4				{ $$=mk_net($1, 0xffffffff); }
@@ -337,8 +355,8 @@ net4:	ipv4 SLASH ipv4	{ $$=mk_net($1, $3); }
 host:	ID				{ $$=$1; }
 	| host DOT ID		{ $$=(char*)malloc(strlen($1)+1+strlen($3)+1);
 						  if ($$==0){
-						  	LOG(L_CRIT, "ERROR: cfg. parser: memory allocation failure"
-						 				" while parsing host\n");
+						  	LOG(L_CRIT, "ERROR: cfg. parser: memory allocation"
+										" failure while parsing host\n");
 						  }else{
 						  	memcpy($$, $1, strlen($1));
 						  	$$[strlen($1)]='.';
@@ -351,6 +369,10 @@ host:	ID				{ $$=$1; }
 	;
 
 
+stm:		cmd						{ $$=$1; }
+		|	LBRACE actions RBRACE	{ $$=$2; }
+	;
+
 actions:	actions action	{$$=append_action($1, $2); }
 		| action			{$$=$1;}
 		| actions error { $$=0; yyerror("bad command"); }
@@ -361,6 +383,24 @@ action:		cmd SEMICOLON {$$=$1;}
 		| cmd error { $$=0; yyerror("bad command: missing ';'?"); }
 	;
 
+if_cmd:		IF exp stm				{ $$=mk_action3( IF_T,
+													 EXPR_ST,
+													 ACTIONS_ST,
+													 NOSUBTYPE,
+													 $2,
+													 $3,
+													 0);
+									}
+		|	IF exp stm ELSE stm		{ $$=mk_action3( IF_T,
+													 EXPR_ST,
+													 ACTIONS_ST,
+													 ACTIONS_ST,
+													 $2,
+													 $3,
+													 $5);
+									}
+	;
+
 cmd:		FORWARD LPAREN host RPAREN	{ $$=mk_action(	FORWARD_T,
 														STRING_ST,
 														NUMBER_ST,
@@ -472,24 +512,37 @@ cmd:		FORWARD LPAREN host RPAREN	{ $$=mk_action(	FORWARD_T,
 		| EXEC LPAREN STRING RPAREN	{ $$=mk_action(	EXEC_T, STRING_ST, 0,
 													$3, 0);
 									}
-		| SET_HOST LPAREN STRING RPAREN { $$=mk_action( SET_HOST_T, STRING_ST, 0, $3, 0); }
+		| SET_HOST LPAREN STRING RPAREN { $$=mk_action(SET_HOST_T, STRING_ST,
+														0, $3, 0); }
 		| SET_HOST error { $$=0; yyerror("missing '(' or ')' ?"); }
-		| SET_HOST LPAREN error RPAREN { $$=0; yyerror("bad argument, string expected"); }
-		| SET_HOSTPORT LPAREN STRING RPAREN { $$=mk_action( SET_HOSTPORT_T, STRING_ST, 0, $3, 0); }
+		| SET_HOST LPAREN error RPAREN { $$=0; yyerror("bad argument, "
+														"string expected"); }
+		| SET_HOSTPORT LPAREN STRING RPAREN { $$=mk_action( SET_HOSTPORT_T, 
+														STRING_ST, 0, $3, 0); }
 		| SET_HOSTPORT error { $$=0; yyerror("missing '(' or ')' ?"); }
-		| SET_HOSTPORT LPAREN error RPAREN { $$=0; yyerror("bad argument, string expected"); }
-		| SET_PORT LPAREN STRING RPAREN { $$=mk_action( SET_PORT_T, STRING_ST, 0, $3, 0); }
+		| SET_HOSTPORT LPAREN error RPAREN { $$=0; yyerror("bad argument,"
+												" string expected"); }
+		| SET_PORT LPAREN STRING RPAREN { $$=mk_action( SET_PORT_T, STRING_ST,
+														0, $3, 0); }
 		| SET_PORT error { $$=0; yyerror("missing '(' or ')' ?"); }
-		| SET_PORT LPAREN error RPAREN { $$=0; yyerror("bad argument, string expected"); }
-		| SET_USER LPAREN STRING RPAREN { $$=mk_action( SET_USER_T, STRING_ST, 0, $3, 0); }
+		| SET_PORT LPAREN error RPAREN { $$=0; yyerror("bad argument, "
+														"string expected"); }
+		| SET_USER LPAREN STRING RPAREN { $$=mk_action( SET_USER_T, STRING_ST,
+														0, $3, 0); }
 		| SET_USER error { $$=0; yyerror("missing '(' or ')' ?"); }
-		| SET_USER LPAREN error RPAREN { $$=0; yyerror("bad argument, string expected"); }
-		| SET_USERPASS LPAREN STRING RPAREN { $$=mk_action( SET_USERPASS_T, STRING_ST, 0, $3, 0); }
+		| SET_USER LPAREN error RPAREN { $$=0; yyerror("bad argument, "
+														"string expected"); }
+		| SET_USERPASS LPAREN STRING RPAREN { $$=mk_action( SET_USERPASS_T, 
+														STRING_ST, 0, $3, 0); }
 		| SET_USERPASS error { $$=0; yyerror("missing '(' or ')' ?"); }
-		| SET_USERPASS LPAREN error RPAREN { $$=0; yyerror("bad argument, string expected"); }
-		| SET_URI LPAREN STRING RPAREN { $$=mk_action( SET_URI_T, STRING_ST, 0, $3, 0); }
+		| SET_USERPASS LPAREN error RPAREN { $$=0; yyerror("bad argument, "
+														"string expected"); }
+		| SET_URI LPAREN STRING RPAREN { $$=mk_action( SET_URI_T, STRING_ST, 
+														0, $3, 0); }
 		| SET_URI error { $$=0; yyerror("missing '(' or ')' ?"); }
-		| SET_URI LPAREN error RPAREN { $$=0; yyerror("bad argument, string expected"); }
+		| SET_URI LPAREN error RPAREN { $$=0; yyerror("bad argument, "
+										"string expected"); }
+		| if_cmd		{ $$=$1; }
 	;
 
 

+ 1 - 1
config.h

@@ -10,7 +10,7 @@
 /* default sip port if none specified */
 #define SIP_PORT 5060
 
-#define CFG_FILE "./sip_router.cfg"
+#define CFG_FILE "./ser.cfg"
 
 /* receive buffer size */
 #define BUF_SIZE 65507

+ 8 - 2
main.c

@@ -30,7 +30,7 @@
 
 
 static char id[]="@(#) $Id$";
-static char version[]="sip_router 0.6";
+static char version[]="ser 0.7";
 static char flags[]="NOCR:"
 #ifdef NOCR
 "On"
@@ -46,7 +46,7 @@ static char flags[]="NOCR:"
 ;
 
 static char help_msg[]= "\
-Usage: sip_router -l address [-l address] [options]\n\
+Usage: ser -l address [-l address] [options]\n\
 Options:\n\
     -f file      Configuration file (default " CFG_FILE ")\n\
     -p port      Listen on the specified port (default: 5060)\n\
@@ -345,6 +345,12 @@ int main(int argc, char** argv)
 	
 	
 	print_rl();
+	/* fix routing lists */
+	if ( (r=fix_rls())!=0){
+		fprintf(stderr, "ERROR: error %x while trying to fix configuration\n",
+						r);
+		goto error;
+	};
 
 	/* fix parameters */
 	if (port_no<=0) port_no=SIP_PORT;

+ 3 - 13
receive.c

@@ -19,7 +19,6 @@
 int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
 {
 	struct sip_msg msg;
-	struct route_elem *re;
 
 	memset(&msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
 	/* fill in msg */
@@ -46,19 +45,10 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
 		}
 		/* check if neccesarry to add receive? */
 		
-		/* find route */
-		re=route_match( &msg, &rlist[0]);
-		if (re==0){
-			/* no route found, send back error msg? */
-			LOG(L_WARN, "WARNING: receive_msg: no route found!\n");
-			goto skip;
-		}
-		re->tx++;
-		/* send msg */
-		DBG(" found route \n");
-		if (run_actions(re->actions, &msg)<0){
+		/* exec routing script */
+		if (run_actions(rlist[0], &msg)<0){
 			LOG(L_WARN, "WARNING: receive_msg: "
-					"error while trying actions\n");
+					"error while trying script\n");
 			goto error;
 		}
 	}else if (msg.first_line.type==SIP_REPLY){

+ 85 - 99
route.c

@@ -18,78 +18,17 @@
 #include "route.h"
 #include "dprint.h"
 #include "proxy.h"
+#include "action.h"
 
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
 
-/* main routing list */
-struct route_elem* rlist[RT_NO];
+/* main routing script table  */
+struct action* rlist[RT_NO];
 
 
-
- void free_re(struct route_elem* r)
-{
-	/*int i;*/
-	if (r){
-		/*
-			regfree(&(r->method));
-			regfree(&(r->uri));
-			
-			if (r->host.h_name)      free(r->host.h_name);
-			if (r->host.h_aliases){
-				for (i=0; r->host.h_aliases[i]; i++)
-					free(r->host.h_aliases[i]);
-				free(r->host.h_aliases);
-			}
-			if (r->host.h_addr_list){
-				for (i=0; r->host.h_addr_list[i]; i++)
-					free(r->host.h_addr_list[i]);
-				free(r->host.h_addr_list);
-			}
-		*/
-			free(r);
-	}
-}
-
-
-
-struct route_elem* init_re()
-{
-	struct route_elem* r;
-	r=(struct route_elem *) malloc(sizeof(struct route_elem));
-	if (r==0) return 0;
-	memset((void*)r, 0, sizeof (struct route_elem));
-	return r;
-}
-
-
-/* adds re list to head; re must be null terminated (last re->next=0))*/
-void push(struct route_elem* re, struct route_elem** head)
-{
-	struct route_elem *t;
-	if (*head==0){
-		*head=re;
-		return;
-	}
-	for (t=*head; t->next;t=t->next);
-	t->next=re;
-}
-
-
-
-void clear_rlist(struct route_elem** rl)
-{
-	struct route_elem *t, *u;
-
-	if (*rl==0) return;
-	u=0;
-	for (t=*rl; t; u=t, t=t->next){
-		if (u) free_re(u);
-	}
-	*rl=0;
-}
-
+static int fix_actions(struct action* a); /*fwd declaration*/
 
 
 /* traverses an expr tree and compiles the REs where necessary) 
@@ -99,6 +38,7 @@ static int fix_expr(struct expr* exp)
 	regex_t* re;
 	int ret;
 	
+	ret=E_BUG;
 	if (exp==0){
 		LOG(L_CRIT, "BUG: fix_expr: null pointer\n");
 		return E_BUG;
@@ -143,6 +83,13 @@ static int fix_expr(struct expr* exp)
 					return E_BUG;
 				}
 			}
+			if (exp->l.operand==ACTION_O){
+				ret=fix_actions((struct action*)exp->r.param);
+				if (ret!=0){
+					LOG(L_CRIT, "ERROR: fix_expr : fix_actions error\n");
+					return ret;
+				}
+			}
 			ret=0;
 	}
 	return ret;
@@ -151,12 +98,18 @@ static int fix_expr(struct expr* exp)
 
 
 /* adds the proxies in the proxy list & resolves the hostnames */
+/* returns 0 if ok, <0 on error */
 static int fix_actions(struct action* a)
 {
 	struct action *t;
 	struct proxy_l* p;
 	char *tmp;
+	int ret;
 	
+	if (a==0){
+		LOG(L_CRIT,"BUG: fix_actions: null pointer\n");
+		return E_BUG;
+	}
 	for(t=a; t!=0; t=t->next){
 		switch(t->type){
 			case FORWARD_T:
@@ -187,6 +140,36 @@ static int fix_actions(struct action* a)
 							return E_BUG;
 					}
 					break;
+		case IF_T:
+				if (t->p1_type!=EXPR_ST){
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+								"%d for if (should be expr)\n",
+								t->p1_type);
+					return E_BUG;
+				}else if( (t->p2_type!=ACTIONS_ST)&&(t->p2_type!=NOSUBTYPE) ){
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+								"%d for if() {...} (should be action)\n",
+								t->p2_type);
+					return E_BUG;
+				}else if( (t->p3_type!=ACTIONS_ST)&&(t->p3_type!=NOSUBTYPE) ){
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+								"%d for if() {} else{...}(should be action)\n",
+								t->p3_type);
+					return E_BUG;
+				}
+				if (t->p1.data){
+					if ((ret=fix_expr((struct expr*)t->p1.data))<0)
+						return ret;
+				}
+				if ( (t->p2_type==ACTIONS_ST)&&(t->p2.data) ){
+					if ((ret=fix_actions((struct action*)t->p2.data))<0)
+						return ret;
+				}
+				if ( (t->p3_type==ACTIONS_ST)&&(t->p3.data) ){
+						if ((ret=fix_actions((struct action*)t->p3.data))<0)
+						return ret;
+				}
+				break;
 		}
 	}
 	return 0;
@@ -277,6 +260,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 {
 
 	int ret;
+	ret=E_BUG;
 	
 	if (e->type!=ELEM_T){
 		LOG(L_CRIT," BUG: eval_elem: invalid type\n");
@@ -302,8 +286,11 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 		case DSTIP_O:
 				ret=comp_ip(msg->dst_ip, e->r.param, e->op, e->subtype);
 				break;
-		case DEFAULT_O:
-				ret=1;
+		case NUMBER_O:
+				ret=!(!e->r.intval); /* !! to transform it in {0,1} */
+				break;
+		case ACTION_O:
+				ret=(run_actions( (struct action*)e->r.param, msg)>=0)?1:0;
 				break;
 		default:
 				LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
@@ -316,7 +303,8 @@ error:
 
 
 
-static int eval_expr(struct expr* e, struct sip_msg* msg)
+/* ret= 0/1 (true/false) & -1 on error */
+int eval_expr(struct expr* e, struct sip_msg* msg)
 {
 	static int rec_lev=0;
 	int ret;
@@ -365,53 +353,56 @@ skip:
 }
 
 
+/* adds an action list to head; a must be null terminated (last a->next=0))*/
+void push(struct action* a, struct action** head)
+{
+	struct action *t;
+	if (*head==0){
+		*head=a;
+		return;
+	}
+	for (t=*head; t->next;t=t->next);
+	t->next=a;
+}
+
+
 
 
-int add_rule(struct expr* e, struct action* a, struct route_elem** head)
+int add_actions(struct action* a, struct action** head)
 {
-	
-	struct route_elem* re;
 	int ret;
 
-	re=init_re();
-	if (re==0) return E_OUT_OF_MEM;
-	LOG(L_DBG, "add_rule: fixing expr...\n");
-	if ((ret=fix_expr(e))!=0) goto error;
-	LOG(L_DBG, "add_rule: fixing actions...\n");
+	LOG(L_DBG, "add_actions: fixing actions...\n");
 	if ((ret=fix_actions(a))!=0) goto error;
-	re->condition=e;
-	re->actions=a;
-	
-	push(re,head);
+	push(a,head);
 	return 0;
 	
 error:
-	free_re(re);
 	return ret;
 }
 
 
 
-struct route_elem* route_match(struct sip_msg* msg, struct route_elem** rl)
+/* fixes all action tables */
+/* returns 0 if ok , <0 on error */
+int fix_rls()
 {
-	struct route_elem* t;
-	if (*rl==0){
-		LOG(L_ERR, "WARNING: route_match: empty routing table\n");
-		return 0;
-	}
-	for (t=*rl; t; t=t->next){
-		if (eval_expr(t->condition, msg)==1) return t;
+	int i,ret;
+	for(i=0;i<RT_NO;i++){
+		if(rlist[i]){
+			if ((ret=fix_actions(rlist[i]))!=0){
+				return ret;
+			}
+		}
 	}
-	/* no match :( */
 	return 0;
 }
 
 
-
 /* debug function, prints main routing table */
 void print_rl()
 {
-	struct route_elem* t;
+	struct action* t;
 	int i,j;
 
 	for(j=0; j<RT_NO; j++){
@@ -421,15 +412,10 @@ void print_rl()
 		}
 		DBG("routing table %d:\n",j);
 		for (t=rlist[j],i=0; t; i++, t=t->next){
-			DBG("%2d.condition: ",i);
-			print_expr(t->condition);
-			DBG("\n  -> ");
-			print_action(t->actions);
-			DBG("\n    Statistics: tx=%d, errors=%d, tx_bytes=%d\n",
-					t->tx, t->errors, t->tx_bytes);
+			print_action(t);
 		}
+		DBG("\n");
 	}
-
 }
 
 

+ 7 - 21
route.h

@@ -17,31 +17,17 @@
 /*#include "cfg_parser.h" */
 
 
+/* main "script table" */
+extern struct action* rlist[RT_NO];
 
-struct route_elem{
-	struct route_elem* next;
 
-	struct expr* condition;
-	struct action* actions;
-
-	int ok; /* set to 0 if an error was found sendig a pkt*/
-	/*counters*/
-	int errors;
-	int tx;
-	int tx_bytes;
-};
-
-/* main "routing table" */
-extern struct route_elem* rlist[RT_NO];
+void push(struct action* a, struct action** head);
+int add_actions(struct action* a, struct action** head);
+void print_rl();
+int fix_rls();
 
+int eval_expr(struct expr* e, struct sip_msg* msg);
 
-void free_re(struct route_elem* re);
-struct route_elem* init_re();
-void push(struct route_elem* re, struct route_elem** head);
-void clear_rlist(struct route_elem** rl);
-int add_rule(struct expr* e, struct action* a, struct route_elem** head);
-struct route_elem* route_match(struct sip_msg* msg,struct route_elem** rl);
-void print_rl();
 
 
 

+ 65 - 1
route_struct.c

@@ -72,6 +72,21 @@ error:
 }
 
 
+struct action* mk_action3(int type, int p1_type, int p2_type, int p3_type,
+							void* p1, void* p2, void* p3)
+{
+	struct action* a;
+
+	a=mk_action(type, p1_type, p2_type, p1, p2);
+	if (a){
+			a->p3_type=p3_type;
+			a->p3.data=p3;
+	}
+	return a;
+}
+
+
+
 struct action* append_action(struct action* a, struct action* b)
 {
 	struct action *t;
@@ -142,6 +157,11 @@ void print_expr(struct expr* exp)
 			case DSTIP_O:
 				DBG("dstip");
 				break;
+			case NUMBER_O:
+				break;
+			case ACTION_O:
+				print_action((struct action*) exp->r.param);
+				break;
 			default:
 				DBG("UNKNOWN");
 		}
@@ -152,6 +172,8 @@ void print_expr(struct expr* exp)
 			case MATCH_OP:
 				DBG("=~");
 				break;
+			case NO_OP:
+				break;
 			default:
 				DBG("<UNKNOWN>");
 		}
@@ -168,6 +190,12 @@ void print_expr(struct expr* exp)
 			case IP_ST:
 					print_ip(exp->r.intval);
 					break;
+			case ACTIONS_ST:
+					print_action((struct action*)exp->r.param);
+					break;
+			case NUMBER_ST:
+					DBG("%d",exp->r.intval);
+					break;
 			default:
 					DBG("type<%d>", exp->subtype);
 		}
@@ -248,6 +276,9 @@ void print_action(struct action* a)
 			case SET_URI_T:
 					DBG("seturi(");
 					break;
+			case IF_T:
+					DBG("if (");
+					break;
 			default:
 					DBG("UNKNOWN(");
 		}
@@ -261,9 +292,16 @@ void print_action(struct action* a)
 			case IP_ST:
 					print_ip(t->p1.number);
 					break;
+			case EXPR_ST:
+					print_expr((struct expr*)t->p1.data);
+					break;
+			case ACTIONS_ST:
+					print_action((struct action*)t->p1.data);
+					break;
 			default:
 					DBG("type<%d>", t->p1_type);
 		}
+		if (t->type==IF_T) DBG(") {");
 		switch(t->p2_type){
 			case NOSUBTYPE:
 					break;
@@ -273,10 +311,36 @@ void print_action(struct action* a)
 			case NUMBER_ST:
 					DBG(", %d",t->p2.number);
 					break;
+			case EXPR_ST:
+					print_expr((struct expr*)t->p2.data);
+					break;
+			case ACTIONS_ST:
+					print_action((struct action*)t->p2.data);
+					break;
 			default:
 					DBG(", type<%d>", t->p2_type);
 		}
-		DBG("); ");
+		if (t->type==IF_T) DBG("} else {");
+		switch(t->p3_type){
+			case NOSUBTYPE:
+					break;
+			case STRING_ST:
+					DBG(", \"%s\"", t->p3.string);
+					break;
+			case NUMBER_ST:
+					DBG(", %d",t->p3.number);
+					break;
+			case EXPR_ST:
+					print_expr((struct expr*)t->p3.data);
+					break;
+			case ACTIONS_ST:
+					print_action((struct action*)t->p3.data);
+					break;
+			default:
+					DBG(", type<%d>", t->p3_type);
+		}
+		if (t->type==IF_T) DBG("}; ");
+		else	DBG("); ");
 	}
 }
 			

+ 13 - 7
route_struct.h

@@ -8,12 +8,14 @@
 
 enum { EXP_T=1, ELEM_T };
 enum { AND_OP=1, OR_OP, NOT_OP };
-enum { EQUAL_OP=10, MATCH_OP };
-enum { METHOD_O=1, URI_O, SRCIP_O, DSTIP_O, DEFAULT_O };
+enum { EQUAL_OP=10, MATCH_OP, NO_OP };
+enum { METHOD_O=1, URI_O, SRCIP_O, DSTIP_O, DEFAULT_O, ACTION_O, NUMBER_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, SET_PORT_T, SET_URI_T};
-enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST };
+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, 
+		SET_PORT_T, SET_URI_T, IF_T };
+enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
+		EXPR_ST, ACTIONS_ST };
 
 	
 struct expr{
@@ -36,11 +38,12 @@ struct action{
 	int type;  /* forward, drop, log, send ...*/
 	int p1_type;
 	int p2_type;
+	int p3_type;
 	union {
 		int number;
 		char* string;
 		void* data;
-	}p1, p2;
+	}p1, p2, p3;
 	struct action* next;
 };
 
@@ -52,7 +55,10 @@ struct net{
 
 struct expr* mk_exp(int op, struct expr* left, struct expr* right);
 struct expr* mk_elem(int op, int subtype, int operand, void* param);
-struct action* mk_action(int type, int p1_type, int p2_type, void* p1, void* p2);
+struct action* mk_action(int type, int p1_type, int p2_type,
+							void* p1, void* p2);
+struct action* mk_action3(int type, int p1_type, int p2_type, int p3_type, 
+							void* p1, void* p2, void* p3);
 struct action* append_action(struct action* a, struct action* b);