123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- /*
- * Copyright (C) 2008 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- /**
- * @file
- * @brief SIP-router core :: lvalues (assignment)
- * \ingroup core
- * Module: \ref core
- */
- /*
- * History:
- * --------
- * 2008-11-30 initial version (andrei)
- * 2009-04-24 delete avps after finding their new value and not before
- * (fixed $avp=$avp)
- * when assigning something undefined (e.g. non-existing avp),
- * delete the lvalue (similar to perl) (andrei)
- */
- #include "lvalue.h"
- #include "dprint.h"
- #include "route.h"
- /**
- * @brief eval rve and assign the result to an avp
- *
- * eval rve and assign the result to an avp, lv->lv.avp=eval(rve)
- * based on do_action() ASSIGN_T.
- * @param h - script context
- * @param msg - sip msg
- * @param lv - lvalue
- * @param rv - rvalue expression
- * @return >= 0 on success (expr. bool value), -1 on error
- */
- inline static int lval_avp_assign(struct run_act_ctx* h, struct sip_msg* msg,
- struct lvalue* lv, struct rvalue* rv)
- {
- avp_spec_t* avp;
- avp_t* r_avp;
- avp_t* avp_mark;
- pv_value_t pval;
- int_str value;
- unsigned short flags;
- struct search_state st;
- int ret, v, destroy_pval;
- int avp_add;
- #if 0
- #define AVP_ASSIGN_NOVAL() \
- /* unknown value => reset the avp in function of its type */ \
- flags=avp->type; \
- if (flags & AVP_VAL_STR){ \
- value.s.s=""; \
- value.s.len=0; \
- }else{ \
- value.n=0; \
- }
- #endif
- #define AVP_ASSIGN_NOVAL() \
- /* no value => delete avp */ \
- avp_add=0
-
- destroy_pval=0;
- flags = 0;
- avp=&lv->lv.avps;
- ret=0;
- avp_add=1;
-
- switch(rv->type){
- case RV_NONE:
- BUG("non-intialized rval / rval expr \n");
- /* unknown value => reset the avp in function of its type */
- flags=avp->type;
- AVP_ASSIGN_NOVAL();
- ret=-1;
- break;
- case RV_INT:
- value.n=rv->v.l;
- flags=avp->type & ~AVP_VAL_STR;
- ret=!(!value.n);
- break;
- case RV_STR:
- value.s=rv->v.s;
- flags=avp->type | AVP_VAL_STR;
- ret=(value.s.len>0);
- break;
- case RV_ACTION_ST:
- flags=avp->type & ~AVP_VAL_STR;
- if (rv->v.action) {
- value.n=run_actions_safe(h, rv->v.action, msg);
- h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return &
- break in expr*/
- } else
- value.n=-1;
- ret=value.n;
- break;
- case RV_BEXPR: /* logic/boolean expr. */
- value.n=eval_expr(h, rv->v.bexpr, msg);
- if (unlikely(value.n<0)){
- if (value.n==EXPR_DROP) /* hack to quit on drop */
- goto drop;
- WARN("error in expression\n");
- value.n=0; /* expr. is treated as false */
- }
- flags=avp->type & ~AVP_VAL_STR;
- ret=value.n;
- break;
- case RV_SEL:
- flags=avp->type|AVP_VAL_STR;
- v=run_select(&value.s, &rv->v.sel, msg);
- if (unlikely(v!=0)){
- value.s.s="";
- value.s.len=0;
- if (v<0){
- ret=-1;
- break;
- } /* v>0 */
- }
- ret=(value.s.len>0);
- break;
- case RV_AVP:
- avp_mark=0;
- if (unlikely((rv->v.avps.type & AVP_INDEX_ALL) == AVP_INDEX_ALL)){
- /* special case: add the value to the avp */
- r_avp = search_first_avp(rv->v.avps.type, rv->v.avps.name,
- &value, &st);
- while(r_avp){
- /* We take only the val type from the source avp
- * and reset the class, track flags and name type */
- flags=(avp->type & ~(AVP_INDEX_ALL|AVP_VAL_STR)) |
- (r_avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL|
- AVP_NAME_STR|AVP_NAME_RE));
- if (add_avp_before(avp_mark, flags, avp->name, value)<0){
- ERR("failed to assign avp\n");
- ret=-1;
- goto error;
- }
- /* move the mark, so the next found AVP will come before
- the one currently added so they will have the same
- order as in the source list */
- if (avp_mark) avp_mark=avp_mark->next;
- else
- avp_mark=search_first_avp(flags, avp->name, 0, 0);
- r_avp=search_next_avp(&st, &value);
- }
- ret=1;
- goto end;
- }else{
- /* normal case, value is replaced */
- r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
- &value, rv->v.avps.index);
- if (likely(r_avp)){
- /* take only the val type from the source avp
- * and reset the class, track flags and name type */
- flags=(avp->type & ~AVP_VAL_STR) | (r_avp->flags &
- ~(AVP_CLASS_ALL|AVP_TRACK_ALL|AVP_NAME_STR|
- AVP_NAME_RE));
- ret=1;
- }else{
- /* on error, keep the type of the assigned avp, but
- reset it to an empty value */
- AVP_ASSIGN_NOVAL();
- ret=0;
- break;
- }
- }
- break;
- case RV_PVAR:
- memset(&pval, 0, sizeof(pval));
- if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
- destroy_pval=1;
- if (pval.flags & PV_TYPE_INT){
- value.n=pval.ri;
- ret=value.n;
- flags=avp->type & ~AVP_VAL_STR;
- }else if (pval.flags & PV_VAL_STR){
- value.s=pval.rs;
- ret=(value.s.len>0);
- flags=avp->type | AVP_VAL_STR;
- }else if (pval.flags==PV_VAL_NONE ||
- (pval.flags & (PV_VAL_NULL|PV_VAL_EMPTY))){
- AVP_ASSIGN_NOVAL();
- ret=0;
- }
- }else{
- /* non existing pvar */
- /* on error, keep the type of the assigned avp, but
- reset it to an empty value */
- AVP_ASSIGN_NOVAL();
- ret=0;
- }
- break;
- }
- /* If the left attr was specified without indexing brackets delete
- * existing AVPs before adding the new value */
- delete_avp(avp->type, avp->name);
- if (avp_add && (add_avp(flags & ~AVP_INDEX_ALL, avp->name, value) < 0)) {
- ERR("failed to assign value to avp\n");
- goto error;
- }
- end:
- if (destroy_pval) pv_value_destroy(&pval);
- return ret;
- error:
- if (destroy_pval) pv_value_destroy(&pval);
- return -1;
- drop:
- if (destroy_pval) pv_value_destroy(&pval);
- return EXPR_DROP;
- }
- /**
- * @brief eval rve and assign the result to a pvar
- *
- * eval rve and assign the result to a pvar, lv->lv.pvar=eval(rve)
- * based on do_action() ASSIGN_T.
- * @param h - script context
- * @param msg - sip msg
- * @param lv - lvalue
- * @param rv - rvalue expression
- * @return >= 0 on success (expr. bool value), -1 on error
- */
- inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
- struct lvalue* lv, struct rvalue* rv)
- {
- pv_spec_t* pvar;
- pv_value_t pval;
- avp_t* r_avp;
- int_str avp_val;
- int ret;
- int v;
- int destroy_pval;
-
- #define PVAR_ASSIGN_NOVAL() \
- /* no value found => "undefine" */ \
- pv_get_null(msg, 0, &pval)
-
- destroy_pval=0;
- pvar=&lv->lv.pvs;
- if (unlikely(!pv_is_w(pvar))){
- ERR("read only pvar\n");
- goto error;
- }
- memset(&pval, 0, sizeof(pval));
- ret=0;
- switch(rv->type){
- case RV_NONE:
- BUG("non-intialized rval / rval expr \n");
- PVAR_ASSIGN_NOVAL();
- ret=-1;
- break;
- case RV_INT:
- pval.flags=PV_TYPE_INT|PV_VAL_INT;
- pval.ri=rv->v.l;
- ret=!(!pval.ri);
- break;
- case RV_STR:
- pval.flags=PV_VAL_STR;
- pval.rs=rv->v.s;
- ret=(pval.rs.len>0);
- break;
- case RV_ACTION_ST:
- pval.flags=PV_TYPE_INT|PV_VAL_INT;
- if (rv->v.action) {
- pval.ri=run_actions_safe(h, rv->v.action, msg);
- h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return &
- break in expr*/
- } else
- pval.ri=0;
- ret=!(!pval.ri);
- break;
- case RV_BEXPR: /* logic/boolean expr. */
- pval.flags=PV_TYPE_INT|PV_VAL_INT;
- pval.ri=eval_expr(h, rv->v.bexpr, msg);
- if (unlikely(pval.ri<0)){
- if (pval.ri==EXPR_DROP) /* hack to quit on drop */
- goto drop;
- WARN("error in expression\n");
- pval.ri=0; /* expr. is treated as false */
- }
- ret=!(!pval.ri);
- break;
- case RV_SEL:
- pval.flags=PV_VAL_STR;
- v=run_select(&pval.rs, &rv->v.sel, msg);
- if (unlikely(v!=0)){
- pval.flags|=PV_VAL_EMPTY;
- pval.rs.s="";
- pval.rs.len=0;
- if (v<0){
- ret=-1;
- break;
- }
- }
- ret=(pval.rs.len>0);
- break;
- case RV_AVP:
- r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
- &avp_val, rv->v.avps.index);
- if (likely(r_avp)){
- if (r_avp->flags & AVP_VAL_STR){
- pval.flags=PV_VAL_STR;
- pval.rs=avp_val.s;
- ret=(pval.rs.len>0);
- }else{
- pval.flags=PV_TYPE_INT|PV_VAL_INT;
- pval.ri=avp_val.n;
- ret=!(!pval.ri);
- }
- }else{
- PVAR_ASSIGN_NOVAL();
- ret=0; /* avp not defined (valid case) */
- break;
- }
- break;
- case RV_PVAR:
- if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
- destroy_pval=1;
- if (pval.flags & PV_TYPE_INT){
- ret=!(!pval.ri);
- }else if (pval.flags & PV_VAL_STR){
- ret=(pval.rs.len>0);
- }else{
- /* no value / not defined (e.g. avp) -> keep the flags */
- ret=0;
- }
- }else{
- ERR("non existing right pvar\n");
- PVAR_ASSIGN_NOVAL();
- ret=-1;
- }
- break;
- }
- if (unlikely(pvar->setf(msg, &pvar->pvp, EQ_T, &pval)<0)){
- ERR("setting pvar failed\n");
- goto error;
- }
- if (destroy_pval) pv_value_destroy(&pval);
- return ret;
- error:
- if (destroy_pval) pv_value_destroy(&pval);
- return -1;
- drop:
- if (destroy_pval) pv_value_destroy(&pval);
- return EXPR_DROP;
- }
- /** eval rve and assign the result to lv
- * lv=eval(rve)
- *
- * @param h - script context
- * @param msg - sip msg
- * @param lv - lvalue
- * @param rve - rvalue expression
- * @return >= 0 on success (expr. bool value), -1 on error
- */
- int lval_assign(struct run_act_ctx* h, struct sip_msg* msg,
- struct lvalue* lv, struct rval_expr* rve)
- {
- struct rvalue* rv;
- int ret;
-
- ret=0;
- rv=rval_expr_eval(h, msg, rve);
- if (unlikely(rv==0)){
- ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
- rve->fpos.s_line, rve->fpos.s_col,
- rve->fpos.e_line, rve->fpos.e_col);
- goto error;
- }
- switch(lv->type){
- case LV_NONE:
- BUG("uninitialized/invalid lvalue (%d) (cfg line: %d)\n",
- lv->type, rve->fpos.s_line);
- goto error;
- case LV_AVP:
- ret=lval_avp_assign(h, msg, lv, rv);
- break;
- case LV_PVAR:
- ret=lval_pvar_assign(h, msg, lv, rv);
- break;
- }
- if (unlikely(ret<0)){
- ERR("assignment failed at pos: (%d,%d-%d,%d)\n",
- rve->fpos.s_line, rve->fpos.s_col,
- rve->fpos.e_line, rve->fpos.e_col);
- }
- rval_destroy(rv);
- return ret;
- error:
- if (rv) rval_destroy(rv);
- return -1;
- }
|