Browse code

core: support for RVEs in fparam fixups

Hack to allow using RVEs in "safe" fparam fixups. This way all the
module functions using them will automatically have var support
(most ser modules that already supported variables as quoted
parameter, support now any variable expression, without quotes
too).
The cleanup is done by the core (this is the "hack" part).

E.g.:
t_set_fr($v + 2 + $x) should work now
(it uses fixup_var_int_1 which is RVE-safe).

t_set_fr("$v") is now equivalent with t_set_fr($v).

Andrei Pelinescu-Onciul authored on 02/06/2010 16:24:05
Showing 6 changed files
... ...
@@ -51,6 +51,8 @@
51 51
  *  2008-12-17  added UDP_MTU_TRY_PROTO_T (andrei)
52 52
  *  2009-05-04  switched IF_T to rval_expr (andrei)
53 53
  *  2009-09-15  added SET_{FWD,RPL}_NO_CONNECT, SET_{FWD,RPL}_CLOSE (andrei)
54
+ *  2010-06-01  special hack/support for fparam fixups so that they can handle
55
+ *               variable RVEs (andrei)
54 56
  */
55 57
 
56 58
 /*!
... ...
@@ -133,9 +135,14 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
133 135
  */
134 136
 #define MODF_RVE_PARAM_FREE(src, dst) \
135 137
 		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; \
138
+			if ((src)[i+2].type == RVE_ST && (dst)[i+2].u.data) { \
139
+				if ((dst)[i+2].type == FPARAM_DYN_ST) {\
140
+					/* frees also orig. dst.u.data */ \
141
+					fparam_free_contents((dst)[i+2].u.data); \
142
+					/* the fparam struct. (dst.u.data) is freed below */ \
143
+				} \
144
+				pkg_free((dst)[i+2].u.data); \
145
+				(dst)[i+2].u.data = 0; \
139 146
 			} \
140 147
 		}
141 148
 
... ...
@@ -147,7 +154,7 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
147 154
  * WARNING: dst must be cleaned when done, use MODULE_RVE_PARAM_FREE()
148 155
  * Side-effects: clobbers i (int), s (str), rv (rvalue*), might jump to error.
149 156
  */
150
-#define MODF_RVE_PARAM_CONVERT(h, msg, src, dst) \
157
+#define MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst) \
151 158
 	do { \
152 159
 		(dst)[1]=(src)[1]; \
153 160
 		for (i=0; i < (src)[1].u.number; i++) { \
... ...
@@ -165,6 +172,12 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
165 172
 				(dst)[i+2].u.string = s.s; \
166 173
 				(dst)[i+2].u.str.len = s.len; \
167 174
 				rval_destroy(rv); \
175
+				if ((cmd)->c.fixup && \
176
+						(long)(cmd)->c.fixup & FIXUP_F_FPARAM_RVE) { \
177
+					call_fixup((cmd)->c.fixup, &(dst)[i+2].u.data, i+1); \
178
+					if ((dst)[i+2].u.data != s.s) \
179
+						(dst)[i+2].type = FPARAM_DYN_ST; \
180
+				} \
168 181
 			} else \
169 182
 				(dst)[i+2]=(src)[i+2]; \
170 183
 		} \
... ...
@@ -180,22 +193,22 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
180 193
  * @param src - source action_u_t array (e.g. action->val)
181 194
  * @param params... - variable list of parameters, passed to the module
182 195
  *               function
183
- * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), f,
196
+ * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), cmd,
184 197
  *               might jump to error.
185 198
  *
186 199
  */
187 200
 #ifdef __SUNPRO_C
188 201
 #define MODF_CALL(f_type, h, msg, src, ...) \
189 202
 	do { \
190
-		f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
191
-		ret=((f_type)f)((msg), __VAR_ARGS__); \
203
+		cmd=(src)[0].u.data; \
204
+		ret=((f_type)cmd->c.function)((msg), __VAR_ARGS__); \
192 205
 		MODF_HANDLE_RETCODE(h, ret); \
193 206
 	} while (0)
194 207
 #else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
195 208
 #define MODF_CALL(f_type, h, msg, src, params...) \
196 209
 	do { \
197
-		f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
198
-		ret=((f_type)f)((msg), ## params ); \
210
+		cmd=(src)[0].u.data; \
211
+		ret=((f_type)cmd->c.function)((msg), ## params ); \
199 212
 		MODF_HANDLE_RETCODE(h, ret); \
200 213
 	} while (0)
201 214
 #endif /* __SUNPRO_C */
... ...
@@ -220,21 +233,21 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
220 233
 #ifdef __SUNPRO_C
221 234
 #define MODF_RVE_CALL(f_type, h, msg, src, dst, ...) \
222 235
 	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__); \
236
+		cmd=(src)[0].u.data; \
237
+		MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst); \
238
+		ret=((f_type)cmd->c.function)((msg), __VAR_ARGS__); \
226 239
 		MODF_HANDLE_RETCODE(h, ret); \
227
-		/* free strings allocated by us */ \
240
+		/* free strings allocated by us or fixups */ \
228 241
 		MODF_RVE_PARAM_FREE(src, dst); \
229 242
 	} while (0)
230 243
 #else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
231 244
 #define MODF_RVE_CALL(f_type, h, msg, src, dst, params...) \
232 245
 	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 ); \
246
+		cmd=(src)[0].u.data; \
247
+		MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst); \
248
+		ret=((f_type)cmd->c.function)((msg), ## params ); \
236 249
 		MODF_HANDLE_RETCODE(h, ret); \
237
-		/* free strings allocated by us */ \
250
+		/* free strings allocated by us or fixups */ \
238 251
 		MODF_RVE_PARAM_FREE(src, dst); \
239 252
 	} while (0)
240 253
 #endif /* __SUNPRO_C */
... ...
@@ -250,7 +263,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
250 263
 	struct dest_info dst;
251 264
 	char* tmp;
252 265
 	char *new_uri, *end, *crt;
253
-	void* f;
266
+	union cmd_export_u* cmd;
254 267
 	int len;
255 268
 	int user;
256 269
 	struct sip_uri uri, next_hop;
... ...
@@ -3747,31 +3747,38 @@ static int mod_f_params_pre_fixup(struct action* a)
3747 3747
 			return -1;
3748 3748
 	}
3749 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 ? */
3750
+	if ( cmd_exp->c.fixup) {
3751
+		if (is_fparam_rve_fixup(cmd_exp->c.fixup))
3752
+			/* mark known fparam rve safe fixups */
3753
+			cmd_exp->c.fixup  = (fixup_function)
3754
+									((unsigned long) cmd_exp->c.fixup |
3755
+										 FIXUP_F_FPARAM_RVE);
3756
+		else if (!((unsigned long)cmd_exp->c.fixup & FIXUP_F_FPARAM_RVE)) {
3757
+			/* v0 or v1 functions that have fixups need constant,
3758
+			  string params.*/
3759
+			for (r=0; r < param_no; r++) {
3760
+				rve=params[r].u.data;
3761
+				if (!rve_is_constant(rve)) {
3762
+					yyerror_at(&rve->fpos, "function %s: parameter %d is not"
3763
+								" constant\n", cmd_exp->c.name, r+1);
3764
+					return -1;
3765
+				}
3766
+				if ((rv = rval_expr_eval(0, 0, rve)) == 0 ||
3767
+						rval_get_str(0, 0, &s, rv, 0) < 0 ) {
3768
+					/* out of mem or bug ? */
3769
+					rval_destroy(rv);
3770
+					yyerror_at(&rve->fpos, "function %s: bad parameter %d"
3771
+									" expression\n", cmd_exp->c.name, r+1);
3772
+					return -1;
3773
+				}
3763 3774
 				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;
3775
+				rve_destroy(rve);
3776
+				params[r].type = STRING_ST; /* asciiz */
3777
+				params[r].u.string = s.s;
3778
+				params[r].u.str.len = s.len; /* not used right now */
3767 3779
 			}
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 3780
 		}
3774
-	} /* else
3781
+	}/* else
3775 3782
 		if no fixups are present, the RVEs can be transformed
3776 3783
 		into strings at runtime, allowing seamless var. use
3777 3784
 		even with old functions.
... ...
@@ -50,6 +50,8 @@
50 50
  *  		unless the operator is DIFF_OP (Miklos)
51 51
  *  2008-12-03  fixups for rvalues in assignments (andrei)
52 52
  *  2009-05-04  switched IF_T to rval_expr (andrei)
53
+ *  2010-06-01  special hack/support for fparam fixups so that they can handle
54
+ *               variable RVEs (andrei)
53 55
  */
54 56
 
55 57
 
... ...
@@ -644,9 +646,6 @@ int fix_actions(struct action* a)
644 646
 	struct rvalue* rv;
645 647
 	int rve_param_no;
646 648
 
647
-	
648
-	char buf[30]; /* tmp buffer needed for module param fixups */
649
-
650 649
 	if (a==0){
651 650
 		LOG(L_CRIT,"BUG: fix_actions: null pointer\n");
652 651
 		return E_BUG;
... ...
@@ -920,44 +919,13 @@ int fix_actions(struct action* a)
920 919
 			case MODULEX_T:
921 920
 				cmd = t->val[0].u.data;
922 921
 				rve_param_no = 0;
923
-				if (cmd && cmd->c.fixup) {
922
+				if (cmd) {
924 923
 					DBG("fixing %s()\n", cmd->c.name);
925 924
 					if (t->val[1].u.number==0) {
926
-						ret = cmd->c.fixup(0, 0);
927
-						if (ret < 0)
928
-							goto error;
929
-					}
930
-					/* type cast NUMBER to STRING, old modules may expect
931
-					 * all STRING params during fixup */
932
-					for (i=0; i<t->val[1].u.number; i++) {
933
-						/* obsoleted by the new RVE changes ? */
934
-						if (t->val[i+2].type == NUMBER_ST) {
935
-							snprintf(buf, sizeof(buf)-1, "%ld", 
936
-										t->val[i+2].u.number);
937
-							/* fixup currently requires string pkg_malloced*/
938
-							t->val[i+2].u.string = pkg_malloc(strlen(buf)+1);
939
-							if (!t->val[i+2].u.string) {
940
-								LOG(L_CRIT, "ERROR: cannot translate NUMBER"
941
-											" to STRING\n");
942
-								ret = E_OUT_OF_MEM;
943
-								goto error;
944
-							}
945
-							strcpy(t->val[i+2].u.string, buf);
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);
950
-						}
951
-					}
952
-					for (i=0; i < t->val[1].u.number; i++) {
953
-						tmp_p = t->val[i+2].u.data;
954
-						ret = cmd->c.fixup(&t->val[i+2].u.data, i+1);
955
-						if (t->val[i+2].u.data != tmp_p)
956
-							t->val[i+2].type = MODFIXUP_ST;
925
+						ret = call_fixup(cmd->c.fixup, 0, 0);
957 926
 						if (ret < 0)
958 927
 							goto error;
959 928
 					}
960
-				} else if (cmd) { /* no fixup => RVE supported => optimize */
961 929
 					for (i=0; i < t->val[1].u.number; i++) {
962 930
 						if (t->val[i+2].type == RVE_ST) {
963 931
 							rve = t->val[i+2].u.data;
... ...
@@ -979,6 +947,13 @@ int fix_actions(struct action* a)
979 947
 								t->val[i+2].u.string = s.s;
980 948
 								/* len is not used for now */
981 949
 								t->val[i+2].u.str.len = s.len;
950
+								tmp_p = t->val[i+2].u.data;
951
+								ret = call_fixup(cmd->c.fixup,
952
+												&t->val[i+2].u.data, i+1);
953
+								if (t->val[i+2].u.data != tmp_p)
954
+									t->val[i+2].type = MODFIXUP_ST;
955
+								if (ret < 0)
956
+									goto error;
982 957
 							} else {
983 958
 								/* expression is not constant => fixup &
984 959
 								   optimize it */
... ...
@@ -990,9 +965,34 @@ int fix_actions(struct action* a)
990 965
 									goto error;
991 966
 								}
992 967
 							}
993
-						} /* if RVE_ST */
994
-					}
968
+						} else  if (t->val[i+2].type == STRING_ST) {
969
+							tmp_p = t->val[i+2].u.data;
970
+							ret = call_fixup(cmd->c.fixup,
971
+											&t->val[i+2].u.data, i+1);
972
+							if (t->val[i+2].u.data != tmp_p)
973
+								t->val[i+2].type = MODFIXUP_ST;
974
+							if (ret < 0)
975
+								goto error;
976
+						} else {
977
+							BUG("invalid module function param type %d\n",
978
+									t->val[i+2].type);
979
+							ret = E_BUG;
980
+							goto error;
981
+						}
982
+					} /* for */
983
+					/* here all the params are either STRING_ST
984
+					   (constant RVEs), MODFIXUP_ST (fixed up)
985
+					   or RVE_ST (non-ct RVEs) */
995 986
 					if (rve_param_no) { /* we have to fix the type */
987
+						if (cmd->c.fixup &&
988
+							!((unsigned long)cmd->c.fixup &
989
+								FIXUP_F_FPARAM_RVE)) {
990
+							BUG("non-ct RVEs (%d) in module function call"
991
+									"that does not support them (%s)\n",
992
+									rve_param_no, cmd->c.name);
993
+							ret = E_BUG;
994
+							goto error;
995
+						}
996 996
 						switch(t->type) {
997 997
 							case MODULE1_T:
998 998
 								t->type = MODULE1_RVE_T;
... ...
@@ -126,7 +126,8 @@ enum _operand_subtype{
126 126
 		SELECT_ST, PVAR_ST,
127 127
 		LVAL_ST,  RVE_ST,
128 128
 		RETCODE_ST, CASE_ST,
129
-		BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST, MATCH_CONDTABLE_ST
129
+		BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST, MATCH_CONDTABLE_ST,
130
+		FPARAM_DYN_ST /* temporary only */
130 131
 };
131 132
 
132 133
 typedef enum _expr_l_type expr_l_type;
... ...
@@ -1569,3 +1569,29 @@ int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param)
1569 1569
 	}
1570 1570
 	return -1;
1571 1571
 }
1572
+
1573
+
1574
+
1575
+/** returns true if a fixup is a fparam_t* one.
1576
+ * Used to automatically detect fparam fixups that can be used with non
1577
+ * contant RVEs.
1578
+ * @param f - function pointer
1579
+ * @return 1 for fparam fixups, 0 for others.
1580
+ */
1581
+int is_fparam_rve_fixup(fixup_function f)
1582
+{
1583
+	if (f == fixup_var_str_12 ||
1584
+		f == fixup_var_str_1 ||
1585
+		f == fixup_var_str_2 ||
1586
+		f == fixup_var_int_12 ||
1587
+		f == fixup_var_int_1 ||
1588
+		f == fixup_var_int_2 ||
1589
+		f == fixup_int_12 ||
1590
+		f == fixup_int_1 ||
1591
+		f == fixup_int_2 ||
1592
+		f == fixup_str_12 ||
1593
+		f == fixup_str_1 ||
1594
+		f == fixup_str_2)
1595
+		return 1;
1596
+	return 0;
1597
+}
... ...
@@ -149,6 +149,17 @@ typedef int (*param_func_t)( modparam_t type, void* val);
149 149
 #define VAR_PARAM_NO  -128  /* function has variable number of parameters
150 150
 							   (see cmd_function_var for the prototype) */
151 151
 
152
+/* special fixup function flags.
153
+ * They are kept in the first 2 bits inside the pointer
154
+ */
155
+#define FIXUP_F_FPARAM_RVE (unsigned long)1 /* fparam fixup, rve ready */
156
+#define FIXUP_F_RESERVED (unsigned long)2  /* not used for now */
157
+#define FIXUP_MASK (~((unsigned long)3)) /* mask for obtainin the pointer val*/
158
+
159
+#define call_fixup(fixup, param, param_no) \
160
+	(((long)(fixup) & FIXUP_MASK)? \
161
+		(((fixup_function)((long)(fixup) & FIXUP_MASK))(param, param_no)):0)
162
+
152 163
 /* Macros - used as rank in child_init function */
153 164
 #define PROC_MAIN      0  /* Main ser process */
154 165
 #define PROC_TIMER    -1  /* Timer attendant process */
... ...
@@ -524,4 +535,6 @@ int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param);
524 535
 int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param);
525 536
 
526 537
 
538
+int is_fparam_rve_fixup(fixup_function f);
539
+
527 540
 #endif /* sr_module_h */