/src/kamailio/src/core/lvalue.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2008 iptelorg GmbH |
3 | | * |
4 | | * Permission to use, copy, modify, and distribute this software for any |
5 | | * purpose with or without fee is hereby granted, provided that the above |
6 | | * copyright notice and this permission notice appear in all copies. |
7 | | * |
8 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | | */ |
16 | | |
17 | | /** |
18 | | * @file |
19 | | * @brief Kamailio core :: lvalues (assignment) |
20 | | * \ingroup core |
21 | | * Module: \ref core |
22 | | */ |
23 | | |
24 | | #include "lvalue.h" |
25 | | #include "dprint.h" |
26 | | #include "route.h" |
27 | | |
28 | | static char _lval_empty_buf[2] = {0}; |
29 | | static str _lval_empty = {_lval_empty_buf, 0}; |
30 | | |
31 | | /* callback to log assign actions */ |
32 | | static log_assign_action_f _log_assign_action = NULL; |
33 | | |
34 | | /** |
35 | | * @brief set callback function log assign actions |
36 | | */ |
37 | | void set_log_assign_action_cb(log_assign_action_f f) |
38 | 0 | { |
39 | 0 | _log_assign_action = f; |
40 | 0 | } |
41 | | |
42 | | /** |
43 | | * @brief eval rve and assign the result to an avp |
44 | | * |
45 | | * eval rve and assign the result to an avp, lv->lv.avp=eval(rve) |
46 | | * based on do_action() ASSIGN_T. |
47 | | * @param h - script context |
48 | | * @param msg - sip msg |
49 | | * @param lv - lvalue |
50 | | * @param rv - rvalue expression |
51 | | * @return >= 0 on success (expr. bool value), -1 on error |
52 | | */ |
53 | | inline static int lval_avp_assign(struct run_act_ctx *h, struct sip_msg *msg, |
54 | | struct lvalue *lv, struct rvalue *rv) |
55 | 0 | { |
56 | 0 | avp_spec_t *avp; |
57 | 0 | avp_t *r_avp; |
58 | 0 | avp_t *avp_mark; |
59 | 0 | pv_value_t pval; |
60 | 0 | int_str value; |
61 | 0 | unsigned short flags; |
62 | 0 | struct search_state st; |
63 | 0 | int ret, v, destroy_pval; |
64 | 0 | int avp_add; |
65 | |
|
66 | | #if 0 |
67 | | #define AVP_ASSIGN_NOVAL() \ |
68 | | /* unknown value => reset the avp in function of its type */ \ |
69 | | flags = avp->type; \ |
70 | | if(flags & AVP_VAL_STR) { \ |
71 | | value.s.s = ""; \ |
72 | | value.s.len = 0; \ |
73 | | } else { \ |
74 | | value.n = 0; \ |
75 | | } |
76 | | #endif |
77 | 0 | #define AVP_ASSIGN_NOVAL() \ |
78 | | /* no value => delete avp */ \ |
79 | 0 | avp_add = 0 |
80 | |
|
81 | 0 | destroy_pval = 0; |
82 | 0 | flags = 0; |
83 | 0 | avp = &lv->lv.avps; |
84 | 0 | ret = 0; |
85 | 0 | avp_add = 1; |
86 | |
|
87 | 0 | switch(rv->type) { |
88 | 0 | case RV_NONE: |
89 | 0 | LM_BUG("non-initialized rval / rval expr \n"); |
90 | | /* unknown value => reset the avp in function of its type */ |
91 | 0 | flags = avp->type; |
92 | 0 | AVP_ASSIGN_NOVAL(); |
93 | 0 | ret = -1; |
94 | 0 | break; |
95 | 0 | case RV_LONG: |
96 | 0 | value.n = rv->v.l; |
97 | 0 | flags = avp->type & ~AVP_VAL_STR; |
98 | 0 | ret = !(!value.n); |
99 | 0 | break; |
100 | 0 | case RV_STR: |
101 | 0 | value.s = rv->v.s; |
102 | 0 | flags = avp->type | AVP_VAL_STR; |
103 | 0 | ret = (value.s.len > 0); |
104 | 0 | break; |
105 | 0 | case RV_ACTION_ST: |
106 | 0 | flags = avp->type & ~AVP_VAL_STR; |
107 | 0 | if(rv->v.action) { |
108 | 0 | value.n = run_actions_safe(h, rv->v.action, msg); |
109 | | /* catch return & break in expr*/ |
110 | 0 | h->run_flags &= ~(RETURN_R_F | BREAK_R_F); |
111 | 0 | } else |
112 | 0 | value.n = -1; |
113 | 0 | ret = value.n; |
114 | 0 | break; |
115 | 0 | case RV_BEXPR: /* logic/boolean expr. */ |
116 | 0 | value.n = eval_expr(h, rv->v.bexpr, msg); |
117 | 0 | if(unlikely(value.n < 0)) { |
118 | 0 | if(value.n == EXPR_DROP) /* hack to quit on drop */ |
119 | 0 | goto drop; |
120 | 0 | LM_WARN("error in expression\n"); |
121 | 0 | value.n = 0; /* expr. is treated as false */ |
122 | 0 | } |
123 | 0 | flags = avp->type & ~AVP_VAL_STR; |
124 | 0 | ret = value.n; |
125 | 0 | break; |
126 | 0 | case RV_SEL: |
127 | 0 | flags = avp->type | AVP_VAL_STR; |
128 | 0 | v = run_select(&value.s, &rv->v.sel, msg); |
129 | 0 | if(unlikely(v != 0)) { |
130 | 0 | value.s = _lval_empty; |
131 | 0 | if(v < 0) { |
132 | 0 | ret = -1; |
133 | 0 | break; |
134 | 0 | } /* v>0 */ |
135 | 0 | } |
136 | 0 | ret = (value.s.len > 0); |
137 | 0 | break; |
138 | 0 | case RV_AVP: |
139 | 0 | avp_mark = 0; |
140 | 0 | if(unlikely((rv->v.avps.type & AVP_INDEX_ALL) == AVP_INDEX_ALL)) { |
141 | | /* special case: add the value to the avp */ |
142 | 0 | r_avp = search_first_avp( |
143 | 0 | rv->v.avps.type, rv->v.avps.name, &value, &st); |
144 | 0 | while(r_avp) { |
145 | | /* We take only the val type from the source avp |
146 | | * and reset the class, track flags and name type */ |
147 | 0 | flags = (avp->type & ~(AVP_INDEX_ALL | AVP_VAL_STR)) |
148 | 0 | | (r_avp->flags |
149 | 0 | & ~(AVP_CLASS_ALL | AVP_TRACK_ALL |
150 | 0 | | AVP_NAME_STR | AVP_NAME_RE)); |
151 | 0 | if(add_avp_before(avp_mark, flags, avp->name, value) < 0) { |
152 | 0 | LM_ERR("failed to assign avp\n"); |
153 | 0 | ret = -1; |
154 | 0 | goto error; |
155 | 0 | } |
156 | | /* move the mark, so the next found AVP will come before |
157 | | * the one currently added so they will have the same |
158 | | * order as in the source list */ |
159 | 0 | if(avp_mark) |
160 | 0 | avp_mark = avp_mark->next; |
161 | 0 | else |
162 | 0 | avp_mark = search_first_avp(flags, avp->name, 0, 0); |
163 | 0 | r_avp = search_next_avp(&st, &value); |
164 | 0 | } |
165 | 0 | ret = 1; |
166 | 0 | goto end; |
167 | 0 | } else { |
168 | | /* normal case, value is replaced */ |
169 | 0 | r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name, |
170 | 0 | &value, rv->v.avps.index); |
171 | 0 | if(likely(r_avp)) { |
172 | | /* take only the val type from the source avp |
173 | | * and reset the class, track flags and name type */ |
174 | 0 | flags = (avp->type & ~AVP_VAL_STR) |
175 | 0 | | (r_avp->flags |
176 | 0 | & ~(AVP_CLASS_ALL | AVP_TRACK_ALL |
177 | 0 | | AVP_NAME_STR | AVP_NAME_RE)); |
178 | 0 | ret = 1; |
179 | 0 | } else { |
180 | | /* on error, keep the type of the assigned avp, but |
181 | | * reset it to an empty value */ |
182 | 0 | AVP_ASSIGN_NOVAL(); |
183 | 0 | ret = 0; |
184 | 0 | break; |
185 | 0 | } |
186 | 0 | } |
187 | 0 | break; |
188 | 0 | case RV_PVAR: |
189 | 0 | memset(&pval, 0, sizeof(pval)); |
190 | 0 | if(likely(pv_get_spec_value(msg, &rv->v.pvs, &pval) == 0)) { |
191 | 0 | destroy_pval = 1; |
192 | 0 | if(pval.flags & PV_TYPE_INT) { |
193 | 0 | value.n = pval.ri; |
194 | 0 | ret = value.n; |
195 | 0 | flags = avp->type & ~AVP_VAL_STR; |
196 | 0 | } else if(pval.flags & PV_VAL_STR) { |
197 | 0 | value.s = pval.rs; |
198 | 0 | ret = (value.s.len > 0); |
199 | 0 | flags = avp->type | AVP_VAL_STR; |
200 | 0 | } else if(pval.flags == PV_VAL_NONE |
201 | 0 | || (pval.flags & (PV_VAL_NULL | PV_VAL_EMPTY))) { |
202 | 0 | AVP_ASSIGN_NOVAL(); |
203 | 0 | ret = 0; |
204 | 0 | } |
205 | 0 | } else { |
206 | | /* non existing pvar */ |
207 | | /* on error, keep the type of the assigned avp, but |
208 | | * reset it to an empty value */ |
209 | 0 | AVP_ASSIGN_NOVAL(); |
210 | 0 | ret = 0; |
211 | 0 | } |
212 | 0 | break; |
213 | 0 | } |
214 | | /* If the left attr was specified without indexing brackets delete |
215 | | * existing AVPs before adding the new value */ |
216 | 0 | delete_avp(avp->type, avp->name); |
217 | 0 | if(avp_add && (add_avp(flags & ~AVP_INDEX_ALL, avp->name, value) < 0)) { |
218 | 0 | LM_ERR("failed to assign value to avp\n"); |
219 | 0 | goto error; |
220 | 0 | } |
221 | 0 | end: |
222 | 0 | if(destroy_pval) |
223 | 0 | pv_value_destroy(&pval); |
224 | 0 | return ret; |
225 | 0 | error: |
226 | 0 | if(destroy_pval) |
227 | 0 | pv_value_destroy(&pval); |
228 | 0 | return -1; |
229 | 0 | drop: |
230 | 0 | if(destroy_pval) |
231 | 0 | pv_value_destroy(&pval); |
232 | 0 | return EXPR_DROP; |
233 | 0 | } |
234 | | |
235 | | |
236 | | /** |
237 | | * @brief eval rve and assign the result to a pvar |
238 | | * |
239 | | * eval rve and assign the result to a pvar, lv->lv.pvar=eval(rve) |
240 | | * based on do_action() ASSIGN_T. |
241 | | * @param h - script context |
242 | | * @param msg - sip msg |
243 | | * @param lv - lvalue |
244 | | * @param rv - rvalue expression |
245 | | * @return >= 0 on success (expr. bool value), -1 on error |
246 | | */ |
247 | | inline static int lval_pvar_assign(struct run_act_ctx *h, struct sip_msg *msg, |
248 | | struct lvalue *lv, struct rvalue *rv) |
249 | 0 | { |
250 | 0 | pv_spec_t *pvar; |
251 | 0 | pv_value_t pval; |
252 | 0 | avp_t *r_avp; |
253 | 0 | int_str avp_val; |
254 | 0 | int ret; |
255 | 0 | int v; |
256 | 0 | int destroy_pval; |
257 | |
|
258 | 0 | #define PVAR_ASSIGN_NOVAL() \ |
259 | | /* no value found => "undefine" */ \ |
260 | 0 | pv_get_null(msg, 0, &pval) |
261 | |
|
262 | 0 | destroy_pval = 0; |
263 | 0 | pvar = lv->lv.pvs; |
264 | 0 | if(unlikely(!pv_is_w(pvar))) { |
265 | 0 | LM_ERR("read only pvar\n"); |
266 | 0 | goto error; |
267 | 0 | } |
268 | 0 | memset(&pval, 0, sizeof(pval)); |
269 | 0 | ret = 0; |
270 | 0 | switch(rv->type) { |
271 | 0 | case RV_NONE: |
272 | 0 | LM_BUG("non-initialized rval / rval expr \n"); |
273 | 0 | PVAR_ASSIGN_NOVAL(); |
274 | 0 | ret = -1; |
275 | 0 | break; |
276 | 0 | case RV_LONG: |
277 | 0 | pval.flags = PV_TYPE_INT | PV_VAL_INT; |
278 | 0 | pval.ri = rv->v.l; |
279 | 0 | ret = !(!pval.ri); |
280 | 0 | break; |
281 | 0 | case RV_STR: |
282 | 0 | pval.flags = PV_VAL_STR; |
283 | 0 | pval.rs = rv->v.s; |
284 | 0 | ret = (pval.rs.len > 0); |
285 | 0 | break; |
286 | 0 | case RV_ACTION_ST: |
287 | 0 | pval.flags = PV_TYPE_INT | PV_VAL_INT; |
288 | 0 | if(rv->v.action) { |
289 | 0 | pval.ri = run_actions_safe(h, rv->v.action, msg); |
290 | | /* catch return & break in expr*/ |
291 | 0 | h->run_flags &= ~(RETURN_R_F | BREAK_R_F); |
292 | 0 | } else |
293 | 0 | pval.ri = 0; |
294 | 0 | ret = !(!pval.ri); |
295 | 0 | break; |
296 | 0 | case RV_BEXPR: /* logic/boolean expr. */ |
297 | 0 | pval.flags = PV_TYPE_INT | PV_VAL_INT; |
298 | 0 | pval.ri = eval_expr(h, rv->v.bexpr, msg); |
299 | 0 | if(unlikely(pval.ri < 0)) { |
300 | 0 | if(pval.ri == EXPR_DROP) /* hack to quit on drop */ |
301 | 0 | goto drop; |
302 | 0 | LM_WARN("error in expression\n"); |
303 | 0 | pval.ri = 0; /* expr. is treated as false */ |
304 | 0 | } |
305 | 0 | ret = !(!pval.ri); |
306 | 0 | break; |
307 | 0 | case RV_SEL: |
308 | 0 | pval.flags = PV_VAL_STR; |
309 | 0 | v = run_select(&pval.rs, &rv->v.sel, msg); |
310 | 0 | if(unlikely(v != 0)) { |
311 | 0 | pval.flags |= PV_VAL_EMPTY; |
312 | 0 | pval.rs = _lval_empty; |
313 | 0 | if(v < 0) { |
314 | 0 | ret = -1; |
315 | 0 | break; |
316 | 0 | } |
317 | 0 | } |
318 | 0 | ret = (pval.rs.len > 0); |
319 | 0 | break; |
320 | 0 | case RV_AVP: |
321 | 0 | r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name, |
322 | 0 | &avp_val, rv->v.avps.index); |
323 | 0 | if(likely(r_avp)) { |
324 | 0 | if(r_avp->flags & AVP_VAL_STR) { |
325 | 0 | pval.flags = PV_VAL_STR; |
326 | 0 | pval.rs = avp_val.s; |
327 | 0 | ret = (pval.rs.len > 0); |
328 | 0 | } else { |
329 | 0 | pval.flags = PV_TYPE_INT | PV_VAL_INT; |
330 | 0 | pval.ri = avp_val.n; |
331 | 0 | ret = !(!pval.ri); |
332 | 0 | } |
333 | 0 | } else { |
334 | 0 | PVAR_ASSIGN_NOVAL(); |
335 | 0 | ret = 0; /* avp not defined (valid case) */ |
336 | 0 | break; |
337 | 0 | } |
338 | 0 | break; |
339 | 0 | case RV_PVAR: |
340 | 0 | if(likely(pv_get_spec_value(msg, &rv->v.pvs, &pval) == 0)) { |
341 | 0 | destroy_pval = 1; |
342 | 0 | if(pval.flags & PV_TYPE_INT) { |
343 | 0 | ret = !(!pval.ri); |
344 | 0 | } else if(pval.flags & PV_VAL_STR) { |
345 | 0 | ret = (pval.rs.len > 0); |
346 | 0 | } else { |
347 | | /* no value / not defined (e.g. avp) -> keep the flags */ |
348 | 0 | ret = 0; |
349 | 0 | } |
350 | 0 | } else { |
351 | 0 | LM_ERR("non existing right pvar\n"); |
352 | 0 | PVAR_ASSIGN_NOVAL(); |
353 | 0 | ret = -1; |
354 | 0 | } |
355 | 0 | break; |
356 | 0 | } |
357 | 0 | if(unlikely(pvar->setf(msg, &pvar->pvp, EQ_T, &pval) < 0)) { |
358 | 0 | LM_ERR("setting pvar failed\n"); |
359 | 0 | goto error; |
360 | 0 | } |
361 | 0 | if(destroy_pval) |
362 | 0 | pv_value_destroy(&pval); |
363 | 0 | return ret; |
364 | 0 | error: |
365 | 0 | if(destroy_pval) |
366 | 0 | pv_value_destroy(&pval); |
367 | 0 | return -1; |
368 | 0 | drop: |
369 | 0 | if(destroy_pval) |
370 | 0 | pv_value_destroy(&pval); |
371 | 0 | return EXPR_DROP; |
372 | 0 | } |
373 | | |
374 | | |
375 | | /** eval rve and assign the result to lv |
376 | | * lv=eval(rve) |
377 | | * |
378 | | * @param h - script context |
379 | | * @param msg - sip msg |
380 | | * @param lv - lvalue |
381 | | * @param rve - rvalue expression |
382 | | * @return >= 0 on success (expr. bool value), -1 on error |
383 | | */ |
384 | | int lval_assign(struct run_act_ctx *h, struct sip_msg *msg, struct lvalue *lv, |
385 | | struct rval_expr *rve) |
386 | 0 | { |
387 | 0 | struct rvalue *rv; |
388 | 0 | int ret; |
389 | |
|
390 | 0 | ret = -1; |
391 | 0 | rv = rval_expr_eval(h, msg, rve); |
392 | 0 | if(unlikely(rv == 0)) { |
393 | 0 | LM_ERR("rval expression evaluation failed (%d,%d-%d,%d)\n", |
394 | 0 | rve->fpos.s_line, rve->fpos.s_col, rve->fpos.e_line, |
395 | 0 | rve->fpos.e_col); |
396 | 0 | goto error; |
397 | 0 | } |
398 | 0 | switch(lv->type) { |
399 | 0 | case LV_NONE: |
400 | 0 | LM_BUG("uninitialized/invalid lvalue (%d) (cfg line: %d)\n", |
401 | 0 | lv->type, rve->fpos.s_line); |
402 | 0 | goto error; |
403 | 0 | case LV_AVP: |
404 | 0 | ret = lval_avp_assign(h, msg, lv, rv); |
405 | 0 | break; |
406 | 0 | case LV_PVAR: |
407 | 0 | ret = lval_pvar_assign(h, msg, lv, rv); |
408 | 0 | break; |
409 | 0 | } |
410 | 0 | if(unlikely(ret < 0)) { |
411 | 0 | LM_ERR("assignment failed at pos: (%d,%d-%d,%d)\n", rve->fpos.s_line, |
412 | 0 | rve->fpos.s_col, rve->fpos.e_line, rve->fpos.e_col); |
413 | 0 | } else { |
414 | 0 | if(unlikely(_log_assign_action != NULL)) |
415 | 0 | _log_assign_action(msg, lv); |
416 | 0 | } |
417 | 0 | rval_destroy(rv); |
418 | 0 | return ret; |
419 | 0 | error: |
420 | 0 | if(rv) |
421 | 0 | rval_destroy(rv); |
422 | 0 | return ret; |
423 | 0 | } |