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.
... | ... |
@@ -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; |