core: support for expressions/variables in function parameters
[sip-router] / action.c
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