Browse code

script: variable number of params for functions

- support for true variable number of parameters module functions
( f(sip_msg, param_no, param_array[]) )
- support for functions with 3-6 parameters using kamailio extended
interface. The implementation is however different: while in kamailio
all module functions where called with 6 parameters (even if they
declared only 2), this version will generate different function
calls (small performance benefit by avoiding unneeded stack pushes
and register saving for the most common 2 parameter functions and
works also with other calling conventions).
For performance reasons, a separate script engine command is now
generated for each type of function: module functions calls with 0-2
parameters (MODULE_T), 3 (MODULE3_T), 4 (MODULE4_T), 5 (MODULE5_T)
and 6 (MODULE6_T) parameters.
In case of name conflicts with variable param. number function,
it's undefined which actual function will get executed (it will be
the "first" one, but the order depends on the module loading order
a.s.o.).

Andrei Pelinescu-Onciul authored on 18/11/2008 23:10:46
Showing 6 changed files
... ...
@@ -46,6 +46,7 @@
46 46
  *              (andrei)
47 47
  *  2007-06-14  run_actions & do_action need a ctx or handle now, no more 
48 48
  *               static vars (andrei)
49
+ *  2008-11-18  support for variable parameter module functions (andrei)
49 50
  */
50 51
 
51 52
 
... ...
@@ -101,6 +102,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
101 101
 	struct dest_info dst;
102 102
 	char* tmp;
103 103
 	char *new_uri, *end, *crt;
104
+	void* f;
104 105
 	int len;
105 106
 	int user;
106 107
 	struct sip_uri uri, next_hop;
... ...
@@ -717,11 +719,89 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
717 717
 			break;
718 718
 		case MODULE_T:
719 719
 			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
720
-					((union cmd_export_u*)a->val[0].u.data)->c.function){
721
-				ret=((union cmd_export_u*)a->val[0].u.data)->c.function(msg,
722
-					(char*)a->val[2].u.data,
723
-					(char*)a->val[3].u.data
724
-				);
720
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
721
+				ret=((cmd_function)f)(msg,
722
+										(char*)a->val[2].u.data,
723
+										(char*)a->val[3].u.data
724
+									);
725
+				if (ret==0) h->run_flags|=EXIT_R_F;
726
+				h->last_retcode=ret;
727
+			} else {
728
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
729
+			}
730
+			break;
731
+		/* instead of using the parameter number, we use different names
732
+		 * for calls to functions with 3, 4, 5, 6 or variable number of
733
+		 * parameters due to performance reasons */
734
+		case MODULE3_T:
735
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
736
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
737
+				ret=((cmd_function3)f)(msg,
738
+										(char*)a->val[2].u.data,
739
+										(char*)a->val[3].u.data,
740
+										(char*)a->val[4].u.data
741
+									);
742
+				if (ret==0) h->run_flags|=EXIT_R_F;
743
+				h->last_retcode=ret;
744
+			} else {
745
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
746
+			}
747
+			break;
748
+		case MODULE4_T:
749
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
750
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
751
+				ret=((cmd_function4)f)(msg,
752
+										(char*)a->val[2].u.data,
753
+										(char*)a->val[3].u.data,
754
+										(char*)a->val[4].u.data,
755
+										(char*)a->val[5].u.data
756
+									);
757
+				if (ret==0) h->run_flags|=EXIT_R_F;
758
+				h->last_retcode=ret;
759
+			} else {
760
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
761
+			}
762
+			break;
763
+		case MODULE5_T:
764
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
765
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
766
+				ret=((cmd_function5)f)(msg,
767
+										(char*)a->val[2].u.data,
768
+										(char*)a->val[3].u.data,
769
+										(char*)a->val[4].u.data,
770
+										(char*)a->val[5].u.data,
771
+										(char*)a->val[6].u.data
772
+									);
773
+				if (ret==0) h->run_flags|=EXIT_R_F;
774
+				h->last_retcode=ret;
775
+			} else {
776
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
777
+			}
778
+			break;
779
+		case MODULE6_T:
780
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
781
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
782
+				ret=((cmd_function6)f)(msg,
783
+										(char*)a->val[2].u.data,
784
+										(char*)a->val[3].u.data,
785
+										(char*)a->val[4].u.data,
786
+										(char*)a->val[5].u.data,
787
+										(char*)a->val[6].u.data,
788
+										(char*)a->val[7].u.data
789
+									);
790
+				if (ret==0) h->run_flags|=EXIT_R_F;
791
+				h->last_retcode=ret;
792
+			} else {
793
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
794
+			}
795
+			break;
796
+		case MODULEX_T:
797
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
798
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
799
+				ret=((cmd_function_var)f)(msg,
800
+											a->val[1].u.number,
801
+											&a->val[2]
802
+										);
725 803
 				if (ret==0) h->run_flags|=EXIT_R_F;
726 804
 				h->last_retcode=ret;
727 805
 			} else {
... ...
@@ -88,6 +88,7 @@
88 88
  * 2007-11-28  added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
89 89
  *              LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
90 90
  * 2008-01-24  added cfg_var definition (Miklos)
91
+ * 2008-11-18  support for variable parameter module functions (andrei)
91 92
 */
92 93
 
93 94
 %{
... ...
@@ -2359,7 +2360,8 @@ cmd:
2359 2359
 		$$=0; yyerror("bad argument, [proto:]host[:port] expected");
2360 2360
 	}
2361 2361
 	| FORCE_SEND_SOCKET error {$$=0; yyerror("missing '(' or ')' ?"); }
2362
-	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST, 0); } LPAREN func_params RPAREN	{
2362
+	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST,
2363
+			0); } LPAREN func_params RPAREN	{
2363 2364
 		mod_func_action->val[0].u.data = 
2364 2365
 			find_export_record($1, mod_func_action->val[1].u.number, rt,
2365 2366
 								&u_tmp);
... ...
@@ -2372,6 +2374,33 @@ cmd:
2372 2372
 			}
2373 2373
 			pkg_free(mod_func_action);
2374 2374
 			mod_func_action=0;
2375
+		}else{
2376
+			switch( ((union cmd_export_u*)
2377
+						mod_func_action->val[0].u.data)->c.param_no){
2378
+				case 0:
2379
+				case 1:
2380
+				case 2:
2381
+					/* MODULE_T used for 0-2 params */
2382
+					break;
2383
+				case 3:
2384
+					mod_func_action->type=MODULE3_T;
2385
+					break;
2386
+				case 4:
2387
+					mod_func_action->type=MODULE4_T;
2388
+					break;
2389
+				case 5:
2390
+					mod_func_action->type=MODULE5_T;
2391
+					break;
2392
+				case 6:
2393
+					mod_func_action->type=MODULE6_T;
2394
+					break;
2395
+				case VAR_PARAM_NO:
2396
+					mod_func_action->type=MODULEX_T;
2397
+					break;
2398
+				default:
2399
+					yyerror("too many parameters for function\n");
2400
+					break;
2401
+			}
2375 2402
 		}
2376 2403
 		$$ = mod_func_action;
2377 2404
 	}
... ...
@@ -2385,8 +2414,10 @@ func_params:
2385 2385
 func_param:
2386 2386
         NUMBER {
2387 2387
 		if (mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
2388
-			mod_func_action->val[mod_func_action->val[1].u.number+2].type = NUMBER_ST;
2389
-			mod_func_action->val[mod_func_action->val[1].u.number+2].u.number = $1;
2388
+			mod_func_action->val[mod_func_action->val[1].u.number+2].type =
2389
+				NUMBER_ST;
2390
+			mod_func_action->val[mod_func_action->val[1].u.number+2].u.number =
2391
+				$1;
2390 2392
 			mod_func_action->val[1].u.number++;
2391 2393
 		} else {
2392 2394
 			yyerror("Too many arguments\n");
... ...
@@ -503,6 +503,11 @@ static int fix_actions(struct action* a)
503 503
 				break;
504 504
 
505 505
 			case MODULE_T:
506
+			case MODULE3_T:
507
+			case MODULE4_T:
508
+			case MODULE5_T:
509
+			case MODULE6_T:
510
+			case MODULEX_T:
506 511
 				cmd = t->val[0].u.data;
507 512
 				if (cmd && cmd->c.fixup) {
508 513
 					int i;
... ...
@@ -350,6 +350,11 @@ void print_action(struct action* t)
350 350
 			DBG("if (");
351 351
 			break;
352 352
 		case MODULE_T:
353
+		case MODULE3_T:
354
+		case MODULE4_T:
355
+		case MODULE5_T:
356
+		case MODULE6_T:
357
+		case MODULEX_T:
353 358
 			DBG(" external_module_call(");
354 359
 			break;
355 360
 		case FORCE_RPORT_T:
... ...
@@ -70,7 +70,7 @@ enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O,
70 70
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
71 71
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T,
72 72
 		SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
73
-		IF_T, MODULE_T,
73
+		IF_T, MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
74 74
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
75 75
 		AVPFLAG_OPER_T,
76 76
 		LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T,
... ...
@@ -133,13 +133,17 @@ typedef struct {
133 133
 	} u;
134 134
 } action_u_t;
135 135
 
136
-#define MAX_ACTIONS 4
136
+/* maximum internal array/params
137
+ * for module function calls val[0] and val[1] store a pointer to the
138
+ * function and the number of params, the rest are the function params 
139
+ */
140
+#define MAX_ACTIONS (2+6)
137 141
 
138 142
 struct action{
139 143
 	int type;  /* forward, drop, log, send ...*/
140 144
 	int count;
141
-	action_u_t val[MAX_ACTIONS];
142 145
 	struct action* next;
146
+	action_u_t val[MAX_ACTIONS];
143 147
 };
144 148
 
145 149
 struct expr* mk_exp(int op, struct expr* left, struct expr* right);
... ...
@@ -353,7 +353,8 @@ union cmd_export_u* find_mod_export_record(char* mod, char* name,
353 353
 			for(i=0, cmd=(void*)&t->exports->VER.cmds[0]; cmd->VER.name; \
354 354
 					i++, cmd=(void*)&t->exports->VER.cmds[i]){\
355 355
 				if((strcmp(name, cmd->VER.name)==0)&& \
356
-					(cmd->VER.param_no==param_no) &&  \
356
+					((cmd->VER.param_no==param_no) || \
357
+					 (cmd->VER.param_no==VAR_PARAM_NO)) && \
357 358
 					((cmd->VER.flags & flags) == flags) \
358 359
 				){ \
359 360
 					DBG("find_export_record: found <%s> in module %s [%s]\n", \