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 133
  */
134 134
 #define MODF_RVE_PARAM_FREE(src, dst) \
135 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; \
136
+			if ((src)[i+2].type == RVE_ST && (dst)[i+2].u.data) { \
137
+				if ((dst)[i+2].type == FPARAM_DYN_ST) {\
138
+					/* frees also orig. dst.u.data */ \
139
+					fparam_free_contents((dst)[i+2].u.data); \
140
+					/* the fparam struct. (dst.u.data) is freed below */ \
141
+				} \
142
+				pkg_free((dst)[i+2].u.data); \
143
+				(dst)[i+2].u.data = 0; \
139 144
 			} \
140 145
 		}
141 146
 
... ...
@@ -147,7 +154,7 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
147 147
  * WARNING: dst must be cleaned when done, use MODULE_RVE_PARAM_FREE()
148 148
  * Side-effects: clobbers i (int), s (str), rv (rvalue*), might jump to error.
149 149
  */
150
-#define MODF_RVE_PARAM_CONVERT(h, msg, src, dst) \
150
+#define MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst) \
151 151
 	do { \
152 152
 		(dst)[1]=(src)[1]; \
153 153
 		for (i=0; i < (src)[1].u.number; i++) { \
... ...
@@ -165,6 +172,12 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
165 165
 				(dst)[i+2].u.string = s.s; \
166 166
 				(dst)[i+2].u.str.len = s.len; \
167 167
 				rval_destroy(rv); \
168
+				if ((cmd)->c.fixup && \
169
+						(long)(cmd)->c.fixup & FIXUP_F_FPARAM_RVE) { \
170
+					call_fixup((cmd)->c.fixup, &(dst)[i+2].u.data, i+1); \
171
+					if ((dst)[i+2].u.data != s.s) \
172
+						(dst)[i+2].type = FPARAM_DYN_ST; \
173
+				} \
168 174
 			} else \
169 175
 				(dst)[i+2]=(src)[i+2]; \
170 176
 		} \
... ...
@@ -180,22 +193,22 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
180 180
  * @param src - source action_u_t array (e.g. action->val)
181 181
  * @param params... - variable list of parameters, passed to the module
182 182
  *               function
183
- * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), f,
183
+ * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), cmd,
184 184
  *               might jump to error.
185 185
  *
186 186
  */
187 187
 #ifdef __SUNPRO_C
188 188
 #define MODF_CALL(f_type, h, msg, src, ...) \
189 189
 	do { \
190
-		f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
191
-		ret=((f_type)f)((msg), __VAR_ARGS__); \
190
+		cmd=(src)[0].u.data; \
191
+		ret=((f_type)cmd->c.function)((msg), __VAR_ARGS__); \
192 192
 		MODF_HANDLE_RETCODE(h, ret); \
193 193
 	} while (0)
194 194
 #else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
195 195
 #define MODF_CALL(f_type, h, msg, src, params...) \
196 196
 	do { \
197
-		f=((union cmd_export_u*)(src)[0].u.data)->c.function; \
198
-		ret=((f_type)f)((msg), ## params ); \
197
+		cmd=(src)[0].u.data; \
198
+		ret=((f_type)cmd->c.function)((msg), ## params ); \
199 199
 		MODF_HANDLE_RETCODE(h, ret); \
200 200
 	} while (0)
201 201
 #endif /* __SUNPRO_C */
... ...
@@ -220,21 +233,21 @@ struct onsend_info* p_onsend=0; /* onsend route send info */
220 220
 #ifdef __SUNPRO_C
221 221
 #define MODF_RVE_CALL(f_type, h, msg, src, dst, ...) \
222 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__); \
223
+		cmd=(src)[0].u.data; \
224
+		MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst); \
225
+		ret=((f_type)cmd->c.function)((msg), __VAR_ARGS__); \
226 226
 		MODF_HANDLE_RETCODE(h, ret); \
227
-		/* free strings allocated by us */ \
227
+		/* free strings allocated by us or fixups */ \
228 228
 		MODF_RVE_PARAM_FREE(src, dst); \
229 229
 	} while (0)
230 230
 #else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
231 231
 #define MODF_RVE_CALL(f_type, h, msg, src, dst, params...) \
232 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 ); \
233
+		cmd=(src)[0].u.data; \
234
+		MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst); \
235
+		ret=((f_type)cmd->c.function)((msg), ## params ); \
236 236
 		MODF_HANDLE_RETCODE(h, ret); \
237
-		/* free strings allocated by us */ \
237
+		/* free strings allocated by us or fixups */ \
238 238
 		MODF_RVE_PARAM_FREE(src, dst); \
239 239
 	} while (0)
240 240
 #endif /* __SUNPRO_C */
... ...
@@ -250,7 +263,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
250 250
 	struct dest_info dst;
251 251
 	char* tmp;
252 252
 	char *new_uri, *end, *crt;
253
-	void* f;
253
+	union cmd_export_u* cmd;
254 254
 	int len;
255 255
 	int user;
256 256
 	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 644
 	struct rvalue* rv;
645 645
 	int rve_param_no;
646 646
 
647
-	
648
-	char buf[30]; /* tmp buffer needed for module param fixups */
649
-
650 647
 	if (a==0){
651 648
 		LOG(L_CRIT,"BUG: fix_actions: null pointer\n");
652 649
 		return E_BUG;
... ...
@@ -920,44 +919,13 @@ int fix_actions(struct action* a)
920 920
 			case MODULEX_T:
921 921
 				cmd = t->val[0].u.data;
922 922
 				rve_param_no = 0;
923
-				if (cmd && cmd->c.fixup) {
923
+				if (cmd) {
924 924
 					DBG("fixing %s()\n", cmd->c.name);
925 925
 					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;
926
+						ret = call_fixup(cmd->c.fixup, 0, 0);
957 927
 						if (ret < 0)
958 928
 							goto error;
959 929
 					}
960
-				} else if (cmd) { /* no fixup => RVE supported => optimize */
961 930
 					for (i=0; i < t->val[1].u.number; i++) {
962 931
 						if (t->val[i+2].type == RVE_ST) {
963 932
 							rve = t->val[i+2].u.data;
... ...
@@ -979,6 +947,13 @@ int fix_actions(struct action* a)
979 979
 								t->val[i+2].u.string = s.s;
980 980
 								/* len is not used for now */
981 981
 								t->val[i+2].u.str.len = s.len;
982
+								tmp_p = t->val[i+2].u.data;
983
+								ret = call_fixup(cmd->c.fixup,
984
+												&t->val[i+2].u.data, i+1);
985
+								if (t->val[i+2].u.data != tmp_p)
986
+									t->val[i+2].type = MODFIXUP_ST;
987
+								if (ret < 0)
988
+									goto error;
982 989
 							} else {
983 990
 								/* expression is not constant => fixup &
984 991
 								   optimize it */
... ...
@@ -990,9 +965,34 @@ int fix_actions(struct action* a)
990 990
 									goto error;
991 991
 								}
992 992
 							}
993
-						} /* if RVE_ST */
994
-					}
993
+						} else  if (t->val[i+2].type == STRING_ST) {
994
+							tmp_p = t->val[i+2].u.data;
995
+							ret = call_fixup(cmd->c.fixup,
996
+											&t->val[i+2].u.data, i+1);
997
+							if (t->val[i+2].u.data != tmp_p)
998
+								t->val[i+2].type = MODFIXUP_ST;
999
+							if (ret < 0)
1000
+								goto error;
1001
+						} else {
1002
+							BUG("invalid module function param type %d\n",
1003
+									t->val[i+2].type);
1004
+							ret = E_BUG;
1005
+							goto error;
1006
+						}
1007
+					} /* for */
1008
+					/* here all the params are either STRING_ST
1009
+					   (constant RVEs), MODFIXUP_ST (fixed up)
1010
+					   or RVE_ST (non-ct RVEs) */
995 1011
 					if (rve_param_no) { /* we have to fix the type */
1012
+						if (cmd->c.fixup &&
1013
+							!((unsigned long)cmd->c.fixup &
1014
+								FIXUP_F_FPARAM_RVE)) {
1015
+							BUG("non-ct RVEs (%d) in module function call"
1016
+									"that does not support them (%s)\n",
1017
+									rve_param_no, cmd->c.name);
1018
+							ret = E_BUG;
1019
+							goto error;
1020
+						}
996 1021
 						switch(t->type) {
997 1022
 							case MODULE1_T:
998 1023
 								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 524
 int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param);
525 525
 
526 526
 
527
+int is_fparam_rve_fixup(fixup_function f);
528
+
527 529
 #endif /* sr_module_h */