Browse Source

New script element, Jan's select function framework (@xxx), extended for
modular use. In the script it can be used as value assigned to AVP and
in the string comparision, RE matching, like:
[email protected][1];
if (@via.protocol=="UDP")...

The name to called function conversion is implemented as tree in a table,
modules can register their own tables in module initialization function.

Description of the construction of the table expected to follow soon in the
documentation files...

Michal Matyska 20 years ago
parent
commit
3fb428edb4
10 changed files with 417 additions and 27 deletions
  1. 14 0
      action.c
  2. 21 2
      cfg.lex
  3. 61 7
      cfg.y
  4. 61 12
      route.c
  5. 14 3
      route_struct.c
  6. 5 3
      route_struct.h
  7. 129 0
      select.c
  8. 95 0
      select.h
  9. 3 0
      select_core.c
  10. 14 0
      select_core.h

+ 14 - 0
action.c

@@ -770,6 +770,20 @@ int do_action(struct action* a, struct sip_msg* msg)
 				}
 				}
 				ret = 1;
 				ret = 1;
 				break;
 				break;
+			} else if (a->p2_type == SELECT_ST) {
+				int r;
+				r = run_select(&value.s, a->p2.select, msg);
+				if (r < 0) {
+					ret=E_UNSPEC;
+					break;
+				} else if (r > 0) {
+					value.s.s = "";
+					value.s.len = 0;
+				}
+
+				flags = a->p1.attr->type | AVP_VAL_STR;
+				name = a->p1.attr->name;
+				ret = 1;
 			} else {
 			} else {
 				LOG(L_CRIT, "BUG: do_action: Bad right side of avp assignment\n");
 				LOG(L_CRIT, "BUG: do_action: Bad right side of avp assignment\n");
 				ret=E_BUG;
 				ret=E_BUG;

+ 21 - 2
cfg.lex

@@ -70,6 +70,7 @@
 	#include <stdlib.h>
 	#include <stdlib.h>
 	#include "ip_addr.h"
 	#include "ip_addr.h"
 	#include "usr_avp.h"
 	#include "usr_avp.h"
+	#include "select.h"
 	#include "cfg.tab.h"
 	#include "cfg.tab.h"
 
 
 	/* states */
 	/* states */
@@ -78,6 +79,7 @@
 	#define COMMENT_LN_S	        2
 	#define COMMENT_LN_S	        2
 	#define STRING_S		3
 	#define STRING_S		3
 	#define ATTR_S                  4
 	#define ATTR_S                  4
+        #define SELECT_S                5
 
 
 	#define STR_BUF_ALLOC_UNIT	128
 	#define STR_BUF_ALLOC_UNIT	128
 	struct str_buf{
 	struct str_buf{
@@ -102,7 +104,7 @@
 %}
 %}
 
 
 /* start conditions */
 /* start conditions */
-%x STRING1 STRING2 COMMENT COMMENT_LN ATTR
+%x STRING1 STRING2 COMMENT COMMENT_LN ATTR SELECT
 
 
 /* action keywords */
 /* action keywords */
 FORWARD	forward
 FORWARD	forward
@@ -194,7 +196,8 @@ PLUS	"+"
 MINUS	"-"
 MINUS	"-"
 
 
 /* Attribute specification */
 /* Attribute specification */
-ATTR_MARK   "$"|"%"|"@"
+ATTR_MARK   "$"|"%"
+SELECT_MARK  "@"
 ATTR_FROM   "from"|"f"
 ATTR_FROM   "from"|"f"
 ATTR_TO     "to"|"t"
 ATTR_TO     "to"|"t"
 ATTR_USER   "user"|"u"
 ATTR_USER   "user"|"u"
@@ -501,6 +504,22 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{PLUS}		{ count(); return PLUS; }
 <INITIAL>{PLUS}		{ count(); return PLUS; }
 <INITIAL>{MINUS}	{ count(); return MINUS; }
 <INITIAL>{MINUS}	{ count(); return MINUS; }
 
 
+<INITIAL>{SELECT_MARK}  { count(); state = SELECT_S; BEGIN(SELECT); return SELECT_MARK; }
+<SELECT>{ID}		{ count(); addstr(&s_buf, yytext, yyleng); 
+                          yylval.strval=s_buf.s;
+                          memset(&s_buf, 0, sizeof(s_buf));
+                          return ID; 
+                        }
+<SELECT>{DOT}           { count(); return DOT; }
+<SELECT>{LBRACK}        { count(); return LBRACK; }
+<SELECT>{RBRACK}        { count(); return RBRACK; }
+<SELECT>{DECNUMBER}	{ count(); yylval.intval=atoi(yytext);return NUMBER; }
+<SELECT>{HEXNUMBER}	{ count(); yylval.intval=(int)strtol(yytext, 0, 16); return NUMBER; }
+<SELECT>{OCTNUMBER}	{ count(); yylval.intval=(int)strtol(yytext, 0, 8); return NUMBER; }
+<SELECT>{BINNUMBER}     { count(); yylval.intval=(int)strtol(yytext, 0, 2); return NUMBER; }
+<SELECT>.               { unput(yytext[0]); state = INITIAL_S; BEGIN(INITIAL); } /* Rescan the token in INITIAL state */
+
+
 <INITIAL>{ATTR_MARK}    { count(); state = ATTR_S; BEGIN(ATTR); return ATTR_MARK; }
 <INITIAL>{ATTR_MARK}    { count(); state = ATTR_S; BEGIN(ATTR); return ATTR_MARK; }
 <ATTR>{ATTR_FROM}       { count(); return ATTR_FROM; }
 <ATTR>{ATTR_FROM}       { count(); return ATTR_FROM; }
 <ATTR>{ATTR_TO}         { count(); return ATTR_TO; }
 <ATTR>{ATTR_TO}         { count(); return ATTR_TO; }

+ 61 - 7
cfg.y

@@ -91,6 +91,7 @@
 #include "name_alias.h"
 #include "name_alias.h"
 #include "ut.h"
 #include "ut.h"
 #include "dset.h"
 #include "dset.h"
+#include "select.h"
 
 
 #include "config.h"
 #include "config.h"
 #ifdef USE_TLS
 #ifdef USE_TLS
@@ -121,6 +122,9 @@ static str* str_tmp;
 static str s_tmp;
 static str s_tmp;
 static struct ip_addr* ip_tmp;
 static struct ip_addr* ip_tmp;
 static struct avp_spec* s_attr;
 static struct avp_spec* s_attr;
+static select_t sel;
+static select_t* sel_ptr;
+
 
 
 static void warn(char* s);
 static void warn(char* s);
 static struct socket_id* mk_listen_id(char*, int, int);
 static struct socket_id* mk_listen_id(char*, int, int);
@@ -137,6 +141,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 	struct ip_addr* ipaddr;
 	struct ip_addr* ipaddr;
 	struct socket_id* sockid;
 	struct socket_id* sockid;
 	struct avp_spec* attr;
 	struct avp_spec* attr;
+	select_t* select;
 }
 }
 
 
 /* terminals */
 /* terminals */
@@ -279,6 +284,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token TOS
 %token TOS
 
 
 %token ATTR_MARK
 %token ATTR_MARK
+%token SELECT_MARK
 %token ATTR_FROM
 %token ATTR_FROM
 %token ATTR_TO
 %token ATTR_TO
 %token ATTR_USER
 %token ATTR_USER
@@ -340,6 +346,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %type <attr> attr_id
 %type <attr> attr_id
 %type <intval> class_id
 %type <intval> class_id
 %type <intval> assign_op
 %type <intval> assign_op
+%type <select> select_id
 /*%type <route_el> rules;
 /*%type <route_el> rules;
   %type <route_el> rule;
   %type <route_el> rule;
 */
 */
@@ -979,6 +986,7 @@ uri_type:	URI			{$$=URI_O;}
 
 
 exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
 exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
                 | METHOD strop attr_id  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
                 | METHOD strop attr_id  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
+                | METHOD strop select_id {$$ = mk_elem($2, METHOD_O, 0, SELECT_ST, $3); }
 		| METHOD strop  ID	{$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
 		| METHOD strop  ID	{$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
 		| METHOD strop error { $$=0; yyerror("string expected"); }
 		| METHOD strop error { $$=0; yyerror("string expected"); }
 		| METHOD error	{ $$=0; yyerror("invalid operator,"
 		| METHOD error	{ $$=0; yyerror("invalid operator,"
@@ -987,6 +995,7 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
 		| uri_type strop STRING	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
 		| uri_type strop STRING	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
                 | uri_type strop host 	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
                 | uri_type strop host 	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
                 | uri_type strop attr_id {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
                 | uri_type strop attr_id {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
+                | uri_type strop select_id {$$ = mk_elem($2, $1, 0, SELECT_ST, $3); }
                 | uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
                 | uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
 		| uri_type strop error { $$=0; yyerror("string or MYSELF expected"); }
 		| uri_type strop error { $$=0; yyerror("string or MYSELF expected"); }
 		| uri_type error	{ $$=0; yyerror("invalid operator,"
 		| uri_type error	{ $$=0; yyerror("invalid operator,"
@@ -1193,9 +1202,15 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
 
 
 		| attr_id		{$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); }
 		| attr_id		{$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); }
 		| attr_id strop STRING	{$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); }
 		| attr_id strop STRING	{$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); }
+		| attr_id strop select_id {$$=mk_elem( $2, AVP_O, (void*)$1, SELECT_ST, $3); }
 		| attr_id intop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
 		| attr_id intop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
 		| attr_id binop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
 		| attr_id binop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
-		| attr_id strop attr_id {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
+                | attr_id strop attr_id {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
+
+                | select_id                 { $$=mk_elem( NO_OP, SELECT_O, $1, 0, 0); }
+		| select_id strop STRING    { $$=mk_elem( $2, SELECT_O, $1, STRING_ST, $3); }
+		| select_id strop attr_id   { $$=mk_elem( $2, SELECT_O, $1, AVP_ST, (void*)$3); }
+		| select_id strop select_id { $$=mk_elem( $2, SELECT_O, $1, SELECT_ST, $3); }
 ;
 ;
 
 
 
 
@@ -1310,39 +1325,77 @@ class_id : LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; }
          | LBRACK ATTR_GLOBAL RBRACK { $$ = AVP_CLASS_GLOBAL; }
          | LBRACK ATTR_GLOBAL RBRACK { $$ = AVP_CLASS_GLOBAL; }
 ;
 ;
 
 
+select_param : ID { 
+		    if (sel.n >= MAX_SELECT_PARAMS-1) {
+			    yyerror("Select identifier too long\n");
+		    }
+		    sel.params[sel.n].type = PARAM_STR; 
+		    sel.params[sel.n].v.s.s = $1;
+		    sel.params[sel.n].v.s.len = strlen($1);
+		    sel.n++;
+                  }
+             | ID LBRACK NUMBER RBRACK {
+		     if (sel.n >= MAX_SELECT_PARAMS-2) {
+			    yyerror("Select identifier too long\n");
+		     }
+		     sel.params[sel.n].type = PARAM_STR;
+		     sel.params[sel.n].v.s.s = $1;
+		     sel.params[sel.n].v.s.len = strlen($1);
+		     sel.n++;
+		     sel.params[sel.n].type = PARAM_INT;
+		     sel.params[sel.n].v.i = $3;
+		     sel.n++;
+	     }
+;
+
+select_params : select_params DOT select_param
+              | select_param
+;
+
+select_id : SELECT_MARK { sel.n = 0; sel.f = 0; } select_params {
+//	if (resolve_select(&sel) < 0) yyerror("Unable to resolve select");
+	sel_ptr = (select_t*)pkg_malloc(sizeof(select_t));
+	if (!sel_ptr) {
+		yyerror("No memory left to allocate select structure\n");
+	}
+	memcpy(sel_ptr, &sel, sizeof(select_t));
+	$$ = sel_ptr;
+}
+;
+
 attr_id : ATTR_MARK ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
 attr_id : ATTR_MARK ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
-                         if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                         if (!s_attr) { yyerror("No memory left"); }
                          s_attr->type = AVP_NAME_STR;                   
                          s_attr->type = AVP_NAME_STR;                   
                          s_attr->name.s.s = $2; s_attr->name.s.len = strlen($2); 
                          s_attr->name.s.s = $2; s_attr->name.s.len = strlen($2); 
                          $$ = s_attr; 
                          $$ = s_attr; 
                        }
                        }
         | ATTR_MARK class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
         | ATTR_MARK class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
-                                      if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                      if (!s_attr) { yyerror("No memory left"); }
                                       s_attr->type = AVP_NAME_STR | $2;
                                       s_attr->type = AVP_NAME_STR | $2;
                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
                                       $$ = s_attr; 
                                       $$ = s_attr; 
                                     }
                                     }
         | ATTR_MARK ATTR_FROM DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
         | ATTR_MARK ATTR_FROM DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
-                                       if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                       if (!s_attr) { yyerror("No memory left"); }
                                        s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM;
                                        s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM;
                                        s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
                                        s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
                                        $$ = s_attr;
                                        $$ = s_attr;
                                      }
                                      }
         | ATTR_MARK ATTR_TO DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
         | ATTR_MARK ATTR_TO DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
-                                     if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                     if (!s_attr) { yyerror("No memory left"); }
                                      s_attr->type = AVP_NAME_STR | AVP_TRACK_TO; 
                                      s_attr->type = AVP_NAME_STR | AVP_TRACK_TO; 
                                      s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
                                      s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
                                      $$ = s_attr;
                                      $$ = s_attr;
                                    }
                                    }
         | ATTR_MARK ATTR_FROM class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
         | ATTR_MARK ATTR_FROM class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
-                                               if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                               if (!s_attr) { yyerror("No memory left"); }
                                                s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | $3; 
                                                s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | $3; 
                                                s_attr->name.s.s = $5; 
                                                s_attr->name.s.s = $5; 
                                                s_attr->name.s.len = strlen($5);
                                                s_attr->name.s.len = strlen($5);
                                                $$ = s_attr;
                                                $$ = s_attr;
                                               }
                                               }
         | ATTR_MARK ATTR_TO class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
         | ATTR_MARK ATTR_TO class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
-                                              if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                              if (!s_attr) { yyerror("No memory left"); }
                                               s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | $3;
                                               s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | $3;
                                               s_attr->name.s.s = $5; s_attr->name.s.len = strlen($5);
                                               s_attr->name.s.s = $5; s_attr->name.s.len = strlen($5);
                                              $$ = s_attr;
                                              $$ = s_attr;
@@ -1357,6 +1410,7 @@ assign_action:   attr_id assign_op STRING  { $$=mk_action($2, AVP_ST, STRING_ST,
                | attr_id assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
                | attr_id assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
                | attr_id assign_op fcmd    { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
                | attr_id assign_op fcmd    { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
                | attr_id assign_op attr_id { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
                | attr_id assign_op attr_id { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
+               | attr_id assign_op select_id { $$=mk_action($2, AVP_ST, SELECT_ST, (void*)$1, (void*)$3); }
                | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
                | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
 ;
 ;
 
 

+ 61 - 12
route.c

@@ -67,9 +67,9 @@
 #include "parser/parse_from.h"
 #include "parser/parse_from.h"
 #include "parser/parse_to.h"
 #include "parser/parse_to.h"
 #include "mem/mem.h"
 #include "mem/mem.h"
+#include "select.h"
 #include "onsend.h"
 #include "onsend.h"
 
 
-
 /* main routing script table  */
 /* main routing script table  */
 struct action* rlist[RT_NO];
 struct action* rlist[RT_NO];
 /* reply routing table */
 /* reply routing table */
@@ -132,7 +132,7 @@ static int fix_expr(struct expr* exp)
 					pkg_free(exp->r.param);
 					pkg_free(exp->r.param);
 					exp->r.re=re;
 					exp->r.re=re;
 					exp->r_type=RE_ST;
 					exp->r_type=RE_ST;
-				}else if (exp->r_type!=RE_ST && exp->r_type != AVP_ST){
+				}else if (exp->r_type!=RE_ST && exp->r_type != AVP_ST && exp->r_type != SELECT_ST){
 					LOG(L_CRIT, "BUG: fix_expr : invalid type for match\n");
 					LOG(L_CRIT, "BUG: fix_expr : invalid type for match\n");
 					return E_BUG;
 					return E_BUG;
 				}
 				}
@@ -159,6 +159,20 @@ static int fix_expr(struct expr* exp)
 				exp->r.str.s = exp->r.string;
 				exp->r.str.s = exp->r.string;
 				exp->r.str.len = len;
 				exp->r.str.len = len;
 			}
 			}
+			if (exp->l_type==SELECT_O) {
+				if ((ret=resolve_select(exp->l.select)) < 0) {
+					BUG("Unable to resolve select\n");
+					print_select(exp->l.select);
+					return ret;
+				}
+			}
+			if ((exp->r_type==SELECT_O)||(exp->r_type==SELECT_ST)) {
+				if ((ret=resolve_select(exp->r.select)) < 0) {
+					BUG("Unable to resolve select\n");
+					print_select(exp->l.select);
+					return ret;
+				}
+			}
 			ret=0;
 			ret=0;
 	}
 	}
 	return ret;
 	return ret;
@@ -280,6 +294,12 @@ static int fix_actions(struct action* a)
 					len = strlen(t->p2.data);
 					len = strlen(t->p2.data);
 					t->p2.str.s = t->p2.data;
 					t->p2.str.s = t->p2.data;
 					t->p2.str.len = len;
 					t->p2.str.len = len;
+				} else if (t->p2_type == SELECT_ST) {
+					if ((ret=resolve_select(t->p2.select)) < 0) {
+						BUG("Unable to resolve select\n");
+						print_select(t->p2.select);
+						return ret;
+					}
 				}
 				}
 				break;
 				break;
 
 
@@ -372,10 +392,11 @@ inline static int comp_num(int op, long left, int rtype, union exp_op* r)
 /*
 /*
  * Compare given string "left" with right side of expression
  * Compare given string "left" with right side of expression
  */
  */
-inline static int comp_str(int op, str* left, int rtype, union exp_op* r)
+inline static int comp_str(int op, str* left, int rtype, union exp_op* r, struct sip_msg* msg)
 {
 {
 	str* right;
 	str* right;
 	int_str val;
 	int_str val;
+	str v;
 	avp_t* avp;
 	avp_t* avp;
 	int ret;
 	int ret;
 	char backup;
 	char backup;
@@ -387,6 +408,11 @@ inline static int comp_str(int op, str* left, int rtype, union exp_op* r)
 		avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
 		avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
 		if (avp && (avp->flags & AVP_VAL_STR)) right = &val.s;
 		if (avp && (avp->flags & AVP_VAL_STR)) right = &val.s;
 		else return 0;
 		else return 0;
+	} else if (rtype == SELECT_ST) {
+		ret = run_select(&v, r->select, msg);
+		if (ret > 0) return 0;       /* Not found */
+		else if (ret < 0) goto error; /* Error */
+		right = &v;
 	} else if ((op == MATCH_OP && rtype == RE_ST)) {
 	} else if ((op == MATCH_OP && rtype == RE_ST)) {
 	} else if (op != MATCH_OP && rtype == STRING_ST) {
 	} else if (op != MATCH_OP && rtype == STRING_ST) {
 		right = &r->str;
 		right = &r->str;
@@ -424,7 +450,7 @@ inline static int comp_str(int op, str* left, int rtype, union exp_op* r)
 			      */
 			      */
 			backup=left->s[left->len];
 			backup=left->s[left->len];
 			left->s[left->len]='\0';
 			left->s[left->len]='\0';
-			if (rtype == AVP_ST) {
+			if (rtype == AVP_ST || rtype == SELECT_ST) {
 				     /* For AVPs we need to compile the RE on the fly */
 				     /* For AVPs we need to compile the RE on the fly */
 				re=(regex_t*)pkg_malloc(sizeof(regex_t));
 				re=(regex_t*)pkg_malloc(sizeof(regex_t));
 				if (re==0){
 				if (re==0){
@@ -499,7 +525,7 @@ error:
 }
 }
 
 
 
 
-inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r)
+inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r, struct sip_msg* msg)
 {
 {
 	avp_t* avp;
 	avp_t* avp;
 	int_str val;
 	int_str val;
@@ -526,14 +552,33 @@ inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r)
 	}
 	}
 
 
 	if (avp->flags & AVP_VAL_STR) {
 	if (avp->flags & AVP_VAL_STR) {
-		return comp_str(op, &val.s, rtype, r);
+		return comp_str(op, &val.s, rtype, r, msg);
 	} else {
 	} else {
 		return comp_num(op, val.n, rtype, r);
 		return comp_num(op, val.n, rtype, r);
 	}
 	}
 }
 }
 
 
+/*
+ * Left side of expression was select
+ */
+inline static int comp_select(int op, select_t* sel, int rtype, union exp_op* r, struct sip_msg* msg)
+{
+	int ret;
+	str val;
 
 
+	ret = run_select(&val, sel, msg);
+	if (ret < 0) return -1;
+	if (ret > 0) return 0;
 
 
+	switch(op) {
+	case NO_OP: return 1;
+	case BINOR_OP:
+	case BINAND_OP:  
+		ERR("Binary operators cannot be used with string selects\n");
+		return -1;
+	}
+	return comp_str(op, &val, rtype, r, msg);
+}
 
 
 /* check_self wrapper -- it checks also for the op */
 /* check_self wrapper -- it checks also for the op */
 inline static int check_self_op(int op, str* s, unsigned short p)
 inline static int check_self_op(int op, str* s, unsigned short p)
@@ -657,7 +702,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 	switch(e->l_type){
 	switch(e->l_type){
 	case METHOD_O:
 	case METHOD_O:
 		ret=comp_str(e->op, &msg->first_line.u.request.method, 
 		ret=comp_str(e->op, &msg->first_line.u.request.method, 
-			     e->r_type, &e->r);
+			     e->r_type, &e->r, msg);
 		break;
 		break;
 	case URI_O:
 	case URI_O:
 		if(msg->new_uri.s) {
 		if(msg->new_uri.s) {
@@ -668,7 +713,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 						       msg->parsed_uri.port_no:SIP_PORT);
 						       msg->parsed_uri.port_no:SIP_PORT);
 			}else{
 			}else{
 				ret=comp_str(e->op, &msg->new_uri, 
 				ret=comp_str(e->op, &msg->new_uri, 
-					     e->r_type, &e->r);
+					     e->r_type, &e->r, msg);
 			}
 			}
 		}else{
 		}else{
 			if (e->r_type==MYSELF_ST){
 			if (e->r_type==MYSELF_ST){
@@ -678,7 +723,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 						       msg->parsed_uri.port_no:SIP_PORT);
 						       msg->parsed_uri.port_no:SIP_PORT);
 			}else{
 			}else{
 				ret=comp_str(e->op, &msg->first_line.u.request.uri,
 				ret=comp_str(e->op, &msg->first_line.u.request.uri,
-					     e->r_type, &e->r);
+					     e->r_type, &e->r, msg);
 			}
 			}
 		}
 		}
 		break;
 		break;
@@ -699,7 +744,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 					  uri.port_no?uri.port_no:SIP_PORT);
 					  uri.port_no?uri.port_no:SIP_PORT);
 		}else{
 		}else{
 			ret=comp_str(e->op, &get_from(msg)->uri,
 			ret=comp_str(e->op, &get_from(msg)->uri,
-				     e->r_type, &e->r);
+				     e->r_type, &e->r, msg);
 		}
 		}
 		break;
 		break;
 
 
@@ -721,7 +766,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 					  uri.port_no?uri.port_no:SIP_PORT);
 					  uri.port_no?uri.port_no:SIP_PORT);
 		}else{
 		}else{
 			ret=comp_str(e->op, &get_to(msg)->uri,
 			ret=comp_str(e->op, &get_to(msg)->uri,
-				     e->r_type, &e->r);
+				     e->r_type, &e->r, msg);
 		}
 		}
 		break;
 		break;
 		
 		
@@ -837,9 +882,13 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
 		break;
 		break;
 
 
 	case AVP_O:
 	case AVP_O:
-		ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r);
+		ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r, msg);
 		break;
 		break;
 		
 		
+	case SELECT_O:
+		ret = comp_select(e->op, e->l.select, e->r_type, &e->r, msg);
+		break;
+
 	default:
 	default:
 		LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
 		LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
 		    e->l_type);
 		    e->l_type);

+ 14 - 3
route_struct.c

@@ -174,6 +174,9 @@ void print_expr(struct expr* exp)
 		        case AVP_ST:
 		        case AVP_ST:
 				DBG("attr");
 				DBG("attr");
 				break;
 				break;
+		        case SELECT_ST:
+			        DBG("select");
+				break;
 			
 			
 			default:
 			default:
 				DBG("UNKNOWN");
 				DBG("UNKNOWN");
@@ -228,9 +231,11 @@ void print_expr(struct expr* exp)
 					DBG("_myself_");
 					DBG("_myself_");
 					break;
 					break;
 		        case AVP_ST:
 		        case AVP_ST:
-				DBG("attr");
-				break;
-			
+				        DBG("attr");
+			 	        break;
+		        case SELECT_ST:
+				        DBG("select");
+				        break;
 			default:
 			default:
 					DBG("type<%d>", exp->r_type);
 					DBG("type<%d>", exp->r_type);
 		}
 		}
@@ -407,6 +412,9 @@ void print_action(struct action* t)
 	case AVP_ST:
 	case AVP_ST:
 		DBG("avp(%u,%.*s)", t->p1.attr->type, t->p1.attr->name.s.len, ZSW(t->p1.attr->name.s.s));
 		DBG("avp(%u,%.*s)", t->p1.attr->type, t->p1.attr->name.s.len, ZSW(t->p1.attr->name.s.s));
 		break;
 		break;
+	case SELECT_ST:
+		DBG("select");
+		break;
 	default:
 	default:
 		DBG("type<%d>", t->p1_type);
 		DBG("type<%d>", t->p1_type);
 	}
 	}
@@ -438,6 +446,9 @@ void print_action(struct action* t)
 	case AVP_ST:
 	case AVP_ST:
 		DBG(", avp(%u,%.*s)", t->p2.attr->type, t->p2.attr->name.s.len, ZSW(t->p2.attr->name.s.s));
 		DBG(", avp(%u,%.*s)", t->p2.attr->type, t->p2.attr->name.s.len, ZSW(t->p2.attr->name.s.s));
 		break;
 		break;
+	case SELECT_ST:
+		DBG("select");
+		break;
 	default:
 	default:
 		DBG(", type<%d>", t->p2_type);
 		DBG(", type<%d>", t->p2_type);
 	}
 	}

+ 5 - 3
route_struct.h

@@ -41,6 +41,7 @@
 #define route_struct_h
 #define route_struct_h
 
 
 #include <regex.h>
 #include <regex.h>
+#include "select.h"
 #include "usr_avp.h"
 #include "usr_avp.h"
 
 
 #define EXPR_DROP -127  /* used only by the expression and if evaluator */
 #define EXPR_DROP -127  /* used only by the expression and if evaluator */
@@ -62,7 +63,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,
 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,
 	   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, 
 	   NUMBER_O, AVP_O, SNDIP_O, SNDPORT_O, TOIP_O, TOPORT_O, SNDPROTO_O, 
-	   SNDAF_O, RETCODE_O};
+	   SNDAF_O, RETCODE_O, SELECT_O};
 
 
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
 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_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, 
@@ -88,14 +89,13 @@ 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,
 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,
 		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, SELECT_ST,
 		RETCODE_ST};
 		RETCODE_ST};
 
 
 /* run flags */
 /* run flags */
 #define EXIT_R_F   1
 #define EXIT_R_F   1
 #define RETURN_R_F 2
 #define RETURN_R_F 2
 
 
-
 /* Expression operand */
 /* Expression operand */
 union exp_op {
 union exp_op {
 	struct expr* expr;
 	struct expr* expr;
@@ -104,6 +104,7 @@ union exp_op {
 	void* param;
 	void* param;
 	int intval;
 	int intval;
 	avp_spec_t* attr;
 	avp_spec_t* attr;
+	select_t* select;
 	regex_t* re;
 	regex_t* re;
 	struct net* net;
 	struct net* net;
 };
 };
@@ -122,6 +123,7 @@ typedef union {
 	str str;
 	str str;
 	void* data;
 	void* data;
 	avp_spec_t* attr;
 	avp_spec_t* attr;
+	select_t* select;
 } action_u_t;
 } action_u_t;
 
 
 struct action{
 struct action{

+ 129 - 0
select.c

@@ -0,0 +1,129 @@
+#include "select.h"
+#include "dprint.h"
+#include "select_core.h"
+#include "mem/mem.h"
+
+/*
+ * The main parser table list placeholder
+ * at startup use core table, modules can
+ * add their own via register_select_table call
+ */
+static select_table_t *select_list = &select_core_table;
+
+int resolve_select(select_t* s)
+{
+	select_f f, pf;
+	int param_idx = 0;
+	int table_idx = 0;
+	select_table_t* t = NULL;;
+	int accept = 0;
+	
+	f = pf = NULL;
+	while (param_idx<s->n) {
+		accept = 0;
+		for (t=select_list; t; t=t->next) {
+			table_idx = 0;	
+			if (!t->table) continue;
+			while (t->table[table_idx].curr_f || t->table[table_idx].new_f) {
+				if (t->table[table_idx].curr_f == f) {
+					if (t->table[table_idx].type == s->params[param_idx].type) {
+						switch (t->table[table_idx].type) {
+						case PARAM_INT:
+							accept = 1;
+							break;
+							case PARAM_STR:
+							accept = (((t->table[table_idx].name.len == s->params[param_idx].v.s.len) || !t->table[table_idx].name.len)
+								   && (!t->table[table_idx].name.s || !strncasecmp(t->table[table_idx].name.s, s->params[param_idx].v.s.s, s->params[param_idx].v.s.len)));
+							break;
+						default:
+							break;
+						}
+					};
+					if ((t->table[table_idx].flags & IS_ALIAS)&&(!pf)) {
+						accept = 1;
+					}
+				}
+				if (accept) goto accepted;
+				table_idx++;
+			}
+		}
+		goto not_found;
+
+		accepted:
+		if (t->table[table_idx].flags & CONSUME_NEXT_STR) {
+			if ((param_idx<s->n-1) && (s->params[param_idx+1].type == PARAM_STR)) {
+				param_idx++;
+			} else if (!(t->table[table_idx].flags & OPTIONAL)) {
+				goto not_found;
+			}
+		}
+		if (t->table[table_idx].flags & CONSUME_NEXT_INT) {
+			if ((param_idx<s->n-1) && (s->params[param_idx+1].type == PARAM_INT)) {
+				param_idx++;
+			} else if (!(t->table[table_idx].flags & OPTIONAL)) {
+				goto not_found;
+			}
+		}
+		if (t->table[table_idx].flags & IS_ALIAS) {
+			pf = f;
+		} else {
+			param_idx++;
+		}
+		f = t->table[table_idx].new_f;
+	}
+
+	if (t->table[table_idx].flags & PARAM_EXPECTED) goto not_found;
+	s->f = f;
+	s->parent_f = pf;
+	return 0;
+	
+not_found:
+	return -1;
+}
+
+int run_select(str* res, select_t* s, struct sip_msg* msg)
+{
+	if (res == NULL) {
+		BUG("Select unprepared result space\n");
+		return -1;
+	}
+	if (s == 0) {
+		BUG("Select structure is NULL\n");
+		return -1;
+	}
+	if (s->f == 0) {
+		BUG("Select structure has not been resolved\n");
+		return -1;
+	}
+DBG("Calling SELECT %p \n", s->f);
+	return s->f(res, s, msg);
+}
+
+void print_select(select_t* s)
+{
+	int i;
+	DBG("select(");
+	for(i = 0; i < s->n; i++) {
+		if (s->params[i].type == PARAM_INT) {
+			DBG("%d,", s->params[i].v.i);
+		} else {
+			DBG("%.*s,", s->params[i].v.s.len, s->params[i].v.s.s);
+		}
+	}
+	DBG(")\n");
+}
+
+int register_select_table(select_row_t* mod_tab)
+{
+	select_table_t* t;
+	t=(select_table_t*)pkg_malloc(sizeof(select_table_t));
+	if (!t) {
+		ERR("No memory for new select_table structure\n");
+		return -1;
+	}
+	
+	t->table=mod_tab;
+	t->next=select_list;
+	select_list=t;
+	return 0;
+}

+ 95 - 0
select.h

@@ -0,0 +1,95 @@
+#ifndef _SELECT_H
+#define _SELECT_H
+
+#include "str.h"
+#include "parser/msg_parser.h"
+
+#define MAX_SELECT_PARAMS 32
+
+// Flags for parser table FLAG bitfiels
+#define DIVERSION_MASK   0x00FF
+// if DIVERSION is set and the function is accepted and has STR param
+// the param is changed into PARAM_DIV and the value is set to (flags & DIVERSION_MASK)
+#define DIVERSION        1<<8
+// if any parameter is expected at this stage
+#define PARAM_EXPECTED   1<<9
+// accept if following parameter is STR (any)
+#define CONSUME_NEXT_STR 1<<10
+// accept if following parameter is INT
+#define CONSUME_NEXT_INT 1<<11
+// next parameter is optional (use with CONSUME_NEXT_STR or CONSUME_NEXT_INT
+#define OPTIONAL         1<<12
+// if conversion to common alias is needed
+// up-to now parsed function would be stored in parent_f
+// NOTE: the parameter is not consumed for ALIAS, 
+// so you can leave it as ..,PARAM_INT, STR_NULL,..
+#define IS_ALIAS         1<<13
+
+/*
+ * Selector call parameter
+ */
+typedef enum {
+	PARAM_INT,  /* Integer parameter */
+	PARAM_STR,  /* String parameter */
+	PARAM_DIV,  /* Integer value got from parsing table */
+} select_param_type_t;
+	
+typedef union {
+	int i;  /* Integer value */
+	str s;  /* String value */
+} select_param_value_t;
+	
+typedef struct sel_param {
+        select_param_type_t type;
+        select_param_value_t v;
+} select_param_t;
+
+struct select;
+
+typedef int (*select_f)(str* res, struct select* s, struct sip_msg* msg);
+
+typedef struct select {
+	select_f f;
+	select_f parent_f;
+	select_param_t params[MAX_SELECT_PARAMS];
+	int n;
+} select_t;
+
+typedef struct {
+	select_f curr_f;
+	select_param_type_t type;
+	str name;
+	select_f new_f;
+	int flags;
+} select_row_t;
+
+typedef struct select_table {
+  select_row_t *table;
+  struct select_table *next;
+} select_table_t;
+
+/*
+ * Lookup corresponding select function based on
+ * the select parameters
+ */
+int resolve_select(select_t* s);
+
+/*
+ * Run the select function
+ */
+int run_select(str* res, select_t* s, struct sip_msg* msg);
+
+/*
+ * Print select for debugging purposes 
+ */
+void print_select(select_t* s);
+
+/*
+ * Register modules' own select parser table
+ */
+int register_select_table(select_row_t *table);
+
+#define SELECT_F(function) extern int function (str* res, select_t* s, struct sip_msg* msg);
+#define ABSTRACT_F(function) int function (str* res, select_t* s, struct sip_msg* msg) {return -1;}
+
+#endif /* _SELECT_H */

+ 3 - 0
select_core.c

@@ -0,0 +1,3 @@
+#include "select.h"
+#include "select_core.h"
+

+ 14 - 0
select_core.h

@@ -0,0 +1,14 @@
+#ifndef _SELECT_CORE_H
+#define _SELECT_CORE_H
+
+#include "str.h"
+#include "parser/msg_parser.h"
+#include "select.h"
+
+static select_row_t select_core[] = {
+	{ NULL, PARAM_INT, STR_NULL, NULL, 0}
+};
+
+static select_table_t select_core_table = {select_core, NULL};
+
+#endif // _SELECT_CORE_H