Module: sip-router
Branch: master
Commit: d75db62dc2c859165fc3f72b256393678fcd00f5
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=d75db62…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)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;