Skip to content

Commit 55f4c9c

Browse files
committed
core: add support for returning values through return() function
1 parent 318d838 commit 55f4c9c

File tree

5 files changed

+315
-7
lines changed

5 files changed

+315
-7
lines changed

action.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ static int route_param_get(struct sip_msg *msg, pv_param_t *ip,
114114
/* (0 if drop or break encountered, 1 if not ) */
115115
static inline int run_actions(struct action* a, struct sip_msg* msg)
116116
{
117-
int ret, _;
117+
int ret, _, ret_lvl;
118118
str top_route;
119119

120120
if (route_stack_size > ROUTE_MAX_REC_LEV) {
@@ -133,12 +133,16 @@ static inline int run_actions(struct action* a, struct sip_msg* msg)
133133
goto error;
134134
}
135135

136+
ret_lvl=script_return_push();
137+
136138
ret=run_action_list(a, msg);
137139

138140
/* if 'return', reset the flag */
139141
if(action_flags&ACT_FL_RETURN)
140142
action_flags &= ~ACT_FL_RETURN;
141143

144+
script_return_pop(ret_lvl);
145+
142146
return ret;
143147

144148
error:
@@ -682,6 +686,10 @@ int do_action(struct action* a, struct sip_msg* msg)
682686
action_flags |= ACT_FL_EXIT;
683687
break;
684688
case RETURN_T:
689+
if (a->elem[1].type == EXPR_ST)
690+
script_return_set(msg, a->elem[1].u.data);
691+
else
692+
script_return_set(msg, NULL);
685693
script_trace("core", "return", msg, a->file, a->line) ;
686694
if (a->elem[0].type == SCRIPTVAR_ST)
687695
{

cfg.y

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ struct port_range {
152152
int max;
153153
struct port_range *next;
154154
} *pr_tmp;
155+
static struct script_return_param sr_tmp;
155156

156157
static inline void warn(char* s);
157158
static struct socket_id* mk_listen_id(char*, enum sip_protos, int);
@@ -160,6 +161,16 @@ static struct socket_id* set_listen_id_adv(struct socket_id *, char *, int);
160161
static struct multi_str *new_string(char *s);
161162
static struct port_range* mk_port_range(int, int);
162163
static int parse_ipnet(char *in, int len, struct net **ipnet);
164+
static struct script_return_param *mk_script_return(enum script_return_type type)
165+
{
166+
struct script_return_param *param = pkg_malloc(sizeof *param);
167+
if (!param)
168+
return NULL;
169+
*param = sr_tmp;
170+
param->type = type;
171+
param->next = NULL;
172+
return param;
173+
}
163174

164175
extern int line;
165176
extern int column;
@@ -249,6 +260,7 @@ extern int cfg_parse_only_routes;
249260
struct _pv_spec *specval;
250261
struct multi_str* multistr;
251262
struct port_range* portrange;
263+
struct script_return_param* return_params;
252264
}
253265

254266
/* terminals */
@@ -493,6 +505,7 @@ extern int cfg_parse_only_routes;
493505
%type <strval> folded_string
494506
%type <multistr> multi_string
495507
%type <portrange> portrange
508+
%type <return_params> return_params return_param
496509

497510
/*
498511
* known shift/reduce conflicts (the default action, shift, is correct):
@@ -2429,6 +2442,17 @@ async_func: ID LPAREN RPAREN {
24292442
}
24302443
;
24312444

2445+
return_param: script_var { sr_tmp.rspec = $1; $$ = mk_script_return(SCRIPT_ROUTE_RET_VAR);}
2446+
| snumber { sr_tmp.rint = $1; $$ = mk_script_return(SCRIPT_ROUTE_RET_INT);}
2447+
| STRING { sr_tmp.rstr.s = $1; sr_tmp.rstr.len = strlen($1);
2448+
$$ = mk_script_return(SCRIPT_ROUTE_RET_STR);}
2449+
| NULLV { $$ = mk_script_return(SCRIPT_ROUTE_RET_NULL);}
2450+
;
2451+
2452+
return_params: return_param { $$ = $1; }
2453+
| return_params COMMA return_param { $3->next = $1; $$ = $3; }
2454+
;
2455+
24322456
cmd: ASSERT LPAREN exp COMMA STRING RPAREN {
24332457
mk_action2( $$, ASSERT_T, EXPR_ST, STRING_ST, $3, $5);
24342458
}
@@ -2437,16 +2461,58 @@ cmd: ASSERT LPAREN exp COMMA STRING RPAREN {
24372461
| EXIT {mk_action0( $$, EXIT_T); }
24382462
| EXIT LPAREN RPAREN {mk_action0( $$, EXIT_T); }
24392463
| RETURN script_var
2440-
{mk_action1( $$, RETURN_T, SCRIPTVAR_ST, (void*)$2); }
2464+
{mk_action2( $$, RETURN_T,
2465+
SCRIPTVAR_ST,
2466+
NULLV_ST,
2467+
(void*)$2,
2468+
NULL); }
24412469
| RETURN LPAREN script_var RPAREN
2442-
{mk_action1( $$, RETURN_T, SCRIPTVAR_ST, (void*)$3); }
2470+
{mk_action2( $$, RETURN_T,
2471+
SCRIPTVAR_ST,
2472+
NULLV_ST,
2473+
(void*)$3,
2474+
NULL); }
2475+
| RETURN LPAREN script_var COMMA return_params RPAREN
2476+
{mk_action2( $$, RETURN_T,
2477+
SCRIPTVAR_ST,
2478+
EXPR_ST,
2479+
(void*)$3,
2480+
$5); }
24432481
| RETURN snumber
2444-
{mk_action1( $$, RETURN_T, NUMBER_ST, (void*)$2); }
2482+
{mk_action2( $$, RETURN_T,
2483+
NUMBER_ST,
2484+
NULLV_ST,
2485+
(void*)$2,
2486+
NULL); }
24452487
| RETURN LPAREN snumber RPAREN
2446-
{mk_action1( $$, RETURN_T, NUMBER_ST, (void*)$3); }
2488+
{mk_action2( $$, RETURN_T,
2489+
NUMBER_ST,
2490+
NULLV_ST,
2491+
(void*)$3,
2492+
NULL); }
2493+
| RETURN LPAREN snumber COMMA return_params RPAREN
2494+
{mk_action2( $$, RETURN_T,
2495+
NUMBER_ST,
2496+
EXPR_ST,
2497+
(void*)$3,
2498+
$5); }
24472499
| RETURN LPAREN RPAREN
2448-
{mk_action1( $$, RETURN_T, NUMBER_ST, (void*)1); }
2449-
| RETURN {mk_action1( $$, RETURN_T, NUMBER_ST, (void*)1); }
2500+
{mk_action2( $$, RETURN_T,
2501+
NUMBER_ST,
2502+
NULLV_ST,
2503+
(void*)1,
2504+
NULL); }
2505+
| RETURN LPAREN COMMA return_params RPAREN
2506+
{mk_action2( $$, RETURN_T,
2507+
NUMBER_ST,
2508+
EXPR_ST,
2509+
(void*)1,
2510+
$4); }
2511+
| RETURN {mk_action2( $$, RETURN_T,
2512+
NUMBER_ST,
2513+
NULLV_ST,
2514+
(void*)1,
2515+
NULL); }
24502516
| LOG_TOK LPAREN STRING RPAREN {mk_action2( $$, LOG_T, NUMBER_ST,
24512517
STRING_ST,(void*)4,$3);
24522518
}

pvar.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ int init_pvar_support(void)
149149
/* route param variable */
150150
static int pv_get_param(struct sip_msg *msg, pv_param_t *ip, pv_value_t *res);
151151
static int pv_parse_param_name(pv_spec_p sp, const str *in);
152+
static int pv_parse_return_value(pv_spec_p sp, const str *in);
152153

153154
/********** helper functions ********/
154155
/**
@@ -3618,6 +3619,56 @@ static int pv_get_xlog_level(struct sip_msg *msg, pv_param_t *param, pv_value_t
36183619
return 0;
36193620
}
36203621

3622+
static int pv_get_return_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
3623+
{
3624+
int index;
3625+
pv_value_t tv;
3626+
3627+
if (param==NULL) {
3628+
LM_CRIT("BUG - bad parameters\n");
3629+
return -1;
3630+
}
3631+
3632+
if(res == NULL)
3633+
return -1;
3634+
3635+
if (param->pvn.type == PV_NAME_INTSTR) {
3636+
if (param->pvn.u.isname.type != 0) {
3637+
LM_ERR("route $return variable accepts only integer indexes\n");
3638+
return -1;
3639+
}
3640+
index = param->pvn.u.isname.name.n;
3641+
} else {
3642+
/* pvar -> it might be another $param variable! */
3643+
if(pv_get_spec_value(msg, (pv_spec_p)(param->pvn.u.dname), &tv)!=0) {
3644+
LM_ERR("cannot get spec value\n");
3645+
return -1;
3646+
}
3647+
3648+
if(tv.flags&PV_VAL_NULL || tv.flags&PV_VAL_EMPTY) {
3649+
LM_ERR("null or empty name\n");
3650+
return -1;
3651+
}
3652+
if (!(tv.flags&PV_VAL_INT) || str2int(&tv.rs,(unsigned int*)&index) < 0) {
3653+
LM_ERR("invalid index <%.*s>\n", tv.rs.len, tv.rs.s);
3654+
return -1;
3655+
}
3656+
}
3657+
3658+
if (script_return_get(res, index) < 0) {
3659+
LM_ERR("could not get return %d\n", index);
3660+
return -1;
3661+
}
3662+
3663+
/* "normalize" integer */
3664+
if ((res->flags & PV_VAL_INT) && !(res->flags & PV_VAL_STR)) {
3665+
res->rs.s = int2str(res->ri, &res->rs.len);
3666+
res->flags |= PV_VAL_STR;
3667+
}
3668+
3669+
return 0;
3670+
}
3671+
36213672
/************** Boolean consts *****************/
36223673

36233674
static const pv_value_t pv_true = {
@@ -4201,6 +4252,8 @@ const pv_export_t _pv_names_table[] = {
42014252
0, 0, 0, 0 },
42024253
{str_const_init("xlog_level"), PVT_XLOG_LEVEL, pv_get_xlog_level,
42034254
pv_set_xlog_level, 0, 0, 0, 0 },
4255+
{str_const_init("return"), PVT_EXTRA, pv_get_return_value, 0,
4256+
pv_parse_return_value, 0, 0, 0 },
42044257
{{0,0}, 0, 0, 0, 0, 0, 0, 0}
42054258
};
42064259

@@ -5545,6 +5598,45 @@ static int pv_parse_param_name(pv_spec_p sp, const str *in)
55455598

55465599
}
55475600

5601+
static int pv_parse_return_value(pv_spec_p sp, const str *in)
5602+
{
5603+
char *p;
5604+
char *s;
5605+
pv_spec_p nsp = 0;
5606+
5607+
if(in==NULL || in->s==NULL || sp==NULL)
5608+
return -1;
5609+
p = in->s;
5610+
if(*p==PV_MARKER)
5611+
{
5612+
nsp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t));
5613+
if(nsp==NULL)
5614+
{
5615+
LM_ERR("no more memory\n");
5616+
return -1;
5617+
}
5618+
s = pv_parse_spec(in, nsp);
5619+
if(s==NULL)
5620+
{
5621+
LM_ERR("invalid name [%.*s]\n", in->len, in->s);
5622+
pv_spec_free(nsp);
5623+
return -1;
5624+
}
5625+
sp->pvp.pvn.type = PV_NAME_PVAR;
5626+
sp->pvp.pvn.u.dname = (void*)nsp;
5627+
return 0;
5628+
}
5629+
sp->pvp.pvn.u.isname.type = 0;
5630+
sp->pvp.pvn.type = PV_NAME_INTSTR;
5631+
/* do our best to convert it to an index */
5632+
if (str2int(in, (unsigned int *)&sp->pvp.pvn.u.isname.name.n) < 0) {
5633+
LM_ERR("could not convert index to int!\n");
5634+
return -1;
5635+
}
5636+
return 0;
5637+
5638+
}
5639+
55485640
static int pv_get_param(struct sip_msg *msg, pv_param_t *ip, pv_value_t *res)
55495641
{
55505642
if (!ip)

route.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,3 +2160,117 @@ int is_script_async_func_used(const char *name, int param_no)
21602160

21612161
return 0;
21622162
}
2163+
2164+
static int script_return_level = 0;
2165+
static struct script_return_value **script_return_values = NULL, *script_return_last;
2166+
2167+
int script_return_push(void)
2168+
{
2169+
struct script_return_value **tmp;
2170+
tmp = pkg_realloc(script_return_values, (script_return_level + 1) * sizeof *tmp);
2171+
if (!tmp) {
2172+
LM_ERR("could not add another return level (current=%d\n", script_return_level);
2173+
return -1;
2174+
}
2175+
script_return_values = tmp;
2176+
script_return_values[script_return_level] = NULL;
2177+
if (script_return_last)
2178+
script_return_free(&script_return_last);
2179+
return script_return_level++;
2180+
}
2181+
2182+
void script_return_pop(int level)
2183+
{
2184+
/* we leave this here, just to have a way of popping the last level */
2185+
if (script_return_last)
2186+
script_return_free(&script_return_last);
2187+
if (script_return_level < 0)
2188+
return;
2189+
if (level != script_return_level - 1) {
2190+
LM_BUG("cannot return level %d vs %d\n", level, script_return_level);
2191+
return;
2192+
}
2193+
script_return_last = script_return_values[level];
2194+
script_return_values = pkg_realloc(script_return_values,
2195+
(--script_return_level) * sizeof *script_return_values);
2196+
}
2197+
2198+
void script_return_free(struct script_return_value **values)
2199+
{
2200+
struct script_return_value *v, *n;
2201+
if (*values == NULL)
2202+
return;
2203+
for (v = *values; v; v = n) {
2204+
n = v->next;
2205+
pkg_free(v);
2206+
}
2207+
*values = NULL;
2208+
}
2209+
2210+
void script_return_set(struct sip_msg *msg, struct script_return_param *params)
2211+
{
2212+
pv_value_t val;
2213+
struct script_return_param *p;
2214+
struct script_return_value *v, *ret = NULL;
2215+
if (script_return_level <= 0) {
2216+
LM_ERR("no return level initialized\n");
2217+
return;
2218+
}
2219+
/* itertate through each parameter to store it's value */
2220+
for (p = params; p; p = p->next) {
2221+
memset(&val, 0, sizeof val);
2222+
switch (p->type) {
2223+
case SCRIPT_ROUTE_RET_INT:
2224+
val.ri = p->rint;
2225+
val.flags = PV_VAL_INT;
2226+
break;
2227+
case SCRIPT_ROUTE_RET_STR:
2228+
val.rs = p->rstr;
2229+
val.flags = PV_VAL_STR;
2230+
break;
2231+
case SCRIPT_ROUTE_RET_VAR:
2232+
if (pv_get_spec_value(msg, p->rspec, &val) != 0) {
2233+
LM_ERR("cannot get return value\n");
2234+
pv_get_null(NULL, NULL, &val);
2235+
}
2236+
break;
2237+
case SCRIPT_ROUTE_RET_NULL:
2238+
pv_get_null(NULL, NULL, &val);
2239+
break;
2240+
default:
2241+
LM_BUG("unhandled return type %d\n", p->type);
2242+
script_return_free(&ret);
2243+
return;
2244+
}
2245+
v = pkg_malloc(sizeof(*v) + ((val.flags & PV_VAL_STR)?val.rs.len:0));
2246+
if (v) {
2247+
v->val = val;
2248+
if (val.flags & PV_VAL_STR) {
2249+
v->val.rs.s = v->buf;
2250+
memcpy(v->val.rs.s, val.rs.s, val.rs.len);
2251+
}
2252+
v->next = ret;
2253+
ret = v;
2254+
} else {
2255+
LM_ERR("could not allocate return value\n");
2256+
script_return_free(&ret);
2257+
return;
2258+
}
2259+
}
2260+
if (script_return_values[script_return_level - 1])
2261+
script_return_free(&script_return_values[script_return_level - 1]);
2262+
script_return_values[script_return_level - 1] = ret;
2263+
}
2264+
2265+
int script_return_get(pv_value_t *res, int index)
2266+
{
2267+
struct script_return_value *v;
2268+
pv_get_null(NULL, NULL, res);
2269+
if (index < 0 || !script_return_last)
2270+
return 0;
2271+
for (v = script_return_last; v && index > 0; v = v->next, index--);
2272+
if (!v)
2273+
return 0;
2274+
*res = v->val;
2275+
return 1;
2276+
}

0 commit comments

Comments
 (0)