Browse code

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: $my_avp=@my.function[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 authored on 20/12/2005 00:49:32
Showing 10 changed files
... ...
@@ -770,6 +770,20 @@ int do_action(struct action* a, struct sip_msg* msg)
770 770
 				}
771 771
 				ret = 1;
772 772
 				break;
773
+			} else if (a->p2_type == SELECT_ST) {
774
+				int r;
775
+				r = run_select(&value.s, a->p2.select, msg);
776
+				if (r < 0) {
777
+					ret=E_UNSPEC;
778
+					break;
779
+				} else if (r > 0) {
780
+					value.s.s = "";
781
+					value.s.len = 0;
782
+				}
783
+
784
+				flags = a->p1.attr->type | AVP_VAL_STR;
785
+				name = a->p1.attr->name;
786
+				ret = 1;
773 787
 			} else {
774 788
 				LOG(L_CRIT, "BUG: do_action: Bad right side of avp assignment\n");
775 789
 				ret=E_BUG;
... ...
@@ -70,6 +70,7 @@
70 70
 	#include <stdlib.h>
71 71
 	#include "ip_addr.h"
72 72
 	#include "usr_avp.h"
73
+	#include "select.h"
73 74
 	#include "cfg.tab.h"
74 75
 
75 76
 	/* states */
... ...
@@ -78,6 +79,7 @@
78 79
 	#define COMMENT_LN_S	        2
79 80
 	#define STRING_S		3
80 81
 	#define ATTR_S                  4
82
+        #define SELECT_S                5
81 83
 
82 84
 	#define STR_BUF_ALLOC_UNIT	128
83 85
 	struct str_buf{
... ...
@@ -102,7 +104,7 @@
102 104
 %}
103 105
 
104 106
 /* start conditions */
105
-%x STRING1 STRING2 COMMENT COMMENT_LN ATTR
107
+%x STRING1 STRING2 COMMENT COMMENT_LN ATTR SELECT
106 108
 
107 109
 /* action keywords */
108 110
 FORWARD	forward
... ...
@@ -194,7 +196,8 @@ PLUS	"+"
194 196
 MINUS	"-"
195 197
 
196 198
 /* Attribute specification */
197
-ATTR_MARK   "$"|"%"|"@"
199
+ATTR_MARK   "$"|"%"
200
+SELECT_MARK  "@"
198 201
 ATTR_FROM   "from"|"f"
199 202
 ATTR_TO     "to"|"t"
200 203
 ATTR_USER   "user"|"u"
... ...
@@ -501,6 +504,22 @@ EAT_ABLE	[\ \t\b\r]
501 504
 <INITIAL>{PLUS}		{ count(); return PLUS; }
502 505
 <INITIAL>{MINUS}	{ count(); return MINUS; }
503 506
 
507
+<INITIAL>{SELECT_MARK}  { count(); state = SELECT_S; BEGIN(SELECT); return SELECT_MARK; }
508
+<SELECT>{ID}		{ count(); addstr(&s_buf, yytext, yyleng); 
509
+                          yylval.strval=s_buf.s;
510
+                          memset(&s_buf, 0, sizeof(s_buf));
511
+                          return ID; 
512
+                        }
513
+<SELECT>{DOT}           { count(); return DOT; }
514
+<SELECT>{LBRACK}        { count(); return LBRACK; }
515
+<SELECT>{RBRACK}        { count(); return RBRACK; }
516
+<SELECT>{DECNUMBER}	{ count(); yylval.intval=atoi(yytext);return NUMBER; }
517
+<SELECT>{HEXNUMBER}	{ count(); yylval.intval=(int)strtol(yytext, 0, 16); return NUMBER; }
518
+<SELECT>{OCTNUMBER}	{ count(); yylval.intval=(int)strtol(yytext, 0, 8); return NUMBER; }
519
+<SELECT>{BINNUMBER}     { count(); yylval.intval=(int)strtol(yytext, 0, 2); return NUMBER; }
520
+<SELECT>.               { unput(yytext[0]); state = INITIAL_S; BEGIN(INITIAL); } /* Rescan the token in INITIAL state */
521
+
522
+
504 523
 <INITIAL>{ATTR_MARK}    { count(); state = ATTR_S; BEGIN(ATTR); return ATTR_MARK; }
505 524
 <ATTR>{ATTR_FROM}       { count(); return ATTR_FROM; }
506 525
 <ATTR>{ATTR_TO}         { count(); return ATTR_TO; }
... ...
@@ -91,6 +91,7 @@
91 91
 #include "name_alias.h"
92 92
 #include "ut.h"
93 93
 #include "dset.h"
94
+#include "select.h"
94 95
 
95 96
 #include "config.h"
96 97
 #ifdef USE_TLS
... ...
@@ -121,6 +122,9 @@ static str* str_tmp;
121 122
 static str s_tmp;
122 123
 static struct ip_addr* ip_tmp;
123 124
 static struct avp_spec* s_attr;
125
+static select_t sel;
126
+static select_t* sel_ptr;
127
+
124 128
 
125 129
 static void warn(char* s);
126 130
 static struct socket_id* mk_listen_id(char*, int, int);
... ...
@@ -137,6 +141,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
137 141
 	struct ip_addr* ipaddr;
138 142
 	struct socket_id* sockid;
139 143
 	struct avp_spec* attr;
144
+	select_t* select;
140 145
 }
141 146
 
142 147
 /* terminals */
... ...
@@ -279,6 +284,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
279 284
 %token TOS
280 285
 
281 286
 %token ATTR_MARK
287
+%token SELECT_MARK
282 288
 %token ATTR_FROM
283 289
 %token ATTR_TO
284 290
 %token ATTR_USER
... ...
@@ -340,6 +346,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
340 346
 %type <attr> attr_id
341 347
 %type <intval> class_id
342 348
 %type <intval> assign_op
349
+%type <select> select_id
343 350
 /*%type <route_el> rules;
344 351
   %type <route_el> rule;
345 352
 */
... ...
@@ -979,6 +986,7 @@ uri_type:	URI			{$$=URI_O;}
979 986
 
980 987
 exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
981 988
                 | METHOD strop attr_id  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
989
+                | METHOD strop select_id {$$ = mk_elem($2, METHOD_O, 0, SELECT_ST, $3); }
982 990
 		| METHOD strop  ID	{$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
983 991
 		| METHOD strop error { $$=0; yyerror("string expected"); }
984 992
 		| METHOD error	{ $$=0; yyerror("invalid operator,"
... ...
@@ -987,6 +995,7 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
987 995
 		| uri_type strop STRING	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
988 996
                 | uri_type strop host 	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
989 997
                 | uri_type strop attr_id {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
998
+                | uri_type strop select_id {$$ = mk_elem($2, $1, 0, SELECT_ST, $3); }
990 999
                 | uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
991 1000
 		| uri_type strop error { $$=0; yyerror("string or MYSELF expected"); }
992 1001
 		| 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);}
1193 1202
 
1194 1203
 		| attr_id		{$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); }
1195 1204
 		| attr_id strop STRING	{$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); }
1205
+		| attr_id strop select_id {$$=mk_elem( $2, AVP_O, (void*)$1, SELECT_ST, $3); }
1196 1206
 		| attr_id intop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
1197 1207
 		| attr_id binop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
1198
-		| attr_id strop attr_id {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
1208
+                | attr_id strop attr_id {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
1209
+
1210
+                | select_id                 { $$=mk_elem( NO_OP, SELECT_O, $1, 0, 0); }
1211
+		| select_id strop STRING    { $$=mk_elem( $2, SELECT_O, $1, STRING_ST, $3); }
1212
+		| select_id strop attr_id   { $$=mk_elem( $2, SELECT_O, $1, AVP_ST, (void*)$3); }
1213
+		| select_id strop select_id { $$=mk_elem( $2, SELECT_O, $1, SELECT_ST, $3); }
1199 1214
 ;
1200 1215
 
1201 1216
 
... ...
@@ -1310,39 +1325,77 @@ class_id : LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; }
1310 1325
          | LBRACK ATTR_GLOBAL RBRACK { $$ = AVP_CLASS_GLOBAL; }
1311 1326
 ;
1312 1327
 
1328
+select_param : ID { 
1329
+		    if (sel.n >= MAX_SELECT_PARAMS-1) {
1330
+			    yyerror("Select identifier too long\n");
1331
+		    }
1332
+		    sel.params[sel.n].type = PARAM_STR; 
1333
+		    sel.params[sel.n].v.s.s = $1;
1334
+		    sel.params[sel.n].v.s.len = strlen($1);
1335
+		    sel.n++;
1336
+                  }
1337
+             | ID LBRACK NUMBER RBRACK {
1338
+		     if (sel.n >= MAX_SELECT_PARAMS-2) {
1339
+			    yyerror("Select identifier too long\n");
1340
+		     }
1341
+		     sel.params[sel.n].type = PARAM_STR;
1342
+		     sel.params[sel.n].v.s.s = $1;
1343
+		     sel.params[sel.n].v.s.len = strlen($1);
1344
+		     sel.n++;
1345
+		     sel.params[sel.n].type = PARAM_INT;
1346
+		     sel.params[sel.n].v.i = $3;
1347
+		     sel.n++;
1348
+	     }
1349
+;
1350
+
1351
+select_params : select_params DOT select_param
1352
+              | select_param
1353
+;
1354
+
1355
+select_id : SELECT_MARK { sel.n = 0; sel.f = 0; } select_params {
1356
+//	if (resolve_select(&sel) < 0) yyerror("Unable to resolve select");
1357
+	sel_ptr = (select_t*)pkg_malloc(sizeof(select_t));
1358
+	if (!sel_ptr) {
1359
+		yyerror("No memory left to allocate select structure\n");
1360
+	}
1361
+	memcpy(sel_ptr, &sel, sizeof(select_t));
1362
+	$$ = sel_ptr;
1363
+}
1364
+;
1365
+
1313 1366
 attr_id : ATTR_MARK ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1314
-                         if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1367
+                         if (!s_attr) { yyerror("No memory left"); }
1315 1368
                          s_attr->type = AVP_NAME_STR;                   
1316 1369
                          s_attr->name.s.s = $2; s_attr->name.s.len = strlen($2); 
1317 1370
                          $$ = s_attr; 
1318 1371
                        }
1319 1372
         | ATTR_MARK class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1320
-                                      if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1373
+                                      if (!s_attr) { yyerror("No memory left"); }
1321 1374
                                       s_attr->type = AVP_NAME_STR | $2;
1322 1375
                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
1323 1376
                                       $$ = s_attr; 
1324 1377
                                     }
1325 1378
         | ATTR_MARK ATTR_FROM DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1326
-                                       if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1379
+                                       if (!s_attr) { yyerror("No memory left"); }
1327 1380
                                        s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM;
1328 1381
                                        s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
1329 1382
                                        $$ = s_attr;
1330 1383
                                      }
1331 1384
         | ATTR_MARK ATTR_TO DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1332
-                                     if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1385
+                                     if (!s_attr) { yyerror("No memory left"); }
1333 1386
                                      s_attr->type = AVP_NAME_STR | AVP_TRACK_TO; 
1334 1387
                                      s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
1335 1388
                                      $$ = s_attr;
1336 1389
                                    }
1337 1390
         | ATTR_MARK ATTR_FROM class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1338
-                                               if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1391
+                                               if (!s_attr) { yyerror("No memory left"); }
1339 1392
                                                s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | $3; 
1340 1393
                                                s_attr->name.s.s = $5; 
1341 1394
                                                s_attr->name.s.len = strlen($5);
1342 1395
                                                $$ = s_attr;
1343 1396
                                               }
1344 1397
         | ATTR_MARK ATTR_TO class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1345
-                                              if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
1398
+                                              if (!s_attr) { yyerror("No memory left"); }
1346 1399
                                               s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | $3;
1347 1400
                                               s_attr->name.s.s = $5; s_attr->name.s.len = strlen($5);
1348 1401
                                              $$ = s_attr;
... ...
@@ -1357,6 +1410,7 @@ assign_action:   attr_id assign_op STRING  { $$=mk_action($2, AVP_ST, STRING_ST,
1357 1410
                | attr_id assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
1358 1411
                | attr_id assign_op fcmd    { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
1359 1412
                | attr_id assign_op attr_id { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
1413
+               | attr_id assign_op select_id { $$=mk_action($2, AVP_ST, SELECT_ST, (void*)$1, (void*)$3); }
1360 1414
                | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
1361 1415
 ;
1362 1416
 
... ...
@@ -67,9 +67,9 @@
67 67
 #include "parser/parse_from.h"
68 68
 #include "parser/parse_to.h"
69 69
 #include "mem/mem.h"
70
+#include "select.h"
70 71
 #include "onsend.h"
71 72
 
72
-
73 73
 /* main routing script table  */
74 74
 struct action* rlist[RT_NO];
75 75
 /* reply routing table */
... ...
@@ -132,7 +132,7 @@ static int fix_expr(struct expr* exp)
132 132
 					pkg_free(exp->r.param);
133 133
 					exp->r.re=re;
134 134
 					exp->r_type=RE_ST;
135
-				}else if (exp->r_type!=RE_ST && exp->r_type != AVP_ST){
135
+				}else if (exp->r_type!=RE_ST && exp->r_type != AVP_ST && exp->r_type != SELECT_ST){
136 136
 					LOG(L_CRIT, "BUG: fix_expr : invalid type for match\n");
137 137
 					return E_BUG;
138 138
 				}
... ...
@@ -159,6 +159,20 @@ static int fix_expr(struct expr* exp)
159 159
 				exp->r.str.s = exp->r.string;
160 160
 				exp->r.str.len = len;
161 161
 			}
162
+			if (exp->l_type==SELECT_O) {
163
+				if ((ret=resolve_select(exp->l.select)) < 0) {
164
+					BUG("Unable to resolve select\n");
165
+					print_select(exp->l.select);
166
+					return ret;
167
+				}
168
+			}
169
+			if ((exp->r_type==SELECT_O)||(exp->r_type==SELECT_ST)) {
170
+				if ((ret=resolve_select(exp->r.select)) < 0) {
171
+					BUG("Unable to resolve select\n");
172
+					print_select(exp->l.select);
173
+					return ret;
174
+				}
175
+			}
162 176
 			ret=0;
163 177
 	}
164 178
 	return ret;
... ...
@@ -280,6 +294,12 @@ static int fix_actions(struct action* a)
280 294
 					len = strlen(t->p2.data);
281 295
 					t->p2.str.s = t->p2.data;
282 296
 					t->p2.str.len = len;
297
+				} else if (t->p2_type == SELECT_ST) {
298
+					if ((ret=resolve_select(t->p2.select)) < 0) {
299
+						BUG("Unable to resolve select\n");
300
+						print_select(t->p2.select);
301
+						return ret;
302
+					}
283 303
 				}
284 304
 				break;
285 305
 
... ...
@@ -372,10 +392,11 @@ inline static int comp_num(int op, long left, int rtype, union exp_op* r)
372 392
 /*
373 393
  * Compare given string "left" with right side of expression
374 394
  */
375
-inline static int comp_str(int op, str* left, int rtype, union exp_op* r)
395
+inline static int comp_str(int op, str* left, int rtype, union exp_op* r, struct sip_msg* msg)
376 396
 {
377 397
 	str* right;
378 398
 	int_str val;
399
+	str v;
379 400
 	avp_t* avp;
380 401
 	int ret;
381 402
 	char backup;
... ...
@@ -387,6 +408,11 @@ inline static int comp_str(int op, str* left, int rtype, union exp_op* r)
387 408
 		avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
388 409
 		if (avp && (avp->flags & AVP_VAL_STR)) right = &val.s;
389 410
 		else return 0;
411
+	} else if (rtype == SELECT_ST) {
412
+		ret = run_select(&v, r->select, msg);
413
+		if (ret > 0) return 0;       /* Not found */
414
+		else if (ret < 0) goto error; /* Error */
415
+		right = &v;
390 416
 	} else if ((op == MATCH_OP && rtype == RE_ST)) {
391 417
 	} else if (op != MATCH_OP && rtype == STRING_ST) {
392 418
 		right = &r->str;
... ...
@@ -424,7 +450,7 @@ inline static int comp_str(int op, str* left, int rtype, union exp_op* r)
424 450
 			      */
425 451
 			backup=left->s[left->len];
426 452
 			left->s[left->len]='\0';
427
-			if (rtype == AVP_ST) {
453
+			if (rtype == AVP_ST || rtype == SELECT_ST) {
428 454
 				     /* For AVPs we need to compile the RE on the fly */
429 455
 				re=(regex_t*)pkg_malloc(sizeof(regex_t));
430 456
 				if (re==0){
... ...
@@ -499,7 +525,7 @@ error:
499 525
 }
500 526
 
501 527
 
502
-inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r)
528
+inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r, struct sip_msg* msg)
503 529
 {
504 530
 	avp_t* avp;
505 531
 	int_str val;
... ...
@@ -526,14 +552,33 @@ inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r)
526 552
 	}
527 553
 
528 554
 	if (avp->flags & AVP_VAL_STR) {
529
-		return comp_str(op, &val.s, rtype, r);
555
+		return comp_str(op, &val.s, rtype, r, msg);
530 556
 	} else {
531 557
 		return comp_num(op, val.n, rtype, r);
532 558
 	}
533 559
 }
534 560
 
561
+/*
562
+ * Left side of expression was select
563
+ */
564
+inline static int comp_select(int op, select_t* sel, int rtype, union exp_op* r, struct sip_msg* msg)
565
+{
566
+	int ret;
567
+	str val;
535 568
 
569
+	ret = run_select(&val, sel, msg);
570
+	if (ret < 0) return -1;
571
+	if (ret > 0) return 0;
536 572
 
573
+	switch(op) {
574
+	case NO_OP: return 1;
575
+	case BINOR_OP:
576
+	case BINAND_OP:  
577
+		ERR("Binary operators cannot be used with string selects\n");
578
+		return -1;
579
+	}
580
+	return comp_str(op, &val, rtype, r, msg);
581
+}
537 582
 
538 583
 /* check_self wrapper -- it checks also for the op */
539 584
 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)
657 702
 	switch(e->l_type){
658 703
 	case METHOD_O:
659 704
 		ret=comp_str(e->op, &msg->first_line.u.request.method, 
660
-			     e->r_type, &e->r);
705
+			     e->r_type, &e->r, msg);
661 706
 		break;
662 707
 	case URI_O:
663 708
 		if(msg->new_uri.s) {
... ...
@@ -668,7 +713,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
668 713
 						       msg->parsed_uri.port_no:SIP_PORT);
669 714
 			}else{
670 715
 				ret=comp_str(e->op, &msg->new_uri, 
671
-					     e->r_type, &e->r);
716
+					     e->r_type, &e->r, msg);
672 717
 			}
673 718
 		}else{
674 719
 			if (e->r_type==MYSELF_ST){
... ...
@@ -678,7 +723,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
678 723
 						       msg->parsed_uri.port_no:SIP_PORT);
679 724
 			}else{
680 725
 				ret=comp_str(e->op, &msg->first_line.u.request.uri,
681
-					     e->r_type, &e->r);
726
+					     e->r_type, &e->r, msg);
682 727
 			}
683 728
 		}
684 729
 		break;
... ...
@@ -699,7 +744,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
699 744
 					  uri.port_no?uri.port_no:SIP_PORT);
700 745
 		}else{
701 746
 			ret=comp_str(e->op, &get_from(msg)->uri,
702
-				     e->r_type, &e->r);
747
+				     e->r_type, &e->r, msg);
703 748
 		}
704 749
 		break;
705 750
 
... ...
@@ -721,7 +766,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
721 766
 					  uri.port_no?uri.port_no:SIP_PORT);
722 767
 		}else{
723 768
 			ret=comp_str(e->op, &get_to(msg)->uri,
724
-				     e->r_type, &e->r);
769
+				     e->r_type, &e->r, msg);
725 770
 		}
726 771
 		break;
727 772
 		
... ...
@@ -837,9 +882,13 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
837 882
 		break;
838 883
 
839 884
 	case AVP_O:
840
-		ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r);
885
+		ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r, msg);
841 886
 		break;
842 887
 		
888
+	case SELECT_O:
889
+		ret = comp_select(e->op, e->l.select, e->r_type, &e->r, msg);
890
+		break;
891
+
843 892
 	default:
844 893
 		LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
845 894
 		    e->l_type);
... ...
@@ -174,6 +174,9 @@ void print_expr(struct expr* exp)
174 174
 		        case AVP_ST:
175 175
 				DBG("attr");
176 176
 				break;
177
+		        case SELECT_ST:
178
+			        DBG("select");
179
+				break;
177 180
 			
178 181
 			default:
179 182
 				DBG("UNKNOWN");
... ...
@@ -228,9 +231,11 @@ void print_expr(struct expr* exp)
228 231
 					DBG("_myself_");
229 232
 					break;
230 233
 		        case AVP_ST:
231
-				DBG("attr");
232
-				break;
233
-			
234
+				        DBG("attr");
235
+			 	        break;
236
+		        case SELECT_ST:
237
+				        DBG("select");
238
+				        break;
234 239
 			default:
235 240
 					DBG("type<%d>", exp->r_type);
236 241
 		}
... ...
@@ -407,6 +412,9 @@ void print_action(struct action* t)
407 412
 	case AVP_ST:
408 413
 		DBG("avp(%u,%.*s)", t->p1.attr->type, t->p1.attr->name.s.len, ZSW(t->p1.attr->name.s.s));
409 414
 		break;
415
+	case SELECT_ST:
416
+		DBG("select");
417
+		break;
410 418
 	default:
411 419
 		DBG("type<%d>", t->p1_type);
412 420
 	}
... ...
@@ -438,6 +446,9 @@ void print_action(struct action* t)
438 446
 	case AVP_ST:
439 447
 		DBG(", avp(%u,%.*s)", t->p2.attr->type, t->p2.attr->name.s.len, ZSW(t->p2.attr->name.s.s));
440 448
 		break;
449
+	case SELECT_ST:
450
+		DBG("select");
451
+		break;
441 452
 	default:
442 453
 		DBG(", type<%d>", t->p2_type);
443 454
 	}
... ...
@@ -41,6 +41,7 @@
41 41
 #define route_struct_h
42 42
 
43 43
 #include <regex.h>
44
+#include "select.h"
44 45
 #include "usr_avp.h"
45 46
 
46 47
 #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 };
62 63
 enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O,
63 64
 	   DSTIP_O, DSTPORT_O, PROTO_O, AF_O, MSGLEN_O, DEFAULT_O, ACTION_O,
64 65
 	   NUMBER_O, AVP_O, SNDIP_O, SNDPORT_O, TOIP_O, TOPORT_O, SNDPROTO_O, 
65
-	   SNDAF_O, RETCODE_O};
66
+	   SNDAF_O, RETCODE_O, SELECT_O};
66 67
 
67 68
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
68 69
 		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,
88 89
 };
89 90
 enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
90 91
 		EXPR_ST, ACTIONS_ST, CMDF_ST, MODFIXUP_ST, URIHOST_ST, URIPORT_ST,
91
-		MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST,
92
+		MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST, SELECT_ST,
92 93
 		RETCODE_ST};
93 94
 
94 95
 /* run flags */
95 96
 #define EXIT_R_F   1
96 97
 #define RETURN_R_F 2
97 98
 
98
-
99 99
 /* Expression operand */
100 100
 union exp_op {
101 101
 	struct expr* expr;
... ...
@@ -104,6 +104,7 @@ union exp_op {
104 104
 	void* param;
105 105
 	int intval;
106 106
 	avp_spec_t* attr;
107
+	select_t* select;
107 108
 	regex_t* re;
108 109
 	struct net* net;
109 110
 };
... ...
@@ -122,6 +123,7 @@ typedef union {
122 123
 	str str;
123 124
 	void* data;
124 125
 	avp_spec_t* attr;
126
+	select_t* select;
125 127
 } action_u_t;
126 128
 
127 129
 struct action{
128 130
new file mode 100644
... ...
@@ -0,0 +1,129 @@
1
+#include "select.h"
2
+#include "dprint.h"
3
+#include "select_core.h"
4
+#include "mem/mem.h"
5
+
6
+/*
7
+ * The main parser table list placeholder
8
+ * at startup use core table, modules can
9
+ * add their own via register_select_table call
10
+ */
11
+static select_table_t *select_list = &select_core_table;
12
+
13
+int resolve_select(select_t* s)
14
+{
15
+	select_f f, pf;
16
+	int param_idx = 0;
17
+	int table_idx = 0;
18
+	select_table_t* t = NULL;;
19
+	int accept = 0;
20
+	
21
+	f = pf = NULL;
22
+	while (param_idx<s->n) {
23
+		accept = 0;
24
+		for (t=select_list; t; t=t->next) {
25
+			table_idx = 0;	
26
+			if (!t->table) continue;
27
+			while (t->table[table_idx].curr_f || t->table[table_idx].new_f) {
28
+				if (t->table[table_idx].curr_f == f) {
29
+					if (t->table[table_idx].type == s->params[param_idx].type) {
30
+						switch (t->table[table_idx].type) {
31
+						case PARAM_INT:
32
+							accept = 1;
33
+							break;
34
+							case PARAM_STR:
35
+							accept = (((t->table[table_idx].name.len == s->params[param_idx].v.s.len) || !t->table[table_idx].name.len)
36
+								   && (!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)));
37
+							break;
38
+						default:
39
+							break;
40
+						}
41
+					};
42
+					if ((t->table[table_idx].flags & IS_ALIAS)&&(!pf)) {
43
+						accept = 1;
44
+					}
45
+				}
46
+				if (accept) goto accepted;
47
+				table_idx++;
48
+			}
49
+		}
50
+		goto not_found;
51
+
52
+		accepted:
53
+		if (t->table[table_idx].flags & CONSUME_NEXT_STR) {
54
+			if ((param_idx<s->n-1) && (s->params[param_idx+1].type == PARAM_STR)) {
55
+				param_idx++;
56
+			} else if (!(t->table[table_idx].flags & OPTIONAL)) {
57
+				goto not_found;
58
+			}
59
+		}
60
+		if (t->table[table_idx].flags & CONSUME_NEXT_INT) {
61
+			if ((param_idx<s->n-1) && (s->params[param_idx+1].type == PARAM_INT)) {
62
+				param_idx++;
63
+			} else if (!(t->table[table_idx].flags & OPTIONAL)) {
64
+				goto not_found;
65
+			}
66
+		}
67
+		if (t->table[table_idx].flags & IS_ALIAS) {
68
+			pf = f;
69
+		} else {
70
+			param_idx++;
71
+		}
72
+		f = t->table[table_idx].new_f;
73
+	}
74
+
75
+	if (t->table[table_idx].flags & PARAM_EXPECTED) goto not_found;
76
+	s->f = f;
77
+	s->parent_f = pf;
78
+	return 0;
79
+	
80
+not_found:
81
+	return -1;
82
+}
83
+
84
+int run_select(str* res, select_t* s, struct sip_msg* msg)
85
+{
86
+	if (res == NULL) {
87
+		BUG("Select unprepared result space\n");
88
+		return -1;
89
+	}
90
+	if (s == 0) {
91
+		BUG("Select structure is NULL\n");
92
+		return -1;
93
+	}
94
+	if (s->f == 0) {
95
+		BUG("Select structure has not been resolved\n");
96
+		return -1;
97
+	}
98
+DBG("Calling SELECT %p \n", s->f);
99
+	return s->f(res, s, msg);
100
+}
101
+
102
+void print_select(select_t* s)
103
+{
104
+	int i;
105
+	DBG("select(");
106
+	for(i = 0; i < s->n; i++) {
107
+		if (s->params[i].type == PARAM_INT) {
108
+			DBG("%d,", s->params[i].v.i);
109
+		} else {
110
+			DBG("%.*s,", s->params[i].v.s.len, s->params[i].v.s.s);
111
+		}
112
+	}
113
+	DBG(")\n");
114
+}
115
+
116
+int register_select_table(select_row_t* mod_tab)
117
+{
118
+	select_table_t* t;
119
+	t=(select_table_t*)pkg_malloc(sizeof(select_table_t));
120
+	if (!t) {
121
+		ERR("No memory for new select_table structure\n");
122
+		return -1;
123
+	}
124
+	
125
+	t->table=mod_tab;
126
+	t->next=select_list;
127
+	select_list=t;
128
+	return 0;
129
+}
0 130
new file mode 100644
... ...
@@ -0,0 +1,95 @@
1
+#ifndef _SELECT_H
2
+#define _SELECT_H
3
+
4
+#include "str.h"
5
+#include "parser/msg_parser.h"
6
+
7
+#define MAX_SELECT_PARAMS 32
8
+
9
+// Flags for parser table FLAG bitfiels
10
+#define DIVERSION_MASK   0x00FF
11
+// if DIVERSION is set and the function is accepted and has STR param
12
+// the param is changed into PARAM_DIV and the value is set to (flags & DIVERSION_MASK)
13
+#define DIVERSION        1<<8
14
+// if any parameter is expected at this stage
15
+#define PARAM_EXPECTED   1<<9
16
+// accept if following parameter is STR (any)
17
+#define CONSUME_NEXT_STR 1<<10
18
+// accept if following parameter is INT
19
+#define CONSUME_NEXT_INT 1<<11
20
+// next parameter is optional (use with CONSUME_NEXT_STR or CONSUME_NEXT_INT
21
+#define OPTIONAL         1<<12
22
+// if conversion to common alias is needed
23
+// up-to now parsed function would be stored in parent_f
24
+// NOTE: the parameter is not consumed for ALIAS, 
25
+// so you can leave it as ..,PARAM_INT, STR_NULL,..
26
+#define IS_ALIAS         1<<13
27
+
28
+/*
29
+ * Selector call parameter
30
+ */
31
+typedef enum {
32
+	PARAM_INT,  /* Integer parameter */
33
+	PARAM_STR,  /* String parameter */
34
+	PARAM_DIV,  /* Integer value got from parsing table */
35
+} select_param_type_t;
36
+	
37
+typedef union {
38
+	int i;  /* Integer value */
39
+	str s;  /* String value */
40
+} select_param_value_t;
41
+	
42
+typedef struct sel_param {
43
+        select_param_type_t type;
44
+        select_param_value_t v;
45
+} select_param_t;
46
+
47
+struct select;
48
+
49
+typedef int (*select_f)(str* res, struct select* s, struct sip_msg* msg);
50
+
51
+typedef struct select {
52
+	select_f f;
53
+	select_f parent_f;
54
+	select_param_t params[MAX_SELECT_PARAMS];
55
+	int n;
56
+} select_t;
57
+
58
+typedef struct {
59
+	select_f curr_f;
60
+	select_param_type_t type;
61
+	str name;
62
+	select_f new_f;
63
+	int flags;
64
+} select_row_t;
65
+
66
+typedef struct select_table {
67
+  select_row_t *table;
68
+  struct select_table *next;
69
+} select_table_t;
70
+
71
+/*
72
+ * Lookup corresponding select function based on
73
+ * the select parameters
74
+ */
75
+int resolve_select(select_t* s);
76
+
77
+/*
78
+ * Run the select function
79
+ */
80
+int run_select(str* res, select_t* s, struct sip_msg* msg);
81
+
82
+/*
83
+ * Print select for debugging purposes 
84
+ */
85
+void print_select(select_t* s);
86
+
87
+/*
88
+ * Register modules' own select parser table
89
+ */
90
+int register_select_table(select_row_t *table);
91
+
92
+#define SELECT_F(function) extern int function (str* res, select_t* s, struct sip_msg* msg);
93
+#define ABSTRACT_F(function) int function (str* res, select_t* s, struct sip_msg* msg) {return -1;}
94
+
95
+#endif /* _SELECT_H */
0 96
new file mode 100644
... ...
@@ -0,0 +1,3 @@
1
+#include "select.h"
2
+#include "select_core.h"
3
+
0 4
new file mode 100644
... ...
@@ -0,0 +1,14 @@
1
+#ifndef _SELECT_CORE_H
2
+#define _SELECT_CORE_H
3
+
4
+#include "str.h"
5
+#include "parser/msg_parser.h"
6
+#include "select.h"
7
+
8
+static select_row_t select_core[] = {
9
+	{ NULL, PARAM_INT, STR_NULL, NULL, 0}
10
+};
11
+
12
+static select_table_t select_core_table = {select_core, NULL};
13
+
14
+#endif // _SELECT_CORE_H