Module: sip-router Branch: master Commit: d75db62dc2c859165fc3f72b256393678fcd00f5 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=d75db62d...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Thu Mar 25 23:20:17 2010 +0100
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.
---
NEWS | 1 + action.c | 35 ++++++++++++++++++++++++++++++----- cfg.y | 11 ++++++++++- route.c | 34 ++++++++++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 8 deletions(-)
diff --git a/NEWS b/NEWS index 1e5d4b5..de353af 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ core: - global, per protocol blacklist ignore masks (via extended send_flags). See dst_blacklist_udp_imask a.s.o (dst_blacklist_*_imask). - per message blacklist ignore masks + - route() now supports rvalue expressions (e.g. route("test"+$i))
new config variables: - dst_blacklist_udp_imask - global blacklist events ignore mask for udp diff --git a/action.c b/action.c index c4823e6..70cec69 100644 --- a/action.c +++ b/action.c @@ -481,20 +481,45 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg) ret=1; break; case ROUTE_T: - if (a->val[0].type!=NUMBER_ST){ + if (likely(a->val[0].type == NUMBER_ST)) + i = a->val[0].u.number; + else if (a->val[0].type == RVE_ST) { + rv = rval_expr_eval(h, msg, a->val[0].u.data); + rval_cache_init(&c1); + if (unlikely(rv == 0 || + rval_get_tmp_str(h, msg, &s, rv, 0, &c1) < 0)) { + rval_destroy(rv); + rval_cache_clean(&c1); + ERR("failed to convert RVE to string\n"); + ret = E_UNSPEC; + goto error; + } + i = route_lookup(&main_rt, s.s); + if (unlikely(i < 0)) { + ERR("route "%s" not found at %s:%d\n", + s.s, (a->cfile)?a->cfile:"line", a->cline); + rval_cache_clean(&c1); + s.s = 0; + ret = E_SCRIPT; + goto error; + } + rval_cache_clean(&c1); + s.s = 0; + } else { LOG(L_CRIT, "BUG: do_action: bad route() type %d\n", a->val[0].type); ret=E_BUG; goto error; } - if ((a->val[0].u.number>=main_rt.idx)||(a->val[0].u.number<0)){ + if (unlikely((i>=main_rt.idx)||(i<0))){ LOG(L_ERR, "ERROR: invalid routing table number in" - "route(%lu)\n", a->val[0].u.number); + "route(%lu) at %s:%d\n", a->val[0].u.number, + (a->cfile)?a->cfile:"line", a->cline); ret=E_CFG; goto error; } - /*ret=((ret=run_actions(rlist[a->val[0].u.number], msg))<0)?ret:1;*/ - ret=run_actions(h, main_rt.rlist[a->val[0].u.number], msg); + /*ret=((ret=run_actions(rlist[a->val[0].u.number],msg))<0)?ret:1;*/ + ret=run_actions(h, main_rt.rlist[i], msg); h->last_retcode=ret; _last_returned_code = h->last_retcode; h->run_flags&=~(RETURN_R_F|BREAK_R_F); /* absorb return & break */ diff --git a/cfg.y b/cfg.y index 2b12b67..4769ae1 100644 --- a/cfg.y +++ b/cfg.y @@ -3042,7 +3042,16 @@ cmd: } | ERROR error { $$=0; yyerror("missing '(' or ')' ?"); } | ERROR LPAREN error RPAREN { $$=0; yyerror("bad error argument"); } - | ROUTE LPAREN route_name RPAREN { + | ROUTE LPAREN rval_expr RPAREN { + if ($3) { + $$ = mk_action(ROUTE_T, 1, RVE_ST, (void*)$3); + set_cfg_pos($$); + } else { + $$ = 0; + YYERROR; + } + } + | ROUTE LPAREN ID RPAREN { if ($3) { $$ = mk_action(ROUTE_T, 1, STRING_ST, (void*)$3); set_cfg_pos($$); diff --git a/route.c b/route.c index 729860e..b1cd14c 100644 --- a/route.c +++ b/route.c @@ -639,6 +639,7 @@ int fix_actions(struct action* a) struct lvalue* lval; struct rval_expr* rve; struct rval_expr* err_rve; + struct rvalue* rv; enum rval_type rve_type, err_type, expected_type;
@@ -1022,10 +1023,38 @@ int fix_actions(struct action* a) t->val[0].type=STR_ST; break; case ROUTE_T: + if (t->val[0].type == RVE_ST) { + rve=(struct rval_expr*)t->val[0].u.data; + if (!rve_is_constant(rve)) { + if ((ret=fix_rval_expr(&t->val[0].u.data)) < 0){ + ERR("route() failed to fix rve at %s:%d\n", + (t->cfile)?t->cfile:"line", t->cline); + ret = E_BUG; + goto error; + } + } else { + /* rve is constant => replace it with a string */ + if ((rv = rval_expr_eval(0, 0, rve)) == 0 || + rval_get_str(0, 0, &s, rv, 0) < 0) { + /* out of mem. or bug ? */ + rval_destroy(rv); + ERR("route() failed to fix ct. rve at %s:%d\n", + (t->cfile)?t->cfile:"line", t->cline); + ret = E_BUG; + goto error; + } + rval_destroy(rv); + rve_destroy(rve); + t->val[0].type = STRING_ST; + t->val[0].u.string = s.s; + t->val[0].u.str.len = s.len; /* not used */ + /* fall-through the STRING_ST if */ + } + } if (t->val[0].type == STRING_ST) { i=route_lookup(&main_rt, t->val[0].u.string); if (i < 0) { - ERR("route "%s" not found at %s:%d\n", + ERR("route "%s" not found at %s:%d\n", t->val[0].u.string, (t->cfile)?t->cfile:"line", t->cline); ret = E_SCRIPT; @@ -1034,7 +1063,8 @@ int fix_actions(struct action* a) t->val[0].type = NUMBER_ST; pkg_free(t->val[0].u.string); t->val[0].u.number = i; - } else if (t->val[0].type != NUMBER_ST) { + } else if (t->val[0].type != NUMBER_ST && + t->val[0].type != RVE_ST) { BUG("invalid subtype %d for route()\n", t->val[0].type); ret = E_BUG;