Browse code

core: support for expressions/variables in function parameters

- 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).

Andrei Pelinescu-Onciul authored on 15/03/2010 19:05:49
Showing 5 changed files
... ...
@@ -108,6 +108,138 @@
108 108
 int _last_returned_code  = 0;
109 109
 struct onsend_info* p_onsend=0; /* onsend route send info */
110 110
 
111
+
112
+
113
+/* handle the exit code of a module function call.
114
+ * (used internally in do_action())
115
+ * @param h - script handle (h->last_retcode and h->run_flags will be set).
116
+ * @param ret - module function (v0 or v2) retcode
117
+ * Side-effects: sets _last_returned_code
118
+ */
119
+#define MODF_HANDLE_RETCODE(h, ret) \
120
+	do { \
121
+		/* if (unlikely((ret)==0)) (h)->run_flags|=EXIT_R_F; */ \
122
+		(h)->run_flags |= EXIT_R_F & (((ret) != 0) -1); \
123
+		(h)->last_retcode=(ret); \
124
+		_last_returned_code = (h)->last_retcode; \
125
+	} while(0)
126
+
127
+
128
+
129
+/* frees parameters converted using MODF_RVE_PARAM_CONVERT() from dst.
130
+ * (used internally in do_action())
131
+ * Assumes src is unchanged.
132
+ * Side-effects: clobbers i (int).
133
+ */
134
+#define MODF_RVE_PARAM_FREE(src, dst) \
135
+		for (i=0; i < (dst)[1].u.number; i++) { \
136
+			if ((src)[i+2].type == RVE_ST && (dst)[i+2].u.string) { \
137
+				pkg_free((dst)[i+2].u.string); \
138
+				(dst)[i+2].u.string = 0; \
139
+			} \
140
+		}
141
+
142
+
143
+/* fills dst from src, converting RVE_ST params to STRING_ST.
144
+ * (used internally in do_action())
145
+ * @param src - source action_u_t array, as in the action structure
146
+ * @param dst - destination action_u_t array, will be filled from src.
147
+ * WARNING: dst must be cleaned when done, use MODULE_RVE_PARAM_FREE()
148
+ * Side-effects: clobbers i (int), s (str), rv (rvalue*), might jump to error.
149
+ */
150
+#define MODF_RVE_PARAM_CONVERT(h, msg, src, dst) \
151
+	do { \
152
+		(dst)[1]=(src)[1]; \
153
+		for (i=0; i < (src)[1].u.number; i++) { \
154
+			if ((src)[2+i].type == RVE_ST) { \
155
+				rv=rval_expr_eval((h), (msg), (src)[i+2].u.data); \
156
+				if (unlikely(rv == 0 || \
157
+					rval_get_str((h), (msg), &s, rv, 0) < 0)) { \
158
+					rval_destroy(rv); \
159
+					ERR("failed to convert RVE to string\n"); \
160
+					(dst)[1].u.number = i; \
161
+					MODF_RVE_PARAM_FREE(src, dst); \
162
+					goto error; \
163
+				} \
164
+				(dst)[i+2].type = STRING_ST; \
165
+				(dst)[i+2].u.string = s.s; \
166
+				(dst)[i+2].u.str.len = s.len; \
167
+				rval_destroy(rv); \
168
+			} else \
169
+				(dst)[i+2]=(src)[i+2]; \
170
+		} \
171
+	} while(0)
172
+
173
+
174
+
175
+/* call a module function with normal STRING_ST params.
176
+ * (used internally in do_action())
177
+ * @param f_type - cmd_function type
178
+ * @param h
179
+ * @param msg
180
+ * @param src - source action_u_t array (e.g. action->val)
181
+ * @param params... - variable list of parameters, passed to the module
182
+ *               function
183
+ * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), f,
184
+ *               might jump to error.
185
+ *
186
+ */
187
+#ifdef __SUNPRO_C
188
+#define MODF_CALL(f_type, h, msg, src, ...) \
189
+	do { \
190
+		f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
191
+		ret=((f_type)f)((msg), __VAR_ARGS__); \
192
+		MODF_HANDLE_RETCODE(h, ret); \
193
+	} while (0)
194
+#else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
195
+#define MODF_CALL(f_type, h, msg, src, params...) \
196
+	do { \
197
+		f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
198
+		ret=((f_type)f)((msg), ## params ); \
199
+		MODF_HANDLE_RETCODE(h, ret); \
200
+	} while (0)
201
+#endif /* __SUNPRO_C */
202
+
203
+
204
+
205
+/* call a module function with possible RVE params.
206
+ * (used internally in do_action())
207
+ * @param f_type - cmd_function type
208
+ * @param h
209
+ * @param msg
210
+ * @param src - source action_u_t array (e.g. action->val)
211
+ * @param dst - temporary action_u_t array used for conversions. It can be
212
+ *              used for the function parameters. It's contents it's not
213
+ *              valid after the call.
214
+ * @param params... - variable list of parameters, passed to the module
215
+ *               function
216
+ * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), f, dst,
217
+ *               might jump to error.
218
+ *
219
+ */
220
+#ifdef __SUNPRO_C
221
+#define MODF_RVE_CALL(f_type, h, msg, src, dst, ...) \
222
+	do { \
223
+		f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
224
+		MODF_RVE_PARAM_CONVERT(h, msg, src, dst); \
225
+		ret=((f_type)f)((msg), __VAR_ARGS__); \
226
+		MODF_HANDLE_RETCODE(h, ret); \
227
+		/* free strings allocated by us */ \
228
+		MODF_RVE_PARAM_FREE(src, dst); \
229
+	} while (0)
230
+#else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
231
+#define MODF_RVE_CALL(f_type, h, msg, src, dst, params...) \
232
+	do { \
233
+		f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
234
+		MODF_RVE_PARAM_CONVERT(h, msg, src, dst); \
235
+		ret=((f_type)f)((msg), ## params ); \
236
+		MODF_HANDLE_RETCODE(h, ret); \
237
+		/* free strings allocated by us */ \
238
+		MODF_RVE_PARAM_FREE(src, dst); \
239
+	} while (0)
240
+#endif /* __SUNPRO_C */
241
+
242
+
111 243
 /* ret= 0! if action -> end of list(e.g DROP),
112 244
       > 0 to continue processing next actions
113 245
    and <0 on error */
... ...
@@ -135,6 +267,13 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
135 135
 	struct rval_cache c1;
136 136
 	str s;
137 137
 	void *srevp[2];
138
+	/* temporary storage space for a struct action.val[] working copy
139
+	 (needed to transform RVE intro STRING before calling module
140
+	   functions). [0] is not used (corresp. to the module export pointer),
141
+	   [1] contains the number of params, and [2..] the param values.
142
+	   We need [1], because some fixup function use it
143
+	  (see fixup_get_param_count()).  */
144
+	static action_u_t mod_f_params[MAX_ACTIONS];
138 145
 
139 146
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
140 147
 	   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)
872 872
 										(struct action*)a->val[2].u.data, msg);
873 873
 					}
874 874
 			break;
875
-		case MODULE_T:
876
-			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
877
-					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
878
-				ret=((cmd_function)f)(msg,
879
-										(char*)a->val[2].u.data,
880
-										(char*)a->val[3].u.data
881
-									);
882
-				if (ret==0) h->run_flags|=EXIT_R_F;
883
-				h->last_retcode=ret;
884
-				_last_returned_code = h->last_retcode;
885
-			} else {
886
-				LOG(L_CRIT,"BUG: do_action: bad module call\n");
887
-				goto error;
888
-			}
875
+		case MODULE0_T:
876
+			MODF_CALL(cmd_function, h, msg, a->val, 0, 0);
889 877
 			break;
890 878
 		/* instead of using the parameter number, we use different names
891 879
 		 * for calls to functions with 3, 4, 5, 6 or variable number of
892 880
 		 * parameters due to performance reasons */
881
+		case MODULE1_T:
882
+			MODF_CALL(cmd_function, h, msg, a->val,
883
+										(char*)a->val[2].u.data,
884
+										0
885
+					);
886
+			break;
887
+		case MODULE2_T:
888
+			MODF_CALL(cmd_function, h, msg, a->val,
889
+										(char*)a->val[2].u.data,
890
+										(char*)a->val[3].u.data
891
+					);
892
+			break;
893 893
 		case MODULE3_T:
894
-			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
895
-					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
896
-				ret=((cmd_function3)f)(msg,
894
+			MODF_CALL(cmd_function3, h, msg, a->val,
897 895
 										(char*)a->val[2].u.data,
898 896
 										(char*)a->val[3].u.data,
899 897
 										(char*)a->val[4].u.data
900
-									);
901
-				if (ret==0) h->run_flags|=EXIT_R_F;
902
-				h->last_retcode=ret;
903
-				_last_returned_code = h->last_retcode;
904
-			} else {
905
-				LOG(L_CRIT,"BUG: do_action: bad module call\n");
906
-				goto error;
907
-			}
898
+					);
908 899
 			break;
909 900
 		case MODULE4_T:
910
-			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
911
-					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
912
-				ret=((cmd_function4)f)(msg,
901
+			MODF_CALL(cmd_function4, h, msg, a->val,
913 902
 										(char*)a->val[2].u.data,
914 903
 										(char*)a->val[3].u.data,
915 904
 										(char*)a->val[4].u.data,
916 905
 										(char*)a->val[5].u.data
917
-									);
918
-				if (ret==0) h->run_flags|=EXIT_R_F;
919
-				h->last_retcode=ret;
920
-				_last_returned_code = h->last_retcode;
921
-			} else {
922
-				LOG(L_CRIT,"BUG: do_action: bad module call\n");
923
-				goto error;
924
-			}
906
+					);
925 907
 			break;
926 908
 		case MODULE5_T:
927
-			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
928
-					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
929
-				ret=((cmd_function5)f)(msg,
909
+			MODF_CALL(cmd_function5, h, msg, a->val,
930 910
 										(char*)a->val[2].u.data,
931 911
 										(char*)a->val[3].u.data,
932 912
 										(char*)a->val[4].u.data,
933 913
 										(char*)a->val[5].u.data,
934 914
 										(char*)a->val[6].u.data
935
-									);
936
-				if (ret==0) h->run_flags|=EXIT_R_F;
937
-				h->last_retcode=ret;
938
-				_last_returned_code = h->last_retcode;
939
-			} else {
940
-				LOG(L_CRIT,"BUG: do_action: bad module call\n");
941
-				goto error;
942
-			}
915
+					);
943 916
 			break;
944 917
 		case MODULE6_T:
945
-			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
946
-					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
947
-				ret=((cmd_function6)f)(msg,
918
+			MODF_CALL(cmd_function6, h, msg, a->val,
948 919
 										(char*)a->val[2].u.data,
949 920
 										(char*)a->val[3].u.data,
950 921
 										(char*)a->val[4].u.data,
951 922
 										(char*)a->val[5].u.data,
952 923
 										(char*)a->val[6].u.data,
953 924
 										(char*)a->val[7].u.data
954
-									);
955
-				if (ret==0) h->run_flags|=EXIT_R_F;
956
-				h->last_retcode=ret;
957
-				_last_returned_code = h->last_retcode;
958
-			} else {
959
-				LOG(L_CRIT,"BUG: do_action: bad module call\n");
960
-				goto error;
961
-			}
925
+					);
962 926
 			break;
963 927
 		case MODULEX_T:
964
-			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
965
-					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
966
-				ret=((cmd_function_var)f)(msg,
967
-											a->val[1].u.number,
968
-											&a->val[2]
969
-										);
970
-				if (ret==0) h->run_flags|=EXIT_R_F;
971
-				h->last_retcode=ret;
972
-				_last_returned_code = h->last_retcode;
973
-			} else {
974
-				LOG(L_CRIT,"BUG: do_action: bad module call\n");
975
-				goto error;
976
-			}
928
+			MODF_CALL(cmd_function_var, h, msg, a->val,
929
+							a->val[1].u.number, &a->val[2]);
930
+			break;
931
+		case MODULE1_RVE_T:
932
+			MODF_RVE_CALL(cmd_function, h, msg, a->val, mod_f_params,
933
+											(char*)mod_f_params[2].u.data,
934
+											0
935
+					);
936
+			break;
937
+		case MODULE2_RVE_T:
938
+			MODF_RVE_CALL(cmd_function, h, msg, a->val, mod_f_params,
939
+											(char*)mod_f_params[2].u.data,
940
+											(char*)mod_f_params[3].u.data
941
+					);
942
+			break;
943
+		case MODULE3_RVE_T:
944
+			MODF_RVE_CALL(cmd_function3, h, msg, a->val, mod_f_params,
945
+											(char*)mod_f_params[2].u.data,
946
+											(char*)mod_f_params[3].u.data,
947
+											(char*)mod_f_params[4].u.data
948
+					);
949
+			break;
950
+		case MODULE4_RVE_T:
951
+			MODF_RVE_CALL(cmd_function4, h, msg, a->val, mod_f_params,
952
+											(char*)mod_f_params[2].u.data,
953
+											(char*)mod_f_params[3].u.data,
954
+											(char*)mod_f_params[4].u.data,
955
+											(char*)mod_f_params[5].u.data
956
+					);
957
+			break;
958
+		case MODULE5_RVE_T:
959
+			MODF_RVE_CALL(cmd_function5, h, msg, a->val, mod_f_params,
960
+											(char*)mod_f_params[2].u.data,
961
+											(char*)mod_f_params[3].u.data,
962
+											(char*)mod_f_params[4].u.data,
963
+											(char*)mod_f_params[5].u.data,
964
+											(char*)mod_f_params[6].u.data
965
+					);
966
+			break;
967
+		case MODULE6_RVE_T:
968
+			MODF_RVE_CALL(cmd_function6, h, msg, a->val, mod_f_params,
969
+											(char*)mod_f_params[2].u.data,
970
+											(char*)mod_f_params[3].u.data,
971
+											(char*)mod_f_params[4].u.data,
972
+											(char*)mod_f_params[5].u.data,
973
+											(char*)mod_f_params[6].u.data,
974
+											(char*)mod_f_params[7].u.data
975
+					);
976
+			break;
977
+		case MODULEX_RVE_T:
978
+			MODF_RVE_CALL(cmd_function_var, h, msg, a->val, mod_f_params,
979
+							a->val[1].u.number, &mod_f_params[2]);
977 980
 			break;
978 981
 		case EVAL_T:
979 982
 			/* only eval the expression to account for possible
... ...
@@ -242,6 +242,8 @@ static struct case_stms* mk_case_stm(struct rval_expr* ct, int is_re,
242 242
 									struct action* a, int* err);
243 243
 static int case_check_type(struct case_stms* stms);
244 244
 static int case_check_default(struct case_stms* stms);
245
+static int mod_f_params_pre_fixup(struct action* a);
246
+static void free_mod_func_action(struct action* a);
245 247
 
246 248
 
247 249
 extern int line;
... ...
@@ -2215,7 +2217,14 @@ fcmd:
2215 2215
 				case RESETFLAG_T:
2216 2216
 				case ISFLAGSET_T:
2217 2217
 				case IF_T:
2218
-				case MODULE_T:
2218
+				case MODULE0_T:
2219
+				case MODULE1_T:
2220
+				case MODULE2_T:
2221
+				case MODULE3_T:
2222
+				case MODULE4_T:
2223
+				case MODULE5_T:
2224
+				case MODULE6_T:
2225
+				case MODULEX_T:
2219 2226
 				case SET_FWD_NO_CONNECT_T:
2220 2227
 				case SET_RPL_NO_CONNECT_T:
2221 2228
 				case SET_FWD_CLOSE_T:
... ...
@@ -3195,9 +3204,9 @@ cmd:
3195 3195
 	| SET_RPL_CLOSE	{
3196 3196
 		$$=mk_action(SET_RPL_CLOSE_T, 0); set_cfg_pos($$);
3197 3197
 	}
3198
-	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST,
3198
+	| ID {mod_func_action = mk_action(MODULE0_T, 2, MODEXP_ST, NULL, NUMBER_ST,
3199 3199
 			0); } LPAREN func_params RPAREN	{
3200
-		mod_func_action->val[0].u.data = 
3200
+		mod_func_action->val[0].u.data =
3201 3201
 			find_export_record($1, mod_func_action->val[1].u.number, rt,
3202 3202
 								&u_tmp);
3203 3203
 		if (mod_func_action->val[0].u.data == 0) {
... ...
@@ -3207,34 +3216,14 @@ cmd:
3207 3207
 			} else {
3208 3208
 				yyerror("unknown command, missing loadmodule?\n");
3209 3209
 			}
3210
-			pkg_free(mod_func_action);
3210
+			free_mod_func_action(mod_func_action);
3211 3211
 			mod_func_action=0;
3212 3212
 		}else{
3213
-			switch( ((union cmd_export_u*)
3214
-						mod_func_action->val[0].u.data)->c.param_no){
3215
-				case 0:
3216
-				case 1:
3217
-				case 2:
3218
-					/* MODULE_T used for 0-2 params */
3219
-					break;
3220
-				case 3:
3221
-					mod_func_action->type=MODULE3_T;
3222
-					break;
3223
-				case 4:
3224
-					mod_func_action->type=MODULE4_T;
3225
-					break;
3226
-				case 5:
3227
-					mod_func_action->type=MODULE5_T;
3228
-					break;
3229
-				case 6:
3230
-					mod_func_action->type=MODULE6_T;
3231
-					break;
3232
-				case VAR_PARAM_NO:
3233
-					mod_func_action->type=MODULEX_T;
3234
-					break;
3235
-				default:
3236
-					yyerror("too many parameters for function\n");
3237
-					break;
3213
+			if (mod_func_action && mod_f_params_pre_fixup(mod_func_action)<0) {
3214
+				/* error messages are printed inside the function */
3215
+				free_mod_func_action(mod_func_action);
3216
+				mod_func_action = 0;
3217
+				YYERROR;
3238 3218
 			}
3239 3219
 		}
3240 3220
 		$$ = mod_func_action;
... ...
@@ -3246,27 +3235,20 @@ func_params:
3246 3246
 	/* empty */
3247 3247
 	| func_params COMMA func_param { }
3248 3248
 	| func_param {}
3249
-	| func_params error { yyerror("call params error\n"); }
3250 3249
 	;
3251 3250
 func_param:
3252
-        intno {
3253
-		if (mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
3251
+	rval_expr {
3252
+		if ($1 && mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
3254 3253
 			mod_func_action->val[mod_func_action->val[1].u.number+2].type =
3255
-				NUMBER_ST;
3256
-			mod_func_action->val[mod_func_action->val[1].u.number+2].u.number =
3254
+				RVE_ST;
3255
+			mod_func_action->val[mod_func_action->val[1].u.number+2].u.data =
3257 3256
 				$1;
3258 3257
 			mod_func_action->val[1].u.number++;
3259
-		} else {
3258
+		} else if ($1) {
3260 3259
 			yyerror("Too many arguments\n");
3261
-		}
3262
-	}
3263
-	| STRING {
3264
-		if (mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
3265
-			mod_func_action->val[mod_func_action->val[1].u.number+2].type = STRING_ST;
3266
-			mod_func_action->val[mod_func_action->val[1].u.number+2].u.string = $1;
3267
-			mod_func_action->val[1].u.number++;
3260
+			YYERROR;
3268 3261
 		} else {
3269
-			yyerror("Too many arguments\n");
3262
+			YYERROR;
3270 3263
 		}
3271 3264
 	}
3272 3265
 	;
... ...
@@ -3709,6 +3691,121 @@ static int case_check_default(struct case_stms* stms)
3709 3709
 
3710 3710
 
3711 3711
 
3712
+/** fixes the parameters and the type of a module function call.
3713
+ * It is done here instead of fix action, to have quicker feedback
3714
+ * on error cases (e.g. passing a non constant to a function with a 
3715
+ * declared fixup) 
3716
+ * The rest of the fixup is done inside do_action().
3717
+ * @param a - filled module function call (MODULE*_T) action structure
3718
+ *            complete with parameters, starting at val[2] and parameter
3719
+ *            number at val[1].
3720
+ * @return 0 on success, -1 on error (it will also print the error msg.).
3721
+ *
3722
+ */
3723
+static int mod_f_params_pre_fixup(struct action* a)
3724
+{
3725
+	union cmd_export_u* cmd_exp;
3726
+	action_u_t* params;
3727
+	int param_no;
3728
+	struct rval_expr* rve;
3729
+	struct rvalue* rv;
3730
+	int r;
3731
+	str s;
3732
+	
3733
+	cmd_exp = a->val[0].u.data;
3734
+	param_no = a->val[1].u.number;
3735
+	params = &a->val[2];
3736
+	
3737
+	switch(cmd_exp->c.param_no) {
3738
+		case 0:
3739
+			a->type = MODULE0_T;
3740
+			break;
3741
+		case 1:
3742
+			a->type = MODULE1_T;
3743
+			break;
3744
+		case 2:
3745
+			a->type = MODULE2_T;
3746
+			break;
3747
+		case 3:
3748
+			a->type = MODULE3_T;
3749
+			break;
3750
+		case 4:
3751
+			a->type = MODULE4_T;
3752
+			break;
3753
+		case 5:
3754
+			a->type = MODULE5_T;
3755
+			break;
3756
+		case 6:
3757
+			a->type = MODULE6_T;
3758
+			break;
3759
+		case VAR_PARAM_NO:
3760
+			a->type = MODULEX_T;
3761
+			break;
3762
+		default:
3763
+			yyerror("function %s: bad definition"
3764
+					" (invalid number of parameters)", cmd_exp->c.name);
3765
+			return -1;
3766
+	}
3767
+	
3768
+	if ( cmd_exp->c.fixup){
3769
+		/* v0 or v1 functions that have fixups need constant,
3770
+		  string params.*/
3771
+		for (r=0; r < param_no; r++) {
3772
+			rve=params[r].u.data;
3773
+			if (!rve_is_constant(rve)) {
3774
+				yyerror_at(&rve->fpos, "function %s: parameter %d is not"
3775
+							" constant\n", cmd_exp->c.name, r+1);
3776
+				return -1;
3777
+			}
3778
+			if ((rv = rval_expr_eval(0, 0, rve)) == 0 ||
3779
+					rval_get_str(0, 0, &s, rv, 0) < 0 ) {
3780
+				/* out of mem or bug ? */
3781
+				rval_destroy(rv);
3782
+				yyerror_at(&rve->fpos, "function %s: bad parameter %d"
3783
+								" expression\n", cmd_exp->c.name, r+1);
3784
+				return -1;
3785
+			}
3786
+			rval_destroy(rv);
3787
+			rve_destroy(rve);
3788
+			params[r].type = STRING_ST; /* asciiz */
3789
+			params[r].u.string = s.s;
3790
+			params[r].u.str.len = s.len; /* not used right now */
3791
+		}
3792
+	} /* else
3793
+		if no fixups are present, the RVEs can be transformed
3794
+		into strings at runtime, allowing seamless var. use
3795
+		even with old functions.
3796
+		Further optimizations -> in fix_actions()
3797
+		*/
3798
+	return 0;
3799
+}
3800
+
3801
+
3802
+
3803
+/** frees a filled module function call action structure.
3804
+ * @param a - filled module function call action structure
3805
+ *            complete with parameters, starting at val[2] and parameter
3806
+ *            number at val[1].
3807
+ */
3808
+static void free_mod_func_action(struct action* a)
3809
+{
3810
+	union cmd_export_u* cmd_exp;
3811
+	action_u_t* params;
3812
+	int param_no;
3813
+	int r;
3814
+	
3815
+	cmd_exp = a->val[0].u.data;
3816
+	param_no = a->val[1].u.number;
3817
+	params = &a->val[2];
3818
+	
3819
+	for (r=0; r < param_no; r++)
3820
+		if (params[r].u.data)
3821
+			rve_destroy(params[r].u.data);
3822
+	pkg_free(a);
3823
+}
3824
+
3825
+
3826
+
3712 3827
 /*
3713 3828
 int main(int argc, char ** argv)
3714 3829
 {
... ...
@@ -629,6 +629,7 @@ int fix_actions(struct action* a)
629 629
 	struct action *t;
630 630
 	struct proxy_l* p;
631 631
 	char *tmp;
632
+	void *tmp_p;
632 633
 	int ret;
633 634
 	int i;
634 635
 	union cmd_export_u* cmd;
... ...
@@ -640,6 +641,8 @@ int fix_actions(struct action* a)
640 640
 	struct rval_expr* rve;
641 641
 	struct rval_expr* err_rve;
642 642
 	enum rval_type rve_type, err_type, expected_type;
643
+	struct rvalue* rv;
644
+	int rve_param_no;
643 645
 
644 646
 	
645 647
 	char buf[30]; /* tmp buffer needed for module param fixups */
... ...
@@ -907,13 +910,16 @@ int fix_actions(struct action* a)
907 907
 					goto error;
908 908
 				break;
909 909
 
910
-			case MODULE_T:
910
+			case MODULE0_T:
911
+			case MODULE1_T:
912
+			case MODULE2_T:
911 913
 			case MODULE3_T:
912 914
 			case MODULE4_T:
913 915
 			case MODULE5_T:
914 916
 			case MODULE6_T:
915 917
 			case MODULEX_T:
916 918
 				cmd = t->val[0].u.data;
919
+				rve_param_no = 0;
917 920
 				if (cmd && cmd->c.fixup) {
918 921
 					DBG("fixing %s()\n", cmd->c.name);
919 922
 					if (t->val[1].u.number==0) {
... ...
@@ -924,6 +930,7 @@ int fix_actions(struct action* a)
924 924
 					/* type cast NUMBER to STRING, old modules may expect
925 925
 					 * all STRING params during fixup */
926 926
 					for (i=0; i<t->val[1].u.number; i++) {
927
+						/* obsoleted by the new RVE changes ? */
927 928
 						if (t->val[i+2].type == NUMBER_ST) {
928 929
 							snprintf(buf, sizeof(buf)-1, "%ld", 
929 930
 										t->val[i+2].u.number);
... ...
@@ -937,17 +944,84 @@ int fix_actions(struct action* a)
937 937
 							}
938 938
 							strcpy(t->val[i+2].u.string, buf);
939 939
 							t->val[i+2].type = STRING_ST;
940
+						}else if (t->val[i+2].type != STRING_ST) {
941
+							BUG("unsupported function parameter type %d\n",
942
+									t->val[i+2].type);
940 943
 						}
941 944
 					}
942
-					for (i=0; i<t->val[1].u.number; i++) {
943
-						void *p;
944
-						p = t->val[i+2].u.data;
945
+					for (i=0; i < t->val[1].u.number; i++) {
946
+						tmp_p = t->val[i+2].u.data;
945 947
 						ret = cmd->c.fixup(&t->val[i+2].u.data, i+1);
946
-						if (t->val[i+2].u.data != p)
948
+						if (t->val[i+2].u.data != tmp_p)
947 949
 							t->val[i+2].type = MODFIXUP_ST;
948 950
 						if (ret < 0)
949 951
 							goto error;
950 952
 					}
953
+				} else if (cmd) { /* no fixup => RVE supported => optimize */
954
+					for (i=0; i < t->val[1].u.number; i++) {
955
+						if (t->val[i+2].type == RVE_ST) {
956
+							rve = t->val[i+2].u.data;
957
+							if (rve_is_constant(rve)) {
958
+								/* if expression is constant => evaluate it
959
+								   as string and replace it with the corresp.
960
+								   string */
961
+								rv = rval_expr_eval(0, 0, rve);
962
+								if (rv == 0 ||
963
+										rval_get_str( 0, 0, &s, rv, 0) < 0 ) {
964
+									ERR("failed to fix constant rve");
965
+									if (rv) rval_destroy(rv);
966
+									ret = E_BUG;
967
+									goto error;
968
+								}
969
+								rval_destroy(rv);
970
+								rve_destroy(rve);
971
+								t->val[i+2].type = STRING_ST;/*asciiz string*/
972
+								t->val[i+2].u.string = s.s;
973
+								/* len is not used for now */
974
+								t->val[i+2].u.str.len = s.len;
975
+							} else {
976
+								/* expression is not constant => fixup &
977
+								   optimize it */
978
+								rve_param_no++;
979
+								if ((ret=fix_rval_expr(&t->val[i+2].u.data))
980
+										< 0) {
981
+									ERR("rve fixup failed\n");
982
+									ret = E_BUG;
983
+									goto error;
984
+								}
985
+							}
986
+						} /* if RVE_ST */
987
+					}
988
+					if (rve_param_no) { /* we have to fix the type */
989
+						switch(t->type) {
990
+							case MODULE1_T:
991
+								t->type = MODULE1_RVE_T;
992
+								break;
993
+							case MODULE2_T:
994
+								t->type = MODULE2_RVE_T;
995
+								break;
996
+							case MODULE3_T:
997
+								t->type = MODULE3_RVE_T;
998
+								break;
999
+							case MODULE4_T:
1000
+								t->type = MODULE4_RVE_T;
1001
+								break;
1002
+							case MODULE5_T:
1003
+								t->type = MODULE5_RVE_T;
1004
+								break;
1005
+							case MODULE6_T:
1006
+								t->type = MODULE6_RVE_T;
1007
+								break;
1008
+							case MODULEX_T:
1009
+								t->type = MODULEX_RVE_T;
1010
+								break;
1011
+							default:
1012
+								BUG("unsupported module function type %d\n",
1013
+										t->type);
1014
+								ret = E_BUG;
1015
+								goto error;
1016
+						}
1017
+					} /* if rve_param_no */
951 1018
 				}
952 1019
 				break;
953 1020
 			case FORCE_SEND_SOCKET_T:
... ...
@@ -443,12 +443,21 @@ void print_action(struct action* t)
443 443
 		case IF_T:
444 444
 			DBG("if (");
445 445
 			break;
446
-		case MODULE_T:
446
+		case MODULE0_T:
447
+		case MODULE1_T:
448
+		case MODULE2_T:
447 449
 		case MODULE3_T:
448 450
 		case MODULE4_T:
449 451
 		case MODULE5_T:
450 452
 		case MODULE6_T:
451 453
 		case MODULEX_T:
454
+		case MODULE1_RVE_T:
455
+		case MODULE2_RVE_T:
456
+		case MODULE3_RVE_T:
457
+		case MODULE4_RVE_T:
458
+		case MODULE5_RVE_T:
459
+		case MODULE6_RVE_T:
460
+		case MODULEX_RVE_T:
452 461
 			DBG(" external_module_call(");
453 462
 			break;
454 463
 		case FORCE_RPORT_T:
... ...
@@ -85,7 +85,12 @@ enum action_type{
85 85
 		SET_USERPHONE_T,
86 86
 		IF_T, SWITCH_T /* only until fixup*/,
87 87
 		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, MATCH_COND_T, WHILE_T,
88
-		MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
88
+		/* module function calls with string only parameters */
89
+		MODULE0_T, MODULE1_T, MODULE2_T, MODULE3_T, MODULE4_T, MODULE5_T,
90
+		MODULE6_T, MODULEX_T,
91
+		/* module function calls, that have some RVE parameters */
92
+		MODULE1_RVE_T, MODULE2_RVE_T, MODULE3_RVE_T,
93
+		MODULE4_RVE_T, MODULE5_RVE_T, MODULE6_RVE_T, MODULEX_RVE_T,
89 94
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
90 95
 		AVPFLAG_OPER_T,
91 96
 		LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T,