core: support for RVEs in fparam fixups
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Wed, 2 Jun 2010 16:24:05 +0000 (18:24 +0200)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Wed, 2 Jun 2010 16:42:18 +0000 (18:42 +0200)
Hack to allow using RVEs in "safe" fparam fixups. This way all the
module functions using them will automatically have var support
(most ser modules that already supported variables as quoted
 parameter, support now any variable expression, without quotes
 too).
The cleanup is done by the core (this is the "hack" part).

E.g.:
t_set_fr($v + 2 + $x)  should work now
(it uses fixup_var_int_1 which is RVE-safe).

t_set_fr("$v") is now equivalent with t_set_fr($v).

action.c
cfg.y
route.c
route_struct.h
sr_module.c
sr_module.h

index bcc49ed..283dbe0 100644 (file)
--- a/action.c
+++ b/action.c
@@ -51,6 +51,8 @@
  *  2008-12-17  added UDP_MTU_TRY_PROTO_T (andrei)
  *  2009-05-04  switched IF_T to rval_expr (andrei)
  *  2009-09-15  added SET_{FWD,RPL}_NO_CONNECT, SET_{FWD,RPL}_CLOSE (andrei)
+ *  2010-06-01  special hack/support for fparam fixups so that they can handle
+ *               variable RVEs (andrei)
  */
 
 /*!
@@ -133,9 +135,14 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
  */
 #define MODF_RVE_PARAM_FREE(src, dst) \
                for (i=0; i < (dst)[1].u.number; i++) { \
-                       if ((src)[i+2].type == RVE_ST && (dst)[i+2].u.string) { \
-                               pkg_free((dst)[i+2].u.string); \
-                               (dst)[i+2].u.string = 0; \
+                       if ((src)[i+2].type == RVE_ST && (dst)[i+2].u.data) { \
+                               if ((dst)[i+2].type == FPARAM_DYN_ST) {\
+                                       /* frees also orig. dst.u.data */ \
+                                       fparam_free_contents((dst)[i+2].u.data); \
+                                       /* the fparam struct. (dst.u.data) is freed below */ \
+                               } \
+                               pkg_free((dst)[i+2].u.data); \
+                               (dst)[i+2].u.data = 0; \
                        } \
                }
 
@@ -147,7 +154,7 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
  * WARNING: dst must be cleaned when done, use MODULE_RVE_PARAM_FREE()
  * Side-effects: clobbers i (int), s (str), rv (rvalue*), might jump to error.
  */
-#define MODF_RVE_PARAM_CONVERT(h, msg, src, dst) \
+#define MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst) \
        do { \
                (dst)[1]=(src)[1]; \
                for (i=0; i < (src)[1].u.number; i++) { \
@@ -165,6 +172,12 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
                                (dst)[i+2].u.string = s.s; \
                                (dst)[i+2].u.str.len = s.len; \
                                rval_destroy(rv); \
+                               if ((cmd)->c.fixup && \
+                                               (long)(cmd)->c.fixup & FIXUP_F_FPARAM_RVE) { \
+                                       call_fixup((cmd)->c.fixup, &(dst)[i+2].u.data, i+1); \
+                                       if ((dst)[i+2].u.data != s.s) \
+                                               (dst)[i+2].type = FPARAM_DYN_ST; \
+                               } \
                        } else \
                                (dst)[i+2]=(src)[i+2]; \
                } \
@@ -180,22 +193,22 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
  * @param src - source action_u_t array (e.g. action->val)
  * @param params... - variable list of parameters, passed to the module
  *               function
- * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), f,
+ * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), cmd,
  *               might jump to error.
  *
  */
 #ifdef __SUNPRO_C
 #define MODF_CALL(f_type, h, msg, src, ...) \
        do { \
-               f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
-               ret=((f_type)f)((msg), __VAR_ARGS__); \
+               cmd=(src)[0].u.data; \
+               ret=((f_type)cmd->c.function)((msg), __VAR_ARGS__); \
                MODF_HANDLE_RETCODE(h, ret); \
        } while (0)
 #else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
 #define MODF_CALL(f_type, h, msg, src, params...) \
        do { \
-               f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
-               ret=((f_type)f)((msg), ## params ); \
+               cmd=(src)[0].u.data; \
+               ret=((f_type)cmd->c.function)((msg), ## params ); \
                MODF_HANDLE_RETCODE(h, ret); \
        } while (0)
 #endif /* __SUNPRO_C */
@@ -220,21 +233,21 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
 #ifdef __SUNPRO_C
 #define MODF_RVE_CALL(f_type, h, msg, src, dst, ...) \
        do { \
-               f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
-               MODF_RVE_PARAM_CONVERT(h, msg, src, dst); \
-               ret=((f_type)f)((msg), __VAR_ARGS__); \
+               cmd=(src)[0].u.data; \
+               MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst); \
+               ret=((f_type)cmd->c.function)((msg), __VAR_ARGS__); \
                MODF_HANDLE_RETCODE(h, ret); \
-               /* free strings allocated by us */ \
+               /* free strings allocated by us or fixups */ \
                MODF_RVE_PARAM_FREE(src, dst); \
        } while (0)
 #else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
 #define MODF_RVE_CALL(f_type, h, msg, src, dst, params...) \
        do { \
-               f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
-               MODF_RVE_PARAM_CONVERT(h, msg, src, dst); \
-               ret=((f_type)f)((msg), ## params ); \
+               cmd=(src)[0].u.data; \
+               MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst); \
+               ret=((f_type)cmd->c.function)((msg), ## params ); \
                MODF_HANDLE_RETCODE(h, ret); \
-               /* free strings allocated by us */ \
+               /* free strings allocated by us or fixups */ \
                MODF_RVE_PARAM_FREE(src, dst); \
        } while (0)
 #endif /* __SUNPRO_C */
@@ -250,7 +263,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
        struct dest_info dst;
        char* tmp;
        char *new_uri, *end, *crt;
-       void* f;
+       union cmd_export_u* cmd;
        int len;
        int user;
        struct sip_uri uri, next_hop;
diff --git a/cfg.y b/cfg.y
index 4cd8038..8074ad8 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -3747,31 +3747,38 @@ static int mod_f_params_pre_fixup(struct action* a)
                        return -1;
        }
        
-       if ( cmd_exp->c.fixup){
-               /* v0 or v1 functions that have fixups need constant,
-                 string params.*/
-               for (r=0; r < param_no; r++) {
-                       rve=params[r].u.data;
-                       if (!rve_is_constant(rve)) {
-                               yyerror_at(&rve->fpos, "function %s: parameter %d is not"
-                                                       " constant\n", cmd_exp->c.name, r+1);
-                               return -1;
-                       }
-                       if ((rv = rval_expr_eval(0, 0, rve)) == 0 ||
-                                       rval_get_str(0, 0, &s, rv, 0) < 0 ) {
-                               /* out of mem or bug ? */
+       if ( cmd_exp->c.fixup) {
+               if (is_fparam_rve_fixup(cmd_exp->c.fixup))
+                       /* mark known fparam rve safe fixups */
+                       cmd_exp->c.fixup  = (fixup_function)
+                                                                       ((unsigned long) cmd_exp->c.fixup |
+                                                                                FIXUP_F_FPARAM_RVE);
+               else if (!((unsigned long)cmd_exp->c.fixup & FIXUP_F_FPARAM_RVE)) {
+                       /* v0 or v1 functions that have fixups need constant,
+                         string params.*/
+                       for (r=0; r < param_no; r++) {
+                               rve=params[r].u.data;
+                               if (!rve_is_constant(rve)) {
+                                       yyerror_at(&rve->fpos, "function %s: parameter %d is not"
+                                                               " constant\n", cmd_exp->c.name, r+1);
+                                       return -1;
+                               }
+                               if ((rv = rval_expr_eval(0, 0, rve)) == 0 ||
+                                               rval_get_str(0, 0, &s, rv, 0) < 0 ) {
+                                       /* out of mem or bug ? */
+                                       rval_destroy(rv);
+                                       yyerror_at(&rve->fpos, "function %s: bad parameter %d"
+                                                                       " expression\n", cmd_exp->c.name, r+1);
+                                       return -1;
+                               }
                                rval_destroy(rv);
-                               yyerror_at(&rve->fpos, "function %s: bad parameter %d"
-                                                               " expression\n", cmd_exp->c.name, r+1);
-                               return -1;
+                               rve_destroy(rve);
+                               params[r].type = STRING_ST; /* asciiz */
+                               params[r].u.string = s.s;
+                               params[r].u.str.len = s.len; /* not used right now */
                        }
-                       rval_destroy(rv);
-                       rve_destroy(rve);
-                       params[r].type = STRING_ST; /* asciiz */
-                       params[r].u.string = s.s;
-                       params[r].u.str.len = s.len; /* not used right now */
                }
-       } /* else
+       }/* else
                if no fixups are present, the RVEs can be transformed
                into strings at runtime, allowing seamless var. use
                even with old functions.
diff --git a/route.c b/route.c
index c9fefb0..25eb512 100644 (file)
--- a/route.c
+++ b/route.c
@@ -50,6 +50,8 @@
  *             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)
  */
 
 
@@ -644,9 +646,6 @@ int fix_actions(struct action* a)
        struct rvalue* rv;
        int rve_param_no;
 
-       
-       char buf[30]; /* tmp buffer needed for module param fixups */
-
        if (a==0){
                LOG(L_CRIT,"BUG: fix_actions: null pointer\n");
                return E_BUG;
@@ -920,44 +919,13 @@ int fix_actions(struct action* a)
                        case MODULEX_T:
                                cmd = t->val[0].u.data;
                                rve_param_no = 0;
-                               if (cmd && cmd->c.fixup) {
+                               if (cmd) {
                                        DBG("fixing %s()\n", cmd->c.name);
                                        if (t->val[1].u.number==0) {
-                                               ret = cmd->c.fixup(0, 0);
-                                               if (ret < 0)
-                                                       goto error;
-                                       }
-                                       /* type cast NUMBER to STRING, old modules may expect
-                                        * all STRING params during fixup */
-                                       for (i=0; i<t->val[1].u.number; i++) {
-                                               /* obsoleted by the new RVE changes ? */
-                                               if (t->val[i+2].type == NUMBER_ST) {
-                                                       snprintf(buf, sizeof(buf)-1, "%ld", 
-                                                                               t->val[i+2].u.number);
-                                                       /* fixup currently requires string pkg_malloced*/
-                                                       t->val[i+2].u.string = pkg_malloc(strlen(buf)+1);
-                                                       if (!t->val[i+2].u.string) {
-                                                               LOG(L_CRIT, "ERROR: cannot translate NUMBER"
-                                                                                       " to STRING\n");
-                                                               ret = E_OUT_OF_MEM;
-                                                               goto error;
-                                                       }
-                                                       strcpy(t->val[i+2].u.string, buf);
-                                                       t->val[i+2].type = STRING_ST;
-                                               }else if (t->val[i+2].type != STRING_ST) {
-                                                       BUG("unsupported function parameter type %d\n",
-                                                                       t->val[i+2].type);
-                                               }
-                                       }
-                                       for (i=0; i < t->val[1].u.number; i++) {
-                                               tmp_p = t->val[i+2].u.data;
-                                               ret = cmd->c.fixup(&t->val[i+2].u.data, i+1);
-                                               if (t->val[i+2].u.data != tmp_p)
-                                                       t->val[i+2].type = MODFIXUP_ST;
+                                               ret = call_fixup(cmd->c.fixup, 0, 0);
                                                if (ret < 0)
                                                        goto error;
                                        }
-                               } else if (cmd) { /* no fixup => RVE supported => optimize */
                                        for (i=0; i < t->val[1].u.number; i++) {
                                                if (t->val[i+2].type == RVE_ST) {
                                                        rve = t->val[i+2].u.data;
@@ -979,6 +947,13 @@ int fix_actions(struct action* a)
                                                                t->val[i+2].u.string = s.s;
                                                                /* len is not used for now */
                                                                t->val[i+2].u.str.len = s.len;
+                                                               tmp_p = t->val[i+2].u.data;
+                                                               ret = call_fixup(cmd->c.fixup,
+                                                                                               &t->val[i+2].u.data, i+1);
+                                                               if (t->val[i+2].u.data != tmp_p)
+                                                                       t->val[i+2].type = MODFIXUP_ST;
+                                                               if (ret < 0)
+                                                                       goto error;
                                                        } else {
                                                                /* expression is not constant => fixup &
                                                                   optimize it */
@@ -990,9 +965,34 @@ int fix_actions(struct action* a)
                                                                        goto error;
                                                                }
                                                        }
-                                               } /* if RVE_ST */
-                                       }
+                                               } else  if (t->val[i+2].type == STRING_ST) {
+                                                       tmp_p = t->val[i+2].u.data;
+                                                       ret = call_fixup(cmd->c.fixup,
+                                                                                       &t->val[i+2].u.data, i+1);
+                                                       if (t->val[i+2].u.data != tmp_p)
+                                                               t->val[i+2].type = MODFIXUP_ST;
+                                                       if (ret < 0)
+                                                               goto error;
+                                               } else {
+                                                       BUG("invalid module function param type %d\n",
+                                                                       t->val[i+2].type);
+                                                       ret = E_BUG;
+                                                       goto error;
+                                               }
+                                       } /* for */
+                                       /* here all the params are either STRING_ST
+                                          (constant RVEs), MODFIXUP_ST (fixed up)
+                                          or RVE_ST (non-ct RVEs) */
                                        if (rve_param_no) { /* we have to fix the type */
+                                               if (cmd->c.fixup &&
+                                                       !((unsigned long)cmd->c.fixup &
+                                                               FIXUP_F_FPARAM_RVE)) {
+                                                       BUG("non-ct RVEs (%d) in module function call"
+                                                                       "that does not support them (%s)\n",
+                                                                       rve_param_no, cmd->c.name);
+                                                       ret = E_BUG;
+                                                       goto error;
+                                               }
                                                switch(t->type) {
                                                        case MODULE1_T:
                                                                t->type = MODULE1_RVE_T;
index 19d3b38..9c7b40b 100644 (file)
@@ -126,7 +126,8 @@ enum _operand_subtype{
                SELECT_ST, PVAR_ST,
                LVAL_ST,  RVE_ST,
                RETCODE_ST, CASE_ST,
-               BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST, MATCH_CONDTABLE_ST
+               BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST, MATCH_CONDTABLE_ST,
+               FPARAM_DYN_ST /* temporary only */
 };
 
 typedef enum _expr_l_type expr_l_type;
index b0c6c20..eb9b54a 100644 (file)
@@ -1569,3 +1569,29 @@ int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param)
        }
        return -1;
 }
+
+
+
+/** returns true if a fixup is a fparam_t* one.
+ * Used to automatically detect fparam fixups that can be used with non
+ * contant RVEs.
+ * @param f - function pointer
+ * @return 1 for fparam fixups, 0 for others.
+ */
+int is_fparam_rve_fixup(fixup_function f)
+{
+       if (f == fixup_var_str_12 ||
+               f == fixup_var_str_1 ||
+               f == fixup_var_str_2 ||
+               f == fixup_var_int_12 ||
+               f == fixup_var_int_1 ||
+               f == fixup_var_int_2 ||
+               f == fixup_int_12 ||
+               f == fixup_int_1 ||
+               f == fixup_int_2 ||
+               f == fixup_str_12 ||
+               f == fixup_str_1 ||
+               f == fixup_str_2)
+               return 1;
+       return 0;
+}
index 10afc55..e69d553 100644 (file)
@@ -149,6 +149,17 @@ typedef int (*param_func_t)( modparam_t type, void* val);
 #define VAR_PARAM_NO  -128  /* function has variable number of parameters
                                                           (see cmd_function_var for the prototype) */
 
+/* special fixup function flags.
+ * They are kept in the first 2 bits inside the pointer
+ */
+#define FIXUP_F_FPARAM_RVE (unsigned long)1 /* fparam fixup, rve ready */
+#define FIXUP_F_RESERVED (unsigned long)2  /* not used for now */
+#define FIXUP_MASK (~((unsigned long)3)) /* mask for obtainin the pointer val*/
+
+#define call_fixup(fixup, param, param_no) \
+       (((long)(fixup) & FIXUP_MASK)? \
+               (((fixup_function)((long)(fixup) & FIXUP_MASK))(param, param_no)):0)
+
 /* Macros - used as rank in child_init function */
 #define PROC_MAIN      0  /* Main ser process */
 #define PROC_TIMER    -1  /* Timer attendant process */
@@ -524,4 +535,6 @@ int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param);
 int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param);
 
 
+int is_fparam_rve_fixup(fixup_function f);
+
 #endif /* sr_module_h */