Merge remote branch 'origin/andrei/rve_f_params'
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Wed, 11 Aug 2010 20:18:06 +0000 (22:18 +0200)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Wed, 11 Aug 2010 20:18:06 +0000 (22:18 +0200)
Automatic support for expressions or variables in lots of module
functions. It applies to all the module functions declared without
a fixup, with a fixup and the corresponding free_fixup function or
with a compatible ser or kamailio style standard fixup (declared
in sr_module.h or mod_fix.h).
E.g.:  f($a, "b = " + $b);  t_set_fr($v + 2 + $x).
       t_set_fr($foo) (equivalent now with t_set_fr("$foo")).

If the expression is constant, then there is no restriction, all the
module functions can take it as parameter.
E.g.: f("7 *" +" 6 = " + 7 * 6) # equivalent to f("7 * 6 = 42")

* origin/andrei/rve_f_params: (21 commits)
  NEWS: notes about expressions in function parameters
  core: enable RVE fixup support when fixup_free is present
  core: automatically fill known fixup_free functions
  core: functions to get a fixup corresp. fixup_free function
  core: k style fixup_free fixes
  core: added generic fparam fixup_free functions
  core: pvapi: added pv_spec_free_contents()
  core: fix "unsigned" bug in sint2str*()
  core: fix auto-deref. for vars in fparam fixups
  perl(k): use sr31_cmd_export_t
  app_python: use sr31_cmd_export_t
  core: internal module interface changes
  print(s): fparam fixup example
  core: support for RVEs in fparam fixups
  core: rval - don't use static buffer for int conversions
  core: ut.* - BSD licence
  core: ut.h: added sint2strbuf()
  perl(k): update api calls:  s/MODULE_T/MODULE2_T/
  app_python: update api calls:  s/MODULE_T/MODULE2_T
  print(s): more module function examples
  core: support for expressions/variables in function parameters

Conflicts:
NEWS
action.c
modules/app_python/python_msgobj.c
modules_k/perl/openserxs.xs
pkg/kamailio/debian-lenny
pvapi.c
route.c
route_struct.h
sr_module.c

12 files changed:
1  2 
NEWS
action.c
cfg.y
mod_fix.c
modules/app_python/python_msgobj.c
modules_k/perl/openserxs.xs
pvapi.c
route.c
route_struct.h
rvalue.c
sr_module.c
sr_module.h

diff --cc NEWS
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -6,12 -6,15 +6,21 @@@ $Id
  sip-router 3.1 chages
  
  core:
 +  - Dragonfly BSD support
 +  - statistics / counters support for tcp and sctp (enable by default)
 +  - statistics / counters api
 +  - networks addresses support in ip comparisons (src_ip, dst_ip, to_ip)
 +    with strings or rvalue expressions.
 +    E.g.: $ip=10.0.0.0;  if (src_ip == $ip +"/8") ....
+   - lots of module functions automatically support now expressions or
+       variables in function parameters. This applies to all the module
+       functions declared without a fixup, with a fixup and the corresponding
+       free_fixup function or with a compatible ser or kamailio style standard
+       fixup (declared in sr_module.h or mod_fix.h).
+       E.g.: f($a, "b = " + $b);  t_set_fr($v + 2 + $x).
+             t_set_fr($foo) (equivalent now with t_set_fr("$foo")).
+   - all the module functions can now be called with any constant expression
+       as parameters. E.g.: f("7 *" +" 6 = " + 7 * 6);
    - onreply_route {...} is now equivalent with onreply_route[0] {...}
    - global, per protocol blacklist ignore masks (via extended send_flags).
      See dst_blacklist_udp_imask a.s.o (dst_blacklist_*_imask).
diff --cc action.c
+++ b/action.c
@@@ -1355,13 -1512,11 +1540,10 @@@ int run_actions(struct run_act_ctx* h, 
        h->rec_lev--;
  end:
        /* process module onbreak handlers if present */
 -      if (h->rec_lev==0 && ret==0)
 +      if (unlikely(h->rec_lev==0 && ret==0))
                for (mod=modules;mod;mod=mod->next)
-                       if (unlikely((mod->mod_interface_ver==0) && mod->exports && 
-                                       mod->exports->v0.onbreak_f)) {
-                               mod->exports->v0.onbreak_f( msg );
-                               DBG("DEBUG: %s onbreak handler called\n",
-                                               mod->exports->c.name);
 -                      if (mod->exports.onbreak_f) {
++                      if (unlikely(mod->exports.onbreak_f)) {
+                               mod->exports.onbreak_f( msg );
 -                              DBG("DEBUG: %s onbreak handler called\n", mod->exports.name);
                        }
        return ret;
  
diff --cc cfg.y
Simple merge
diff --cc mod_fix.c
+++ b/mod_fix.c
@@@ -168,18 -166,233 +166,235 @@@ int fixup_regexpNL_none(void** param, i
  
  FIXUP_F1T(str_null, 1, 1, FPARAM_STR)
  FIXUP_F1T(str_str, 1, 2,  FPARAM_STR)
+ FIXUP_F1T(str_all, 1, 100,  FPARAM_STR)
  
- /* TODO: int can be converted in place, no need for pkg_malloc'ed fparam_t*/
+ /*
+   no free fixups possible for unit_*
+   (they overwrite the pointer with the converted number => the original
+    value cannot be recovered)
  FIXUP_F1T(uint_null, 1, 1, FPARAM_INT)
  FIXUP_F1T(uint_uint, 1, 2, FPARAM_INT)
+ */
+ int fixup_uint_uint(void** param, int param_no)
+ {
+       str s;
+       unsigned int num;
+       
+       s.s = *param;
+       s.len = strlen(s.s);
+       if (likely(str2int(&s, &num) == 0)) {
+               *param = (void*)(long)num;
+       } else
+               /* not a number */
+               return E_UNSPEC;
+       return 0;
+ }
+ int fixup_uint_null(void** param, int param_no)
+ {
+       if (param_no == 1)
+               return fixup_uint_uint(param, param_no);
+       return E_UNSPEC;
+ }
  
+ /* fixup_regexp_null() has to be written "by hand", since
+    it needs to save the original pointer (the fixup users expects
+    a pointer to the regex in *param and hence the original value
+    needed on free cannot be recovered directly).
  FIXUP_F1T(regexp_null, 1, 1, FPARAM_REGEX)
+ */
  
+ struct regex_fixup {
+       regex_t regex; /* compiled regex */
+       void* orig;    /* original pointer */
+ };
+ int fixup_regexp_null(void** param, int param_no)
+ {
+       struct regex_fixup* re;
+       
+       if (param_no != 1)
+               return E_UNSPEC;
+       if ((re=pkg_malloc(sizeof(*re))) ==0) {
+               ERR("No memory left\n");
+               goto error;
+       }
+       if (regcomp(&re->regex, *param,
+                               REG_EXTENDED|REG_ICASE|REG_NEWLINE))
+               goto error;
+       re->orig = *param;
+       *param = re;
+       return 0;
+ error:
+       if (re)
+               pkg_free(re);
+       return E_UNSPEC;
+ }
+ int fixup_free_regexp_null(void** param, int param_no)
+ {
+       struct regex_fixup* re;
+       
+       if (param_no != 1)
+               return E_UNSPEC;
+       if (*param) {
+               re = *param;
+               *param = re->orig;
+               regfree(&re->regex);
+               pkg_free(re);
+       }
+       return 0;
+ }
+ /* fixup_pvar_*() has to be written "by hand", since
+    it needs to save the original pointer (the fixup users expects
+    a pointer to the pv_spec_t in *param and hence the original value
+    needed on free cannot be recovered directly).
  FIXUP_F1T(pvar_null, 1, 1, FPARAM_PVS)
  FIXUP_F1T(pvar_pvar, 1, 2, FPARAM_PVS)
 -              pv_spec_free_contents(&pvs_f->pvs);
+ */
+ struct pvs_fixup {
+       pv_spec_t pvs; /* parsed pv spec */
+       void* orig;    /* original pointer */
+ };
+ int fixup_pvar_all(void** param, int param_no)
+ {
+       struct pvs_fixup* pvs_f;
+       str name;
+       
+       pvs_f = 0;
+       name.s = *param;
+       name.len = strlen(name.s);
+       trim(&name);
+       if (name.len == 0 || name.s[0] != '$')
+               /* not a pvs id */
+               goto error;
+       if ((pvs_f=pkg_malloc(sizeof(*pvs_f))) == 0) {
+               ERR("No memory left\n");
+               goto error;
+       }
+       if (pv_parse_spec2(&name, &pvs_f->pvs, 1) == 0)
+               /* not a valid pvs identifier */
+               goto error;
+       pvs_f->orig = *param;
+       *param = pvs_f;
+       return 0;
+ error:
+       if (pvs_f)
+               pkg_free(pvs_f);
+       return E_UNSPEC;
+ }
+ int fixup_free_pvar_all(void** param, int param_no)
+ {
+       struct pvs_fixup* pvs_f;
+       
+       if (*param) {
+               pvs_f = *param;
+               *param = pvs_f->orig;
++              /* free only the contents (don't attempt to free &pvs_f->pvs)*/
++              pv_spec_destroy(&pvs_f->pvs);
++              /* free the whole pvs_fixup */
+               pkg_free(pvs_f);
+       }
+       return 0;
+ }
+ int fixup_pvar_pvar(void** param, int param_no)
+ {
+       if (param_no > 2)
+               return E_UNSPEC;
+       return fixup_free_pvar_all(param, param_no);
+ }
+ int fixup_free_pvar_pvar(void** param, int param_no)
+ {
+       if (param_no > 2)
+               return E_UNSPEC;
+       return fixup_free_pvar_all(param, param_no);
+ }
+ int fixup_pvar_null(void** param, int param_no)
+ {
+       if (param_no != 1)
+               return E_UNSPEC;
+       return fixup_pvar_all(param, param_no);
+ }
  
+ int fixup_free_pvar_null(void** param, int param_no)
+ {
+       if (param_no != 1)
+               return E_UNSPEC;
+       return fixup_free_pvar_all(param, param_no);
+ }
+ /* must be written "by hand", see above (fixup_pvar_pvar).
  FIXUP_F2T(pvar_str, 1, 2, 1, FPARAM_PVS, FPARAM_STR)
  FIXUP_F2T(pvar_str_str, 1, 3, 1, FPARAM_PVS, FPARAM_STR)
+ */
+ int fixup_pvar_str(void** param, int param_no)
+ {
+       if (param_no == 1)
+               return fixup_pvar_all(param, param_no);
+       else if (param_no == 2)
+               return fixup_str_str(param, param_no);
+       return E_UNSPEC;
+ }
+ int fixup_free_pvar_str(void** param, int param_no)
+ {
+       if (param_no == 1)
+               return fixup_free_pvar_all(param, param_no);
+       else if (param_no == 2)
+               return fixup_free_str_str(param, param_no);
+       return E_UNSPEC;
+ }
+ int fixup_pvar_str_str(void** param, int param_no)
+ {
+       if (param_no == 1)
+               return fixup_pvar_all(param, param_no);
+       else if (param_no == 2 || param_no == 3)
+               return fixup_str_all(param, param_no);
+       return E_UNSPEC;
+ }
+ int fixup_free_pvar_str_str(void** param, int param_no)
+ {
+       if (param_no == 1)
+               return fixup_free_pvar_all(param, param_no);
+       else if (param_no == 2 || param_no == 3)
+               return fixup_free_str_all(param, param_no);
+       return E_UNSPEC;
+ }
  
  FIXUP_F2FP(igp_null, 1, 1, 1, FPARAM_INT|FPARAM_PVS, 0)
  FIXUP_F2FP(igp_igp, 1, 2, 2,  FPARAM_INT|FPARAM_PVS, 0)
@@@ -236,27 -233,27 +236,27 @@@ msg_call_function(msgobject *self, PyOb
          return Py_None;
      }
  
-     if (fexport->v1.fixup != NULL) {
+     if (fexport->fixup != NULL) {
          if (i >= 3) {
-             rval = fexport->v1.fixup(&(act->val[3].u.data), 2);
 -            rval = fexport->fixup(&(act->val[2].u.data), 2);
++            rval = fexport->fixup(&(act->val[3].u.data), 2);
              if (rval < 0) {
                  PyErr_SetString(PyExc_RuntimeError, "Error in fixup (2)");
                  Py_INCREF(Py_None);
                  return Py_None;
              }
 -            act->val[2].type = MODFIXUP_ST;
 +            act->val[3].type = MODFIXUP_ST;
          }
          if (i >= 2) {
-             rval = fexport->v1.fixup(&(act->val[2].u.data), 1);
 -            rval = fexport->fixup(&(act->val[1].u.data), 1);
++            rval = fexport->fixup(&(act->val[2].u.data), 1);
              if (rval < 0) {
                  PyErr_SetString(PyExc_RuntimeError, "Error in fixup (1)");
                  Py_INCREF(Py_None);
                  return Py_None;
              }
 -            act->val[1].type = MODFIXUP_ST;
 +            act->val[2].type = MODFIXUP_ST;
          }
          if (i == 1) {
-             rval = fexport->v1.fixup(0, 0);
+             rval = fexport->fixup(0, 0);
              if (rval < 0) {
                  PyErr_SetString(PyExc_RuntimeError, "Error in fixup (0)");
                  Py_INCREF(Py_None);
@@@ -285,23 -285,23 +285,23 @@@ int moduleFunc(struct sip_msg *m, char 
                }
  
                if (argc>=2) {
-                       *retval = exp_func_struct->v1.fixup(&(act->val[3].u.data), 2);
 -                      *retval = exp_func_struct->fixup(&(act->val[2].u.data), 2);
++                      *retval = exp_func_struct->fixup(&(act->val[3].u.data), 2);
                        if (*retval < 0) {
                                LM_ERR("Error in fixup (2)\n");
                                return -1;
                        }
 -                      act->val[2].type = MODFIXUP_ST;
 +                      act->val[3].type = MODFIXUP_ST;
                }
                if (argc>=1) {
-                       *retval = exp_func_struct->v1.fixup(&(act->val[2].u.data), 1);
 -                      *retval = exp_func_struct->fixup(&(act->val[1].u.data), 1);
++                      *retval = exp_func_struct->fixup(&(act->val[2].u.data), 1);
                        if (*retval < 0) {
                                LM_ERR("Error in fixup (1)\n");
                                return -1;
                        }
 -                      act->val[1].type = MODFIXUP_ST;
 +                      act->val[2].type = MODFIXUP_ST;
                }
                if (argc==0) {
-                       *retval = exp_func_struct->v1.fixup(0, 0);
+                       *retval = exp_func_struct->fixup(0, 0);
                        if (*retval < 0) {
                                LM_ERR("Error in fixup (0)\n");
                                return -1;
diff --cc pvapi.c
+++ b/pvapi.c
@@@ -1147,21 -1075,20 +1147,21 @@@ error
        return NULL;
  }
  
- /**
-  * destroy the content of pv_spec_t structure
 -/** frees only the contests of a pv_spec_t. */
 -void pv_spec_free_contents(pv_spec_t *spec)
++/** destroy the content of pv_spec_t structure.
 + */
 +void pv_spec_destroy(pv_spec_t *spec)
  {
 -      /* TODO: free name if it is PV */
 +      if(spec==0) return;
 +      /* free name if it is PV */
 +      if(spec->pvp.pvn.nfree)
 +              spec->pvp.pvn.nfree((void*)(&spec->pvp.pvn));
        if(spec->trans)
                tr_free((trans_t*)spec->trans);
  }
  
 -
 -
--/**
-  * free the pv_spec_t structure
 - *
++/** free the pv_spec_t structure.
   */
  void pv_spec_free(pv_spec_t *spec)
  {
diff --cc route.c
+++ b/route.c
   *            unless the operator is DIFF_OP (Miklos)
   *  2008-12-03  fixups for rvalues in assignments (andrei)
   *  2009-05-04  switched IF_T to rval_expr (andrei)
+  *  2010-06-01  special hack/support for fparam fixups so that they can handle
+  *               variable RVEs (andrei)
 + *  2010-06-18  ip comparison (comp_ip()) normalizes strings to
 + *              ip/netmask  (andrei)
   */
  
  
diff --cc route_struct.h
@@@ -122,7 -127,9 +127,10 @@@ enum _operand_subtype
                LVAL_ST,  RVE_ST,
                RETCODE_ST, CASE_ST,
                BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST, MATCH_CONDTABLE_ST,
-               SELECT_UNFIXED_ST
++              SELECT_UNFIXED_ST,
+               STRING_RVE_ST /* RVE converted to a string (fparam hack) */,
+               RVE_FREE_FIXUP_ST /* (str)RVE fixed up by a reversable fixup */,
+               FPARAM_DYN_ST /* temporary only (fparam hack) */
  };
  
  typedef enum _expr_l_type expr_l_type;
diff --cc rvalue.c
Simple merge
diff --cc sr_module.c
@@@ -1275,12 -1287,17 +1287,19 @@@ int fix_param_types(int types, void** p
  int fixup_var_str_12(void** param, int param_no)
  {
        int ret;
-       if ((ret = fix_param(FPARAM_PVS, param)) <= 0) return ret;
-       if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
-       if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
-       if ((ret = fix_param(FPARAM_PVE, param)) <= 0) return ret;
+       if (fixup_get_param_type(param) != STRING_RVE_ST) {
+               /* if called with a RVE already converted to string =>
+                  don't try AVP, PVAR or SELECT (to avoid double
+                  deref., e.g.: $foo="$bar"; f($foo) ) */
 -              if ((sr_cfg_compat!=SR_COMPAT_SER) &&
 -                      ((ret = fix_param(FPARAM_PVS, param)) <= 0)) return ret;
++              if ((ret = fix_param(FPARAM_PVS, param)) <= 0) return ret;
+               if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
+               if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
++              /* FIXME: if not PVE (string only), fix as string! or
++                 make a separate fixup  fixup_varpve_... */
++              if ((ret = fix_param(FPARAM_PVE, param)) <= 0) return ret;
+       }
        if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
 -      ERR("Error while fixing parameter, AVP, SELECT, and str conversions"
 +      ERR("Error while fixing parameter, PV, AVP, SELECT, and str conversions"
                        " failed\n");
        return -1;
  }
@@@ -1312,11 -1329,17 +1331,16 @@@ int fixup_var_str_2(void** param, int p
  int fixup_var_int_12(void** param, int param_no)
  {
        int ret;
-       if ((ret = fix_param(FPARAM_PVS, param)) <= 0) return ret;
-       if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
-       if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
+       if (fixup_get_param_type(param) != STRING_RVE_ST) {
+               /* if called with a RVE already converted to string =>
+                  don't try AVP, PVAR or SELECT (to avoid double
+                  deref., e.g.: $foo="$bar"; f($foo) ) */
 -              if ((sr_cfg_compat!=SR_COMPAT_SER) &&
 -                      ((ret = fix_param(FPARAM_PVS, param)) <= 0)) return ret;
++              if ((ret = fix_param(FPARAM_PVS, param)) <= 0) return ret;
+               if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
+               if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
+       }
        if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
 -      ERR("Error while fixing parameter, AVP, SELECT, and int conversions"
 +      ERR("Error while fixing parameter, PV, AVP, SELECT, and int conversions"
                        " failed\n");
        return -1;
  }
diff --cc sr_module.h
Simple merge