core: support for expressions/variables in function parameters
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 15 Mar 2010 19:05:49 +0000 (20:05 +0100)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 15 Mar 2010 19:20:05 +0000 (20:20 +0100)
- all module functions that do not have fixups can now be called
  with variables, avps or expressions. They will be converted to
  string, either on startup (if the expression is constant, e.g.
  "a"+"b") or at runtime (if the expression is not constant, .e.g.
   $a, $b+$var(foo)+"test").
   E.g.: f("1+1=" + 1 + 1, "v=" + $v).
- slightly faster module function calls (eliminated some
  never-triggered sanity tests).

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

index e39b539..bcc49ed 100644 (file)
--- a/action.c
+++ b/action.c
 int _last_returned_code  = 0;
 struct onsend_info* p_onsend=0; /* onsend route send info */
 
+
+
+/* handle the exit code of a module function call.
+ * (used internally in do_action())
+ * @param h - script handle (h->last_retcode and h->run_flags will be set).
+ * @param ret - module function (v0 or v2) retcode
+ * Side-effects: sets _last_returned_code
+ */
+#define MODF_HANDLE_RETCODE(h, ret) \
+       do { \
+               /* if (unlikely((ret)==0)) (h)->run_flags|=EXIT_R_F; */ \
+               (h)->run_flags |= EXIT_R_F & (((ret) != 0) -1); \
+               (h)->last_retcode=(ret); \
+               _last_returned_code = (h)->last_retcode; \
+       } while(0)
+
+
+
+/* frees parameters converted using MODF_RVE_PARAM_CONVERT() from dst.
+ * (used internally in do_action())
+ * Assumes src is unchanged.
+ * Side-effects: clobbers i (int).
+ */
+#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; \
+                       } \
+               }
+
+
+/* fills dst from src, converting RVE_ST params to STRING_ST.
+ * (used internally in do_action())
+ * @param src - source action_u_t array, as in the action structure
+ * @param dst - destination action_u_t array, will be filled from src.
+ * 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) \
+       do { \
+               (dst)[1]=(src)[1]; \
+               for (i=0; i < (src)[1].u.number; i++) { \
+                       if ((src)[2+i].type == RVE_ST) { \
+                               rv=rval_expr_eval((h), (msg), (src)[i+2].u.data); \
+                               if (unlikely(rv == 0 || \
+                                       rval_get_str((h), (msg), &s, rv, 0) < 0)) { \
+                                       rval_destroy(rv); \
+                                       ERR("failed to convert RVE to string\n"); \
+                                       (dst)[1].u.number = i; \
+                                       MODF_RVE_PARAM_FREE(src, dst); \
+                                       goto error; \
+                               } \
+                               (dst)[i+2].type = STRING_ST; \
+                               (dst)[i+2].u.string = s.s; \
+                               (dst)[i+2].u.str.len = s.len; \
+                               rval_destroy(rv); \
+                       } else \
+                               (dst)[i+2]=(src)[i+2]; \
+               } \
+       } while(0)
+
+
+
+/* call a module function with normal STRING_ST params.
+ * (used internally in do_action())
+ * @param f_type - cmd_function type
+ * @param h
+ * @param msg
+ * @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,
+ *               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__); \
+               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 ); \
+               MODF_HANDLE_RETCODE(h, ret); \
+       } while (0)
+#endif /* __SUNPRO_C */
+
+
+
+/* call a module function with possible RVE params.
+ * (used internally in do_action())
+ * @param f_type - cmd_function type
+ * @param h
+ * @param msg
+ * @param src - source action_u_t array (e.g. action->val)
+ * @param dst - temporary action_u_t array used for conversions. It can be
+ *              used for the function parameters. It's contents it's not
+ *              valid after the call.
+ * @param params... - variable list of parameters, passed to the module
+ *               function
+ * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), f, dst,
+ *               might jump to error.
+ *
+ */
+#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__); \
+               MODF_HANDLE_RETCODE(h, ret); \
+               /* free strings allocated by us */ \
+               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 ); \
+               MODF_HANDLE_RETCODE(h, ret); \
+               /* free strings allocated by us */ \
+               MODF_RVE_PARAM_FREE(src, dst); \
+       } while (0)
+#endif /* __SUNPRO_C */
+
+
 /* ret= 0! if action -> end of list(e.g DROP),
       > 0 to continue processing next actions
    and <0 on error */
@@ -135,6 +267,13 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
        struct rval_cache c1;
        str s;
        void *srevp[2];
+       /* temporary storage space for a struct action.val[] working copy
+        (needed to transform RVE intro STRING before calling module
+          functions). [0] is not used (corresp. to the module export pointer),
+          [1] contains the number of params, and [2..] the param values.
+          We need [1], because some fixup function use it
+         (see fixup_get_param_count()).  */
+       static action_u_t mod_f_params[MAX_ACTIONS];
 
        /* reset the value of error to E_UNSPEC so avoid unknowledgable
           functions to return with error (status<0) and not setting it
@@ -872,108 +1011,111 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                                                                (struct action*)a->val[2].u.data, msg);
                                        }
                        break;
-               case MODULE_T:
-                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
-                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
-                               ret=((cmd_function)f)(msg,
-                                                                               (char*)a->val[2].u.data,
-                                                                               (char*)a->val[3].u.data
-                                                                       );
-                               if (ret==0) h->run_flags|=EXIT_R_F;
-                               h->last_retcode=ret;
-                               _last_returned_code = h->last_retcode;
-                       } else {
-                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
-                               goto error;
-                       }
+               case MODULE0_T:
+                       MODF_CALL(cmd_function, h, msg, a->val, 0, 0);
                        break;
                /* instead of using the parameter number, we use different names
                 * for calls to functions with 3, 4, 5, 6 or variable number of
                 * parameters due to performance reasons */
+               case MODULE1_T:
+                       MODF_CALL(cmd_function, h, msg, a->val,
+                                                                               (char*)a->val[2].u.data,
+                                                                               0
+                                       );
+                       break;
+               case MODULE2_T:
+                       MODF_CALL(cmd_function, h, msg, a->val,
+                                                                               (char*)a->val[2].u.data,
+                                                                               (char*)a->val[3].u.data
+                                       );
+                       break;
                case MODULE3_T:
-                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
-                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
-                               ret=((cmd_function3)f)(msg,
+                       MODF_CALL(cmd_function3, h, msg, a->val,
                                                                                (char*)a->val[2].u.data,
                                                                                (char*)a->val[3].u.data,
                                                                                (char*)a->val[4].u.data
-                                                                       );
-                               if (ret==0) h->run_flags|=EXIT_R_F;
-                               h->last_retcode=ret;
-                               _last_returned_code = h->last_retcode;
-                       } else {
-                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
-                               goto error;
-                       }
+                                       );
                        break;
                case MODULE4_T:
-                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
-                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
-                               ret=((cmd_function4)f)(msg,
+                       MODF_CALL(cmd_function4, h, msg, a->val,
                                                                                (char*)a->val[2].u.data,
                                                                                (char*)a->val[3].u.data,
                                                                                (char*)a->val[4].u.data,
                                                                                (char*)a->val[5].u.data
-                                                                       );
-                               if (ret==0) h->run_flags|=EXIT_R_F;
-                               h->last_retcode=ret;
-                               _last_returned_code = h->last_retcode;
-                       } else {
-                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
-                               goto error;
-                       }
+                                       );
                        break;
                case MODULE5_T:
-                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
-                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
-                               ret=((cmd_function5)f)(msg,
+                       MODF_CALL(cmd_function5, h, msg, a->val,
                                                                                (char*)a->val[2].u.data,
                                                                                (char*)a->val[3].u.data,
                                                                                (char*)a->val[4].u.data,
                                                                                (char*)a->val[5].u.data,
                                                                                (char*)a->val[6].u.data
-                                                                       );
-                               if (ret==0) h->run_flags|=EXIT_R_F;
-                               h->last_retcode=ret;
-                               _last_returned_code = h->last_retcode;
-                       } else {
-                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
-                               goto error;
-                       }
+                                       );
                        break;
                case MODULE6_T:
-                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
-                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
-                               ret=((cmd_function6)f)(msg,
+                       MODF_CALL(cmd_function6, h, msg, a->val,
                                                                                (char*)a->val[2].u.data,
                                                                                (char*)a->val[3].u.data,
                                                                                (char*)a->val[4].u.data,
                                                                                (char*)a->val[5].u.data,
                                                                                (char*)a->val[6].u.data,
                                                                                (char*)a->val[7].u.data
-                                                                       );
-                               if (ret==0) h->run_flags|=EXIT_R_F;
-                               h->last_retcode=ret;
-                               _last_returned_code = h->last_retcode;
-                       } else {
-                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
-                               goto error;
-                       }
+                                       );
                        break;
                case MODULEX_T:
-                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
-                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
-                               ret=((cmd_function_var)f)(msg,
-                                                                                       a->val[1].u.number,
-                                                                                       &a->val[2]
-                                                                               );
-                               if (ret==0) h->run_flags|=EXIT_R_F;
-                               h->last_retcode=ret;
-                               _last_returned_code = h->last_retcode;
-                       } else {
-                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
-                               goto error;
-                       }
+                       MODF_CALL(cmd_function_var, h, msg, a->val,
+                                                       a->val[1].u.number, &a->val[2]);
+                       break;
+               case MODULE1_RVE_T:
+                       MODF_RVE_CALL(cmd_function, h, msg, a->val, mod_f_params,
+                                                                                       (char*)mod_f_params[2].u.data,
+                                                                                       0
+                                       );
+                       break;
+               case MODULE2_RVE_T:
+                       MODF_RVE_CALL(cmd_function, h, msg, a->val, mod_f_params,
+                                                                                       (char*)mod_f_params[2].u.data,
+                                                                                       (char*)mod_f_params[3].u.data
+                                       );
+                       break;
+               case MODULE3_RVE_T:
+                       MODF_RVE_CALL(cmd_function3, h, msg, a->val, mod_f_params,
+                                                                                       (char*)mod_f_params[2].u.data,
+                                                                                       (char*)mod_f_params[3].u.data,
+                                                                                       (char*)mod_f_params[4].u.data
+                                       );
+                       break;
+               case MODULE4_RVE_T:
+                       MODF_RVE_CALL(cmd_function4, h, msg, a->val, mod_f_params,
+                                                                                       (char*)mod_f_params[2].u.data,
+                                                                                       (char*)mod_f_params[3].u.data,
+                                                                                       (char*)mod_f_params[4].u.data,
+                                                                                       (char*)mod_f_params[5].u.data
+                                       );
+                       break;
+               case MODULE5_RVE_T:
+                       MODF_RVE_CALL(cmd_function5, h, msg, a->val, mod_f_params,
+                                                                                       (char*)mod_f_params[2].u.data,
+                                                                                       (char*)mod_f_params[3].u.data,
+                                                                                       (char*)mod_f_params[4].u.data,
+                                                                                       (char*)mod_f_params[5].u.data,
+                                                                                       (char*)mod_f_params[6].u.data
+                                       );
+                       break;
+               case MODULE6_RVE_T:
+                       MODF_RVE_CALL(cmd_function6, h, msg, a->val, mod_f_params,
+                                                                                       (char*)mod_f_params[2].u.data,
+                                                                                       (char*)mod_f_params[3].u.data,
+                                                                                       (char*)mod_f_params[4].u.data,
+                                                                                       (char*)mod_f_params[5].u.data,
+                                                                                       (char*)mod_f_params[6].u.data,
+                                                                                       (char*)mod_f_params[7].u.data
+                                       );
+                       break;
+               case MODULEX_RVE_T:
+                       MODF_RVE_CALL(cmd_function_var, h, msg, a->val, mod_f_params,
+                                                       a->val[1].u.number, &mod_f_params[2]);
                        break;
                case EVAL_T:
                        /* only eval the expression to account for possible
diff --git a/cfg.y b/cfg.y
index 8bda2fc..4cd8038 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -242,6 +242,8 @@ static struct case_stms* mk_case_stm(struct rval_expr* ct, int is_re,
                                                                        struct action* a, int* err);
 static int case_check_type(struct case_stms* stms);
 static int case_check_default(struct case_stms* stms);
+static int mod_f_params_pre_fixup(struct action* a);
+static void free_mod_func_action(struct action* a);
 
 
 extern int line;
@@ -2215,7 +2217,14 @@ fcmd:
                                case RESETFLAG_T:
                                case ISFLAGSET_T:
                                case IF_T:
-                               case MODULE_T:
+                               case MODULE0_T:
+                               case MODULE1_T:
+                               case MODULE2_T:
+                               case MODULE3_T:
+                               case MODULE4_T:
+                               case MODULE5_T:
+                               case MODULE6_T:
+                               case MODULEX_T:
                                case SET_FWD_NO_CONNECT_T:
                                case SET_RPL_NO_CONNECT_T:
                                case SET_FWD_CLOSE_T:
@@ -3195,9 +3204,9 @@ cmd:
        | SET_RPL_CLOSE {
                $$=mk_action(SET_RPL_CLOSE_T, 0); set_cfg_pos($$);
        }
-       | ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST,
+       | ID {mod_func_action = mk_action(MODULE0_T, 2, MODEXP_ST, NULL, NUMBER_ST,
                        0); } LPAREN func_params RPAREN {
-               mod_func_action->val[0].u.data = 
+               mod_func_action->val[0].u.data =
                        find_export_record($1, mod_func_action->val[1].u.number, rt,
                                                                &u_tmp);
                if (mod_func_action->val[0].u.data == 0) {
@@ -3207,34 +3216,14 @@ cmd:
                        } else {
                                yyerror("unknown command, missing loadmodule?\n");
                        }
-                       pkg_free(mod_func_action);
+                       free_mod_func_action(mod_func_action);
                        mod_func_action=0;
                }else{
-                       switch( ((union cmd_export_u*)
-                                               mod_func_action->val[0].u.data)->c.param_no){
-                               case 0:
-                               case 1:
-                               case 2:
-                                       /* MODULE_T used for 0-2 params */
-                                       break;
-                               case 3:
-                                       mod_func_action->type=MODULE3_T;
-                                       break;
-                               case 4:
-                                       mod_func_action->type=MODULE4_T;
-                                       break;
-                               case 5:
-                                       mod_func_action->type=MODULE5_T;
-                                       break;
-                               case 6:
-                                       mod_func_action->type=MODULE6_T;
-                                       break;
-                               case VAR_PARAM_NO:
-                                       mod_func_action->type=MODULEX_T;
-                                       break;
-                               default:
-                                       yyerror("too many parameters for function\n");
-                                       break;
+                       if (mod_func_action && mod_f_params_pre_fixup(mod_func_action)<0) {
+                               /* error messages are printed inside the function */
+                               free_mod_func_action(mod_func_action);
+                               mod_func_action = 0;
+                               YYERROR;
                        }
                }
                $$ = mod_func_action;
@@ -3246,27 +3235,20 @@ func_params:
        /* empty */
        | func_params COMMA func_param { }
        | func_param {}
-       | func_params error { yyerror("call params error\n"); }
        ;
 func_param:
-        intno {
-               if (mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
+       rval_expr {
+               if ($1 && mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
                        mod_func_action->val[mod_func_action->val[1].u.number+2].type =
-                               NUMBER_ST;
-                       mod_func_action->val[mod_func_action->val[1].u.number+2].u.number =
+                               RVE_ST;
+                       mod_func_action->val[mod_func_action->val[1].u.number+2].u.data =
                                $1;
                        mod_func_action->val[1].u.number++;
-               } else {
+               } else if ($1) {
                        yyerror("Too many arguments\n");
-               }
-       }
-       | STRING {
-               if (mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
-                       mod_func_action->val[mod_func_action->val[1].u.number+2].type = STRING_ST;
-                       mod_func_action->val[mod_func_action->val[1].u.number+2].u.string = $1;
-                       mod_func_action->val[1].u.number++;
+                       YYERROR;
                } else {
-                       yyerror("Too many arguments\n");
+                       YYERROR;
                }
        }
        ;
@@ -3709,6 +3691,121 @@ static int case_check_default(struct case_stms* stms)
 
 
 
+/** fixes the parameters and the type of a module function call.
+ * It is done here instead of fix action, to have quicker feedback
+ * on error cases (e.g. passing a non constant to a function with a 
+ * declared fixup) 
+ * The rest of the fixup is done inside do_action().
+ * @param a - filled module function call (MODULE*_T) action structure
+ *            complete with parameters, starting at val[2] and parameter
+ *            number at val[1].
+ * @return 0 on success, -1 on error (it will also print the error msg.).
+ *
+ */
+static int mod_f_params_pre_fixup(struct action* a)
+{
+       union cmd_export_u* cmd_exp;
+       action_u_t* params;
+       int param_no;
+       struct rval_expr* rve;
+       struct rvalue* rv;
+       int r;
+       str s;
+       
+       cmd_exp = a->val[0].u.data;
+       param_no = a->val[1].u.number;
+       params = &a->val[2];
+       
+       switch(cmd_exp->c.param_no) {
+               case 0:
+                       a->type = MODULE0_T;
+                       break;
+               case 1:
+                       a->type = MODULE1_T;
+                       break;
+               case 2:
+                       a->type = MODULE2_T;
+                       break;
+               case 3:
+                       a->type = MODULE3_T;
+                       break;
+               case 4:
+                       a->type = MODULE4_T;
+                       break;
+               case 5:
+                       a->type = MODULE5_T;
+                       break;
+               case 6:
+                       a->type = MODULE6_T;
+                       break;
+               case VAR_PARAM_NO:
+                       a->type = MODULEX_T;
+                       break;
+               default:
+                       yyerror("function %s: bad definition"
+                                       " (invalid number of parameters)", cmd_exp->c.name);
+                       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 ? */
+                               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);
+                       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
+               if no fixups are present, the RVEs can be transformed
+               into strings at runtime, allowing seamless var. use
+               even with old functions.
+               Further optimizations -> in fix_actions()
+               */
+       return 0;
+}
+
+
+
+/** frees a filled module function call action structure.
+ * @param a - filled module function call action structure
+ *            complete with parameters, starting at val[2] and parameter
+ *            number at val[1].
+ */
+static void free_mod_func_action(struct action* a)
+{
+       union cmd_export_u* cmd_exp;
+       action_u_t* params;
+       int param_no;
+       int r;
+       
+       cmd_exp = a->val[0].u.data;
+       param_no = a->val[1].u.number;
+       params = &a->val[2];
+       
+       for (r=0; r < param_no; r++)
+               if (params[r].u.data)
+                       rve_destroy(params[r].u.data);
+       pkg_free(a);
+}
+
+
+
 /*
 int main(int argc, char ** argv)
 {
diff --git a/route.c b/route.c
index 0268c12..c9fefb0 100644 (file)
--- a/route.c
+++ b/route.c
@@ -629,6 +629,7 @@ int fix_actions(struct action* a)
        struct action *t;
        struct proxy_l* p;
        char *tmp;
+       void *tmp_p;
        int ret;
        int i;
        union cmd_export_u* cmd;
@@ -640,6 +641,8 @@ int fix_actions(struct action* a)
        struct rval_expr* rve;
        struct rval_expr* err_rve;
        enum rval_type rve_type, err_type, expected_type;
+       struct rvalue* rv;
+       int rve_param_no;
 
        
        char buf[30]; /* tmp buffer needed for module param fixups */
@@ -907,13 +910,16 @@ int fix_actions(struct action* a)
                                        goto error;
                                break;
 
-                       case MODULE_T:
+                       case MODULE0_T:
+                       case MODULE1_T:
+                       case MODULE2_T:
                        case MODULE3_T:
                        case MODULE4_T:
                        case MODULE5_T:
                        case MODULE6_T:
                        case MODULEX_T:
                                cmd = t->val[0].u.data;
+                               rve_param_no = 0;
                                if (cmd && cmd->c.fixup) {
                                        DBG("fixing %s()\n", cmd->c.name);
                                        if (t->val[1].u.number==0) {
@@ -924,6 +930,7 @@ int fix_actions(struct action* a)
                                        /* 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);
@@ -937,17 +944,84 @@ int fix_actions(struct action* a)
                                                        }
                                                        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++) {
-                                               void *p;
-                                               p = t->val[i+2].u.data;
+                                       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 != p)
+                                               if (t->val[i+2].u.data != tmp_p)
                                                        t->val[i+2].type = MODFIXUP_ST;
                                                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;
+                                                       if (rve_is_constant(rve)) {
+                                                               /* if expression is constant => evaluate it
+                                                                  as string and replace it with the corresp.
+                                                                  string */
+                                                               rv = rval_expr_eval(0, 0, rve);
+                                                               if (rv == 0 ||
+                                                                               rval_get_str( 0, 0, &s, rv, 0) < 0 ) {
+                                                                       ERR("failed to fix constant rve");
+                                                                       if (rv) rval_destroy(rv);
+                                                                       ret = E_BUG;
+                                                                       goto error;
+                                                               }
+                                                               rval_destroy(rv);
+                                                               rve_destroy(rve);
+                                                               t->val[i+2].type = STRING_ST;/*asciiz string*/
+                                                               t->val[i+2].u.string = s.s;
+                                                               /* len is not used for now */
+                                                               t->val[i+2].u.str.len = s.len;
+                                                       } else {
+                                                               /* expression is not constant => fixup &
+                                                                  optimize it */
+                                                               rve_param_no++;
+                                                               if ((ret=fix_rval_expr(&t->val[i+2].u.data))
+                                                                               < 0) {
+                                                                       ERR("rve fixup failed\n");
+                                                                       ret = E_BUG;
+                                                                       goto error;
+                                                               }
+                                                       }
+                                               } /* if RVE_ST */
+                                       }
+                                       if (rve_param_no) { /* we have to fix the type */
+                                               switch(t->type) {
+                                                       case MODULE1_T:
+                                                               t->type = MODULE1_RVE_T;
+                                                               break;
+                                                       case MODULE2_T:
+                                                               t->type = MODULE2_RVE_T;
+                                                               break;
+                                                       case MODULE3_T:
+                                                               t->type = MODULE3_RVE_T;
+                                                               break;
+                                                       case MODULE4_T:
+                                                               t->type = MODULE4_RVE_T;
+                                                               break;
+                                                       case MODULE5_T:
+                                                               t->type = MODULE5_RVE_T;
+                                                               break;
+                                                       case MODULE6_T:
+                                                               t->type = MODULE6_RVE_T;
+                                                               break;
+                                                       case MODULEX_T:
+                                                               t->type = MODULEX_RVE_T;
+                                                               break;
+                                                       default:
+                                                               BUG("unsupported module function type %d\n",
+                                                                               t->type);
+                                                               ret = E_BUG;
+                                                               goto error;
+                                               }
+                                       } /* if rve_param_no */
                                }
                                break;
                        case FORCE_SEND_SOCKET_T:
index 85ebcc5..371acaa 100644 (file)
@@ -443,12 +443,21 @@ void print_action(struct action* t)
                case IF_T:
                        DBG("if (");
                        break;
-               case MODULE_T:
+               case MODULE0_T:
+               case MODULE1_T:
+               case MODULE2_T:
                case MODULE3_T:
                case MODULE4_T:
                case MODULE5_T:
                case MODULE6_T:
                case MODULEX_T:
+               case MODULE1_RVE_T:
+               case MODULE2_RVE_T:
+               case MODULE3_RVE_T:
+               case MODULE4_RVE_T:
+               case MODULE5_RVE_T:
+               case MODULE6_RVE_T:
+               case MODULEX_RVE_T:
                        DBG(" external_module_call(");
                        break;
                case FORCE_RPORT_T:
index 4894bd5..19d3b38 100644 (file)
@@ -85,7 +85,12 @@ enum action_type{
                SET_USERPHONE_T,
                IF_T, SWITCH_T /* only until fixup*/,
                BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, MATCH_COND_T, WHILE_T,
-               MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
+               /* module function calls with string only parameters */
+               MODULE0_T, MODULE1_T, MODULE2_T, MODULE3_T, MODULE4_T, MODULE5_T,
+               MODULE6_T, MODULEX_T,
+               /* module function calls, that have some RVE parameters */
+               MODULE1_RVE_T, MODULE2_RVE_T, MODULE3_RVE_T,
+               MODULE4_RVE_T, MODULE5_RVE_T, MODULE6_RVE_T, MODULEX_RVE_T,
                SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
                AVPFLAG_OPER_T,
                LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T,