Browse code

core: route(): added support for rvalue expressions parameters

route($foo+$bar+"test") will work now. Constant values (e.g.
route("foo"+"bar") are optimized to the simple string case
(route("foobar")).

Closes FlySpray#52.

Andrei Pelinescu-Onciul authored on 25/03/2010 22:20:17
Showing 4 changed files
... ...
@@ -10,6 +10,7 @@ core:
10 10
   - global, per protocol blacklist ignore masks (via extended send_flags).
11 11
     See dst_blacklist_udp_imask a.s.o (dst_blacklist_*_imask).
12 12
   - per message blacklist ignore masks
13
+  - route() now supports rvalue expressions (e.g. route("test"+$i))
13 14
 
14 15
 new config variables:
15 16
   - dst_blacklist_udp_imask - global blacklist events ignore mask for udp
... ...
@@ -481,20 +481,45 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
481 481
 			ret=1;
482 482
 			break;
483 483
 		case ROUTE_T:
484
-			if (a->val[0].type!=NUMBER_ST){
484
+			if (likely(a->val[0].type == NUMBER_ST))
485
+				i = a->val[0].u.number;
486
+			else if (a->val[0].type == RVE_ST) {
487
+				rv = rval_expr_eval(h, msg, a->val[0].u.data);
488
+				rval_cache_init(&c1);
489
+				if (unlikely(rv == 0 ||
490
+						rval_get_tmp_str(h, msg, &s, rv, 0, &c1) < 0)) {
491
+					rval_destroy(rv);
492
+					rval_cache_clean(&c1);
493
+					ERR("failed to convert RVE to string\n");
494
+					ret = E_UNSPEC;
495
+					goto error;
496
+				}
497
+				i = route_lookup(&main_rt, s.s);
498
+				if (unlikely(i < 0)) {
499
+					ERR("route \"%s\" not found at %s:%d\n",
500
+							s.s, (a->cfile)?a->cfile:"line", a->cline);
501
+					rval_cache_clean(&c1);
502
+					s.s = 0;
503
+					ret = E_SCRIPT;
504
+					goto error;
505
+				}
506
+				rval_cache_clean(&c1);
507
+				s.s = 0;
508
+			} else {
485 509
 				LOG(L_CRIT, "BUG: do_action: bad route() type %d\n",
486 510
 						a->val[0].type);
487 511
 				ret=E_BUG;
488 512
 				goto error;
489 513
 			}
490
-			if ((a->val[0].u.number>=main_rt.idx)||(a->val[0].u.number<0)){
514
+			if (unlikely((i>=main_rt.idx)||(i<0))){
491 515
 				LOG(L_ERR, "ERROR: invalid routing table number in"
492
-							"route(%lu)\n", a->val[0].u.number);
516
+							"route(%lu) at %s:%d\n", a->val[0].u.number,
517
+							(a->cfile)?a->cfile:"line", a->cline);
493 518
 				ret=E_CFG;
494 519
 				goto error;
495 520
 			}
496
-			/*ret=((ret=run_actions(rlist[a->val[0].u.number], msg))<0)?ret:1;*/
497
-			ret=run_actions(h, main_rt.rlist[a->val[0].u.number], msg);
521
+			/*ret=((ret=run_actions(rlist[a->val[0].u.number],msg))<0)?ret:1;*/
522
+			ret=run_actions(h, main_rt.rlist[i], msg);
498 523
 			h->last_retcode=ret;
499 524
 			_last_returned_code = h->last_retcode;
500 525
 			h->run_flags&=~(RETURN_R_F|BREAK_R_F); /* absorb return & break */
... ...
@@ -3042,7 +3042,16 @@ cmd:
3042 3042
 	}
3043 3043
 	| ERROR error { $$=0; yyerror("missing '(' or ')' ?"); }
3044 3044
 	| ERROR LPAREN error RPAREN { $$=0; yyerror("bad error argument"); }
3045
-	| ROUTE LPAREN route_name RPAREN	{
3045
+	| ROUTE LPAREN rval_expr RPAREN	{
3046
+		if ($3) {
3047
+			$$ = mk_action(ROUTE_T, 1, RVE_ST, (void*)$3);
3048
+			set_cfg_pos($$);
3049
+		} else {
3050
+			$$ = 0;
3051
+			YYERROR;
3052
+		}
3053
+	}
3054
+	| ROUTE LPAREN ID RPAREN	{
3046 3055
 		if ($3) {
3047 3056
 			$$ = mk_action(ROUTE_T, 1, STRING_ST, (void*)$3);
3048 3057
 			set_cfg_pos($$);
... ...
@@ -639,6 +639,7 @@ int fix_actions(struct action* a)
639 639
 	struct lvalue* lval;
640 640
 	struct rval_expr* rve;
641 641
 	struct rval_expr* err_rve;
642
+	struct rvalue* rv;
642 643
 	enum rval_type rve_type, err_type, expected_type;
643 644
 
644 645
 	
... ...
@@ -1022,10 +1023,38 @@ int fix_actions(struct action* a)
1022 1022
 				t->val[0].type=STR_ST;
1023 1023
 				break;
1024 1024
 			case ROUTE_T:
1025
+				if (t->val[0].type == RVE_ST) {
1026
+					rve=(struct rval_expr*)t->val[0].u.data;
1027
+					if (!rve_is_constant(rve)) {
1028
+						if ((ret=fix_rval_expr(&t->val[0].u.data)) < 0){
1029
+							ERR("route() failed to fix rve at %s:%d\n",
1030
+								(t->cfile)?t->cfile:"line", t->cline);
1031
+							ret = E_BUG;
1032
+							goto error;
1033
+						}
1034
+					} else {
1035
+						/* rve is constant => replace it with a string */
1036
+						if ((rv = rval_expr_eval(0, 0, rve)) == 0 ||
1037
+								rval_get_str(0, 0, &s, rv, 0) < 0) {
1038
+							/* out of mem. or bug ? */
1039
+							rval_destroy(rv);
1040
+							ERR("route() failed to fix ct. rve at %s:%d\n",
1041
+								(t->cfile)?t->cfile:"line", t->cline);
1042
+							ret = E_BUG;
1043
+							goto error;
1044
+						}
1045
+						rval_destroy(rv);
1046
+						rve_destroy(rve);
1047
+						t->val[0].type = STRING_ST;
1048
+						t->val[0].u.string = s.s;
1049
+						t->val[0].u.str.len = s.len; /* not used */
1050
+						/* fall-through the STRING_ST if */
1051
+					}
1052
+				}
1025 1053
 				if (t->val[0].type == STRING_ST) {
1026 1054
 					i=route_lookup(&main_rt, t->val[0].u.string);
1027 1055
 					if (i < 0) {
1028
-						ERR("route \"%s\" not found at %s:%d\n", 
1056
+						ERR("route \"%s\" not found at %s:%d\n",
1029 1057
 								t->val[0].u.string,
1030 1058
 								(t->cfile)?t->cfile:"line", t->cline);
1031 1059
 						ret = E_SCRIPT;
... ...
@@ -1034,7 +1063,8 @@ int fix_actions(struct action* a)
1034 1034
 					t->val[0].type = NUMBER_ST;
1035 1035
 					pkg_free(t->val[0].u.string);
1036 1036
 					t->val[0].u.number = i;
1037
-				} else if (t->val[0].type != NUMBER_ST) {
1037
+				} else if (t->val[0].type != NUMBER_ST &&
1038
+							t->val[0].type != RVE_ST) {
1038 1039
 					BUG("invalid subtype %d for route()\n",
1039 1040
 								t->val[0].type);
1040 1041
 					ret = E_BUG;