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 */
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
(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
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;
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:
| 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) {
} 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;
/* 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;
}
}
;
+/** 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)
{
struct action *t;
struct proxy_l* p;
char *tmp;
+ void *tmp_p;
int ret;
int i;
union cmd_export_u* cmd;
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 */
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) {
/* 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);
}
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: