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 267
 	struct rval_cache c1;
136 268
 	str s;
137 269
 	void *srevp[2];
270
+	/* temporary storage space for a struct action.val[] working copy
271
+	 (needed to transform RVE intro STRING before calling module
272
+	   functions). [0] is not used (corresp. to the module export pointer),
273
+	   [1] contains the number of params, and [2..] the param values.
274
+	   We need [1], because some fixup function use it
275
+	  (see fixup_get_param_count()).  */
276
+	static action_u_t mod_f_params[MAX_ACTIONS];
138 277
 
139 278
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
140 279
 	   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 1011
 										(struct action*)a->val[2].u.data, msg);
873 1012
 					}
874 1013
 			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
-			}
1014
+		case MODULE0_T:
1015
+			MODF_CALL(cmd_function, h, msg, a->val, 0, 0);
889 1016
 			break;
890 1017
 		/* instead of using the parameter number, we use different names
891 1018
 		 * for calls to functions with 3, 4, 5, 6 or variable number of
892 1019
 		 * parameters due to performance reasons */
1020
+		case MODULE1_T:
1021
+			MODF_CALL(cmd_function, h, msg, a->val,
1022
+										(char*)a->val[2].u.data,
1023
+										0
1024
+					);
1025
+			break;
1026
+		case MODULE2_T:
1027
+			MODF_CALL(cmd_function, h, msg, a->val,
1028
+										(char*)a->val[2].u.data,
1029
+										(char*)a->val[3].u.data
1030
+					);
1031
+			break;
893 1032
 		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,
1033
+			MODF_CALL(cmd_function3, h, msg, a->val,
897 1034
 										(char*)a->val[2].u.data,
898 1035
 										(char*)a->val[3].u.data,
899 1036
 										(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
-			}
1037
+					);
908 1038
 			break;
909 1039
 		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,
1040
+			MODF_CALL(cmd_function4, h, msg, a->val,
913 1041
 										(char*)a->val[2].u.data,
914 1042
 										(char*)a->val[3].u.data,
915 1043
 										(char*)a->val[4].u.data,
916 1044
 										(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
-			}
1045
+					);
925 1046
 			break;
926 1047
 		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,
1048
+			MODF_CALL(cmd_function5, h, msg, a->val,
930 1049
 										(char*)a->val[2].u.data,
931 1050
 										(char*)a->val[3].u.data,
932 1051
 										(char*)a->val[4].u.data,
933 1052
 										(char*)a->val[5].u.data,
934 1053
 										(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
-			}
1054
+					);
943 1055
 			break;
944 1056
 		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,
1057
+			MODF_CALL(cmd_function6, h, msg, a->val,
948 1058
 										(char*)a->val[2].u.data,
949 1059
 										(char*)a->val[3].u.data,
950 1060
 										(char*)a->val[4].u.data,
951 1061
 										(char*)a->val[5].u.data,
952 1062
 										(char*)a->val[6].u.data,
953 1063
 										(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
-			}
1064
+					);
962 1065
 			break;
963 1066
 		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
-			}
1067
+			MODF_CALL(cmd_function_var, h, msg, a->val,
1068
+							a->val[1].u.number, &a->val[2]);
1069
+			break;
1070
+		case MODULE1_RVE_T:
1071
+			MODF_RVE_CALL(cmd_function, h, msg, a->val, mod_f_params,
1072
+											(char*)mod_f_params[2].u.data,
1073
+											0
1074
+					);
1075
+			break;
1076
+		case MODULE2_RVE_T:
1077
+			MODF_RVE_CALL(cmd_function, h, msg, a->val, mod_f_params,
1078
+											(char*)mod_f_params[2].u.data,
1079
+											(char*)mod_f_params[3].u.data
1080
+					);
1081
+			break;
1082
+		case MODULE3_RVE_T:
1083
+			MODF_RVE_CALL(cmd_function3, h, msg, a->val, mod_f_params,
1084
+											(char*)mod_f_params[2].u.data,
1085
+											(char*)mod_f_params[3].u.data,
1086
+											(char*)mod_f_params[4].u.data
1087
+					);
1088
+			break;
1089
+		case MODULE4_RVE_T:
1090
+			MODF_RVE_CALL(cmd_function4, h, msg, a->val, mod_f_params,
1091
+											(char*)mod_f_params[2].u.data,
1092
+											(char*)mod_f_params[3].u.data,
1093
+											(char*)mod_f_params[4].u.data,
1094
+											(char*)mod_f_params[5].u.data
1095
+					);
1096
+			break;
1097
+		case MODULE5_RVE_T:
1098
+			MODF_RVE_CALL(cmd_function5, h, msg, a->val, mod_f_params,
1099
+											(char*)mod_f_params[2].u.data,
1100
+											(char*)mod_f_params[3].u.data,
1101
+											(char*)mod_f_params[4].u.data,
1102
+											(char*)mod_f_params[5].u.data,
1103
+											(char*)mod_f_params[6].u.data
1104
+					);
1105
+			break;
1106
+		case MODULE6_RVE_T:
1107
+			MODF_RVE_CALL(cmd_function6, h, msg, a->val, mod_f_params,
1108
+											(char*)mod_f_params[2].u.data,
1109
+											(char*)mod_f_params[3].u.data,
1110
+											(char*)mod_f_params[4].u.data,
1111
+											(char*)mod_f_params[5].u.data,
1112
+											(char*)mod_f_params[6].u.data,
1113
+											(char*)mod_f_params[7].u.data
1114
+					);
1115
+			break;
1116
+		case MODULEX_RVE_T:
1117
+			MODF_RVE_CALL(cmd_function_var, h, msg, a->val, mod_f_params,
1118
+							a->val[1].u.number, &mod_f_params[2]);
977 1119
 			break;
978 1120
 		case EVAL_T:
979 1121
 			/* 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 2217
 				case RESETFLAG_T:
2216 2218
 				case ISFLAGSET_T:
2217 2219
 				case IF_T:
2218
-				case MODULE_T:
2220
+				case MODULE0_T:
2221
+				case MODULE1_T:
2222
+				case MODULE2_T:
2223
+				case MODULE3_T:
2224
+				case MODULE4_T:
2225
+				case MODULE5_T:
2226
+				case MODULE6_T:
2227
+				case MODULEX_T:
2219 2228
 				case SET_FWD_NO_CONNECT_T:
2220 2229
 				case SET_RPL_NO_CONNECT_T:
2221 2230
 				case SET_FWD_CLOSE_T:
... ...
@@ -3195,9 +3204,9 @@ cmd:
3195 3204
 	| SET_RPL_CLOSE	{
3196 3205
 		$$=mk_action(SET_RPL_CLOSE_T, 0); set_cfg_pos($$);
3197 3206
 	}
3198
-	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST,
3207
+	| ID {mod_func_action = mk_action(MODULE0_T, 2, MODEXP_ST, NULL, NUMBER_ST,
3199 3208
 			0); } LPAREN func_params RPAREN	{
3200
-		mod_func_action->val[0].u.data = 
3209
+		mod_func_action->val[0].u.data =
3201 3210
 			find_export_record($1, mod_func_action->val[1].u.number, rt,
3202 3211
 								&u_tmp);
3203 3212
 		if (mod_func_action->val[0].u.data == 0) {
... ...
@@ -3207,34 +3216,14 @@ cmd:
3207 3216
 			} else {
3208 3217
 				yyerror("unknown command, missing loadmodule?\n");
3209 3218
 			}
3210
-			pkg_free(mod_func_action);
3219
+			free_mod_func_action(mod_func_action);
3211 3220
 			mod_func_action=0;
3212 3221
 		}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;
3222
+			if (mod_func_action && mod_f_params_pre_fixup(mod_func_action)<0) {
3223
+				/* error messages are printed inside the function */
3224
+				free_mod_func_action(mod_func_action);
3225
+				mod_func_action = 0;
3226
+				YYERROR;
3238 3227
 			}
3239 3228
 		}
3240 3229
 		$$ = mod_func_action;
... ...
@@ -3246,27 +3235,20 @@ func_params:
3246 3235
 	/* empty */
3247 3236
 	| func_params COMMA func_param { }
3248 3237
 	| func_param {}
3249
-	| func_params error { yyerror("call params error\n"); }
3250 3238
 	;
3251 3239
 func_param:
3252
-        intno {
3253
-		if (mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
3240
+	rval_expr {
3241
+		if ($1 && mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
3254 3242
 			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 =
3243
+				RVE_ST;
3244
+			mod_func_action->val[mod_func_action->val[1].u.number+2].u.data =
3257 3245
 				$1;
3258 3246
 			mod_func_action->val[1].u.number++;
3259
-		} else {
3247
+		} else if ($1) {
3260 3248
 			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++;
3249
+			YYERROR;
3268 3250
 		} else {
3269
-			yyerror("Too many arguments\n");
3251
+			YYERROR;
3270 3252
 		}
3271 3253
 	}
3272 3254
 	;
... ...
@@ -3709,6 +3691,121 @@ static int case_check_default(struct case_stms* stms)
3709 3691
 
3710 3692
 
3711 3693
 
3694
+/** fixes the parameters and the type of a module function call.
3695
+ * It is done here instead of fix action, to have quicker feedback
3696
+ * on error cases (e.g. passing a non constant to a function with a 
3697
+ * declared fixup) 
3698
+ * The rest of the fixup is done inside do_action().
3699
+ * @param a - filled module function call (MODULE*_T) action structure
3700
+ *            complete with parameters, starting at val[2] and parameter
3701
+ *            number at val[1].
3702
+ * @return 0 on success, -1 on error (it will also print the error msg.).
3703
+ *
3704
+ */
3705
+static int mod_f_params_pre_fixup(struct action* a)
3706
+{
3707
+	union cmd_export_u* cmd_exp;
3708
+	action_u_t* params;
3709
+	int param_no;
3710
+	struct rval_expr* rve;
3711
+	struct rvalue* rv;
3712
+	int r;
3713
+	str s;
3714
+	
3715
+	cmd_exp = a->val[0].u.data;
3716
+	param_no = a->val[1].u.number;
3717
+	params = &a->val[2];
3718
+	
3719
+	switch(cmd_exp->c.param_no) {
3720
+		case 0:
3721
+			a->type = MODULE0_T;
3722
+			break;
3723
+		case 1:
3724
+			a->type = MODULE1_T;
3725
+			break;
3726
+		case 2:
3727
+			a->type = MODULE2_T;
3728
+			break;
3729
+		case 3:
3730
+			a->type = MODULE3_T;
3731
+			break;
3732
+		case 4:
3733
+			a->type = MODULE4_T;
3734
+			break;
3735
+		case 5:
3736
+			a->type = MODULE5_T;
3737
+			break;
3738
+		case 6:
3739
+			a->type = MODULE6_T;
3740
+			break;
3741
+		case VAR_PARAM_NO:
3742
+			a->type = MODULEX_T;
3743
+			break;
3744
+		default:
3745
+			yyerror("function %s: bad definition"
3746
+					" (invalid number of parameters)", cmd_exp->c.name);
3747
+			return -1;
3748
+	}
3749
+	
3750
+	if ( cmd_exp->c.fixup){
3751
+		/* v0 or v1 functions that have fixups need constant,
3752
+		  string params.*/
3753
+		for (r=0; r < param_no; r++) {
3754
+			rve=params[r].u.data;
3755
+			if (!rve_is_constant(rve)) {
3756
+				yyerror_at(&rve->fpos, "function %s: parameter %d is not"
3757
+							" constant\n", cmd_exp->c.name, r+1);
3758
+				return -1;
3759
+			}
3760
+			if ((rv = rval_expr_eval(0, 0, rve)) == 0 ||
3761
+					rval_get_str(0, 0, &s, rv, 0) < 0 ) {
3762
+				/* out of mem or bug ? */
3763
+				rval_destroy(rv);
3764
+				yyerror_at(&rve->fpos, "function %s: bad parameter %d"
3765
+								" expression\n", cmd_exp->c.name, r+1);
3766
+				return -1;
3767
+			}
3768
+			rval_destroy(rv);
3769
+			rve_destroy(rve);
3770
+			params[r].type = STRING_ST; /* asciiz */
3771
+			params[r].u.string = s.s;
3772
+			params[r].u.str.len = s.len; /* not used right now */
3773
+		}
3774
+	} /* else
3775
+		if no fixups are present, the RVEs can be transformed
3776
+		into strings at runtime, allowing seamless var. use
3777
+		even with old functions.
3778
+		Further optimizations -> in fix_actions()
3779
+		*/
3780
+	return 0;
3781
+}
3782
+
3783
+
3784
+
3785
+/** frees a filled module function call action structure.
3786
+ * @param a - filled module function call action structure
3787
+ *            complete with parameters, starting at val[2] and parameter
3788
+ *            number at val[1].
3789
+ */
3790
+static void free_mod_func_action(struct action* a)
3791
+{
3792
+	union cmd_export_u* cmd_exp;
3793
+	action_u_t* params;
3794
+	int param_no;
3795
+	int r;
3796
+	
3797
+	cmd_exp = a->val[0].u.data;
3798
+	param_no = a->val[1].u.number;
3799
+	params = &a->val[2];
3800
+	
3801
+	for (r=0; r < param_no; r++)
3802
+		if (params[r].u.data)
3803
+			rve_destroy(params[r].u.data);
3804
+	pkg_free(a);
3805
+}
3806
+
3807
+
3808
+
3712 3809
 /*
3713 3810
 int main(int argc, char ** argv)
3714 3811
 {
... ...
@@ -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 641
 	struct rval_expr* rve;
641 642
 	struct rval_expr* err_rve;
642 643
 	enum rval_type rve_type, err_type, expected_type;
644
+	struct rvalue* rv;
645
+	int rve_param_no;
643 646
 
644 647
 	
645 648
 	char buf[30]; /* tmp buffer needed for module param fixups */
... ...
@@ -907,13 +910,16 @@ int fix_actions(struct action* a)
907 910
 					goto error;
908 911
 				break;
909 912
 
910
-			case MODULE_T:
913
+			case MODULE0_T:
914
+			case MODULE1_T:
915
+			case MODULE2_T:
911 916
 			case MODULE3_T:
912 917
 			case MODULE4_T:
913 918
 			case MODULE5_T:
914 919
 			case MODULE6_T:
915 920
 			case MODULEX_T:
916 921
 				cmd = t->val[0].u.data;
922
+				rve_param_no = 0;
917 923
 				if (cmd && cmd->c.fixup) {
918 924
 					DBG("fixing %s()\n", cmd->c.name);
919 925
 					if (t->val[1].u.number==0) {
... ...
@@ -924,6 +930,7 @@ int fix_actions(struct action* a)
924 930
 					/* type cast NUMBER to STRING, old modules may expect
925 931
 					 * all STRING params during fixup */
926 932
 					for (i=0; i<t->val[1].u.number; i++) {
933
+						/* obsoleted by the new RVE changes ? */
927 934
 						if (t->val[i+2].type == NUMBER_ST) {
928 935
 							snprintf(buf, sizeof(buf)-1, "%ld", 
929 936
 										t->val[i+2].u.number);
... ...
@@ -937,17 +944,84 @@ int fix_actions(struct action* a)
937 944
 							}
938 945
 							strcpy(t->val[i+2].u.string, buf);
939 946
 							t->val[i+2].type = STRING_ST;
947
+						}else if (t->val[i+2].type != STRING_ST) {
948
+							BUG("unsupported function parameter type %d\n",
949
+									t->val[i+2].type);
940 950
 						}
941 951
 					}
942
-					for (i=0; i<t->val[1].u.number; i++) {
943
-						void *p;
944
-						p = t->val[i+2].u.data;
952
+					for (i=0; i < t->val[1].u.number; i++) {
953
+						tmp_p = t->val[i+2].u.data;
945 954
 						ret = cmd->c.fixup(&t->val[i+2].u.data, i+1);
946
-						if (t->val[i+2].u.data != p)
955
+						if (t->val[i+2].u.data != tmp_p)
947 956
 							t->val[i+2].type = MODFIXUP_ST;
948 957
 						if (ret < 0)
949 958
 							goto error;
950 959
 					}
960
+				} else if (cmd) { /* no fixup => RVE supported => optimize */
961
+					for (i=0; i < t->val[1].u.number; i++) {
962
+						if (t->val[i+2].type == RVE_ST) {
963
+							rve = t->val[i+2].u.data;
964
+							if (rve_is_constant(rve)) {
965
+								/* if expression is constant => evaluate it
966
+								   as string and replace it with the corresp.
967
+								   string */
968
+								rv = rval_expr_eval(0, 0, rve);
969
+								if (rv == 0 ||
970
+										rval_get_str( 0, 0, &s, rv, 0) < 0 ) {
971
+									ERR("failed to fix constant rve");
972
+									if (rv) rval_destroy(rv);
973
+									ret = E_BUG;
974
+									goto error;
975
+								}
976
+								rval_destroy(rv);
977
+								rve_destroy(rve);
978
+								t->val[i+2].type = STRING_ST;/*asciiz string*/
979
+								t->val[i+2].u.string = s.s;
980
+								/* len is not used for now */
981
+								t->val[i+2].u.str.len = s.len;
982
+							} else {
983
+								/* expression is not constant => fixup &
984
+								   optimize it */
985
+								rve_param_no++;
986
+								if ((ret=fix_rval_expr(&t->val[i+2].u.data))
987
+										< 0) {
988
+									ERR("rve fixup failed\n");
989
+									ret = E_BUG;
990
+									goto error;
991
+								}
992
+							}
993
+						} /* if RVE_ST */
994
+					}
995
+					if (rve_param_no) { /* we have to fix the type */
996
+						switch(t->type) {
997
+							case MODULE1_T:
998
+								t->type = MODULE1_RVE_T;
999
+								break;
1000
+							case MODULE2_T:
1001
+								t->type = MODULE2_RVE_T;
1002
+								break;
1003
+							case MODULE3_T:
1004
+								t->type = MODULE3_RVE_T;
1005
+								break;
1006
+							case MODULE4_T:
1007
+								t->type = MODULE4_RVE_T;
1008
+								break;
1009
+							case MODULE5_T:
1010
+								t->type = MODULE5_RVE_T;
1011
+								break;
1012
+							case MODULE6_T:
1013
+								t->type = MODULE6_RVE_T;
1014
+								break;
1015
+							case MODULEX_T:
1016
+								t->type = MODULEX_RVE_T;
1017
+								break;
1018
+							default:
1019
+								BUG("unsupported module function type %d\n",
1020
+										t->type);
1021
+								ret = E_BUG;
1022
+								goto error;
1023
+						}
1024
+					} /* if rve_param_no */
951 1025
 				}
952 1026
 				break;
953 1027
 			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,