core: fix all reported doxygen errors in PV and value evaluation code
[sip-router] / lvalue.c
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 SIP-router core :: lvalues (assignment)
20  * \ingroup core
21  * Module: \ref core
22  */
23
24 /* 
25  * History:
26  * --------
27  *  2008-11-30  initial version (andrei)
28  *  2009-04-24  delete avps after finding their new value and not before
29  *               (fixed $avp=$avp)
30  *              when assigning something undefined (e.g. non-existing avp),
31  *              delete the lvalue (similar to perl)  (andrei)
32  */
33
34
35 #include "lvalue.h"
36 #include "dprint.h"
37 #include "route.h"
38
39
40
41 /**
42  * @brief eval rve and assign the result to an avp
43  * 
44  * eval rve and assign the result to an avp, lv->lv.avp=eval(rve)
45  * based on do_action() ASSIGN_T.
46  * @param h  - script context
47  * @param msg - sip msg
48  * @param lv - lvalue
49  * @param rv - rvalue expression
50  * @return >= 0 on success (expr. bool value), -1 on error
51  */
52 inline static int lval_avp_assign(struct run_act_ctx* h, struct sip_msg* msg,
53                                                                         struct lvalue* lv, struct rvalue* rv)
54 {
55         avp_spec_t* avp;
56         avp_t* r_avp;
57         avp_t* avp_mark;
58         pv_value_t pval;
59         int_str value;
60         unsigned short flags;
61         struct search_state st;
62         int ret, v, destroy_pval;
63         int avp_add;
64
65 #if 0
66         #define AVP_ASSIGN_NOVAL() \
67                 /* unknown value => reset the avp in function of its type */ \
68                 flags=avp->type; \
69                 if (flags & AVP_VAL_STR){ \
70                         value.s.s=""; \
71                         value.s.len=0; \
72                 }else{ \
73                         value.n=0; \
74                 }
75 #endif
76         #define AVP_ASSIGN_NOVAL() \
77                 /* no value => delete avp */ \
78                 avp_add=0
79         
80         destroy_pval=0;
81         flags = 0;
82         avp=&lv->lv.avps;
83         ret=0;
84         avp_add=1;
85         
86         switch(rv->type){
87                 case RV_NONE:
88                         BUG("non-intialized rval / rval expr \n");
89                         /* unknown value => reset the avp in function of its type */
90                         flags=avp->type;
91                         AVP_ASSIGN_NOVAL();
92                         ret=-1;
93                         break;
94                 case RV_INT:
95                         value.n=rv->v.l;
96                         flags=avp->type & ~AVP_VAL_STR;
97                         ret=!(!value.n);
98                         break;
99                 case RV_STR:
100                         value.s=rv->v.s;
101                         flags=avp->type | AVP_VAL_STR;
102                         ret=(value.s.len>0);
103                         break;
104                 case RV_ACTION_ST:
105                         flags=avp->type & ~AVP_VAL_STR;
106                         if (rv->v.action) {
107                                 value.n=run_actions_safe(h, rv->v.action, msg);
108                                 h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return &
109                                                                                                                     break in expr*/
110                         } else
111                                 value.n=-1;
112                         ret=value.n;
113                         break;
114                 case RV_BEXPR: /* logic/boolean expr. */
115                         value.n=eval_expr(h, rv->v.bexpr, msg);
116                         if (unlikely(value.n<0)){
117                                 if (value.n==EXPR_DROP) /* hack to quit on drop */
118                                         goto drop;
119                                 WARN("error in expression\n");
120                                 value.n=0; /* expr. is treated as false */
121                         }
122                         flags=avp->type & ~AVP_VAL_STR;
123                         ret=value.n;
124                         break;
125                 case RV_SEL:
126                         flags=avp->type|AVP_VAL_STR;
127                         v=run_select(&value.s, &rv->v.sel, msg);
128                         if (unlikely(v!=0)){
129                                 value.s.s="";
130                                 value.s.len=0;
131                                 if (v<0){
132                                         ret=-1;
133                                         break;
134                                 } /* v>0 */
135                         }
136                         ret=(value.s.len>0);
137                         break;
138                 case RV_AVP:
139                         avp_mark=0;
140                         if (unlikely((rv->v.avps.type & AVP_INDEX_ALL) == AVP_INDEX_ALL)){
141                                 /* special case: add the value to the avp */
142                                 r_avp = search_first_avp(rv->v.avps.type, rv->v.avps.name,
143                                                                                         &value, &st);
144                                 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                                         flags=(avp->type & ~(AVP_INDEX_ALL|AVP_VAL_STR)) | 
148                                                         (r_avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL|
149                                                                                                 AVP_NAME_STR|AVP_NAME_RE));
150                                         if (add_avp_before(avp_mark, flags, avp->name, value)<0){
151                                                 ERR("failed to assign avp\n");
152                                                 ret=-1;
153                                                 goto error;
154                                         }
155                                         /* move the mark, so the next found AVP will come before
156                                            the one currently added so they will have the same 
157                                            order as in the source list */
158                                         if (avp_mark) avp_mark=avp_mark->next;
159                                         else
160                                                 avp_mark=search_first_avp(flags, avp->name, 0, 0);
161                                         r_avp=search_next_avp(&st, &value);
162                                 }
163                                 ret=1;
164                                 goto end;
165                         }else{
166                                 /* normal case, value is replaced */
167                                 r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
168                                                                                         &value, rv->v.avps.index);
169                                 if (likely(r_avp)){
170                                         /* take only the val type from the source avp
171                                          * and reset the class, track flags and name type  */
172                                         flags=(avp->type & ~AVP_VAL_STR) | (r_avp->flags & 
173                                                                 ~(AVP_CLASS_ALL|AVP_TRACK_ALL|AVP_NAME_STR|
174                                                                         AVP_NAME_RE));
175                                         ret=1;
176                                 }else{
177                                         /* on error, keep the type of the assigned avp, but
178                                            reset it to an empty value */
179                                         AVP_ASSIGN_NOVAL();
180                                         ret=0;
181                                         break;
182                                 }
183                         }
184                         break;
185                 case RV_PVAR:
186                         memset(&pval, 0, sizeof(pval));
187                         if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
188                                 destroy_pval=1;
189                                 if (pval.flags & PV_TYPE_INT){
190                                         value.n=pval.ri;
191                                         ret=value.n;
192                                         flags=avp->type & ~AVP_VAL_STR;
193                                 }else if (pval.flags & PV_VAL_STR){
194                                         value.s=pval.rs;
195                                         ret=(value.s.len>0);
196                                         flags=avp->type | AVP_VAL_STR;
197                                 }else if (pval.flags==PV_VAL_NONE ||
198                                                         (pval.flags & (PV_VAL_NULL|PV_VAL_EMPTY))){
199                                         AVP_ASSIGN_NOVAL();
200                                         ret=0;
201                                 }
202                         }else{
203                                 /* non existing pvar */
204                                 /* on error, keep the type of the assigned avp, but
205                                    reset it to an empty value */
206                                 AVP_ASSIGN_NOVAL();
207                                 ret=0;
208                         }
209                         break;
210         }
211         /* If the left attr was specified without indexing brackets delete
212          * existing AVPs before adding the new value */
213         delete_avp(avp->type, avp->name);
214         if (avp_add && (add_avp(flags & ~AVP_INDEX_ALL, avp->name, value) < 0)) {
215                 ERR("failed to assign value to avp\n");
216                 goto error;
217         }
218 end:
219         if (destroy_pval) pv_value_destroy(&pval);
220         return ret;
221 error:
222         if (destroy_pval) pv_value_destroy(&pval);
223         return -1;
224 drop:
225         if (destroy_pval) pv_value_destroy(&pval);
226         return EXPR_DROP;
227 }
228
229
230
231 /**
232  * @brief eval rve and assign the result to a pvar
233  *
234  * eval rve and assign the result to a pvar, lv->lv.pvar=eval(rve)
235  * based on do_action() ASSIGN_T.
236  * @param h  - script context
237  * @param msg - sip msg
238  * @param lv - lvalue
239  * @param rv - rvalue expression
240  * @return >= 0 on success (expr. bool value), -1 on error
241  */
242 inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
243                                                                         struct lvalue* lv, struct rvalue* rv)
244 {
245         pv_spec_t* pvar;
246         pv_value_t pval;
247         avp_t* r_avp;
248         int_str avp_val;
249         int ret;
250         int v;
251         int destroy_pval;
252         
253         #define PVAR_ASSIGN_NOVAL() \
254                 /* no value found => "undefine" */ \
255                 pv_get_null(msg, 0, &pval)
256         
257         destroy_pval=0;
258         pvar=&lv->lv.pvs;
259         if (unlikely(!pv_is_w(pvar))){
260                 ERR("read only pvar\n");
261                 goto error;
262         }
263         memset(&pval, 0, sizeof(pval));
264         ret=0;
265         switch(rv->type){
266                 case RV_NONE:
267                         BUG("non-intialized rval / rval expr \n");
268                         PVAR_ASSIGN_NOVAL();
269                         ret=-1;
270                         break;
271                 case RV_INT:
272                         pval.flags=PV_TYPE_INT|PV_VAL_INT;
273                         pval.ri=rv->v.l;
274                         ret=!(!pval.ri);
275                         break;
276                 case RV_STR:
277                         pval.flags=PV_VAL_STR;
278                         pval.rs=rv->v.s;
279                         ret=(pval.rs.len>0);
280                         break;
281                 case RV_ACTION_ST:
282                         pval.flags=PV_TYPE_INT|PV_VAL_INT;
283                         if (rv->v.action) {
284                                 pval.ri=run_actions_safe(h, rv->v.action, msg);
285                                 h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return &
286                                                                                                                     break in expr*/
287                         } else
288                                 pval.ri=0;
289                         ret=!(!pval.ri);
290                         break;
291                 case RV_BEXPR: /* logic/boolean expr. */
292                         pval.flags=PV_TYPE_INT|PV_VAL_INT;
293                         pval.ri=eval_expr(h, rv->v.bexpr, msg);
294                         if (unlikely(pval.ri<0)){
295                                 if (pval.ri==EXPR_DROP) /* hack to quit on drop */
296                                         goto drop;
297                                 WARN("error in expression\n");
298                                 pval.ri=0; /* expr. is treated as false */
299                         }
300                         ret=!(!pval.ri);
301                         break;
302                 case RV_SEL:
303                         pval.flags=PV_VAL_STR;
304                         v=run_select(&pval.rs, &rv->v.sel, msg);
305                         if (unlikely(v!=0)){
306                                 pval.flags|=PV_VAL_EMPTY;
307                                 pval.rs.s="";
308                                 pval.rs.len=0;
309                                 if (v<0){
310                                         ret=-1;
311                                         break;
312                                 }
313                         }
314                         ret=(pval.rs.len>0);
315                         break;
316                 case RV_AVP:
317                                 r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
318                                                                                         &avp_val, rv->v.avps.index);
319                                 if (likely(r_avp)){
320                                         if (r_avp->flags & AVP_VAL_STR){
321                                                 pval.flags=PV_VAL_STR;
322                                                 pval.rs=avp_val.s;
323                                                 ret=(pval.rs.len>0);
324                                         }else{
325                                                 pval.flags=PV_TYPE_INT|PV_VAL_INT;
326                                                 pval.ri=avp_val.n;
327                                                 ret=!(!pval.ri);
328                                         }
329                                 }else{
330                                         PVAR_ASSIGN_NOVAL();
331                                         ret=0; /* avp not defined (valid case) */
332                                         break;
333                                 }
334                         break;
335                 case RV_PVAR:
336                         if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
337                                 destroy_pval=1;
338                                 if (pval.flags & PV_TYPE_INT){
339                                         ret=!(!pval.ri);
340                                 }else if (pval.flags & PV_VAL_STR){
341                                         ret=(pval.rs.len>0);
342                                 }else{
343                                         /* no value / not defined (e.g. avp) -> keep the flags */
344                                         ret=0;
345                                 }
346                         }else{
347                                 ERR("non existing right pvar\n");
348                                 PVAR_ASSIGN_NOVAL();
349                                 ret=-1;
350                         }
351                         break;
352         }
353         if (unlikely(pvar->setf(msg, &pvar->pvp, EQ_T, &pval)<0)){
354                 ERR("setting pvar failed\n");
355                 goto error;
356         }
357         if (destroy_pval) pv_value_destroy(&pval);
358         return ret;
359 error:
360         if (destroy_pval) pv_value_destroy(&pval);
361         return -1;
362 drop:
363         if (destroy_pval) pv_value_destroy(&pval);
364         return EXPR_DROP;
365 }
366
367
368
369 /** eval rve and assign the result to lv
370  * lv=eval(rve)
371  *
372  * @param h  - script context
373  * @param msg - sip msg
374  * @param lv - lvalue
375  * @param rve - rvalue expression
376  * @return >= 0 on success (expr. bool value), -1 on error
377  */
378 int lval_assign(struct run_act_ctx* h, struct sip_msg* msg, 
379                                 struct lvalue* lv, struct rval_expr* rve)
380 {
381         struct rvalue* rv;
382         int ret;
383         
384         ret=0;
385         rv=rval_expr_eval(h, msg, rve);
386         if (unlikely(rv==0)){
387                 ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
388                                 rve->fpos.s_line, rve->fpos.s_col,
389                                 rve->fpos.e_line, rve->fpos.e_col);
390                 goto error;
391         }
392         switch(lv->type){
393                 case LV_NONE:
394                         BUG("uninitialized/invalid lvalue (%d) (cfg line: %d)\n",
395                                         lv->type, rve->fpos.s_line);
396                         goto error;
397                 case LV_AVP:
398                         ret=lval_avp_assign(h, msg, lv, rv);
399                         break;
400                 case LV_PVAR:
401                         ret=lval_pvar_assign(h, msg, lv, rv);
402                         break;
403         }
404         if (unlikely(ret<0)){
405                 ERR("assignment failed at pos: (%d,%d-%d,%d)\n",
406                         rve->fpos.s_line, rve->fpos.s_col,
407                         rve->fpos.e_line, rve->fpos.e_col);
408         }
409         rval_destroy(rv);
410         return ret;
411 error:
412         if (rv) rval_destroy(rv);
413         return -1;
414 }