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 102
 	struct dest_info dst;
102 103
 	char* tmp;
103 104
 	char *new_uri, *end, *crt;
105
+	void* f;
104 106
 	int len;
105 107
 	int user;
106 108
 	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 719
 			break;
718 720
 		case MODULE_T:
719 721
 			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
-				);
722
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
723
+				ret=((cmd_function)f)(msg,
724
+										(char*)a->val[2].u.data,
725
+										(char*)a->val[3].u.data
726
+									);
727
+				if (ret==0) h->run_flags|=EXIT_R_F;
728
+				h->last_retcode=ret;
729
+			} else {
730
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
731
+			}
732
+			break;
733
+		/* instead of using the parameter number, we use different names
734
+		 * for calls to functions with 3, 4, 5, 6 or variable number of
735
+		 * parameters due to performance reasons */
736
+		case MODULE3_T:
737
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
738
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
739
+				ret=((cmd_function3)f)(msg,
740
+										(char*)a->val[2].u.data,
741
+										(char*)a->val[3].u.data,
742
+										(char*)a->val[4].u.data
743
+									);
744
+				if (ret==0) h->run_flags|=EXIT_R_F;
745
+				h->last_retcode=ret;
746
+			} else {
747
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
748
+			}
749
+			break;
750
+		case MODULE4_T:
751
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
752
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
753
+				ret=((cmd_function4)f)(msg,
754
+										(char*)a->val[2].u.data,
755
+										(char*)a->val[3].u.data,
756
+										(char*)a->val[4].u.data,
757
+										(char*)a->val[5].u.data
758
+									);
759
+				if (ret==0) h->run_flags|=EXIT_R_F;
760
+				h->last_retcode=ret;
761
+			} else {
762
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
763
+			}
764
+			break;
765
+		case MODULE5_T:
766
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
767
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
768
+				ret=((cmd_function5)f)(msg,
769
+										(char*)a->val[2].u.data,
770
+										(char*)a->val[3].u.data,
771
+										(char*)a->val[4].u.data,
772
+										(char*)a->val[5].u.data,
773
+										(char*)a->val[6].u.data
774
+									);
775
+				if (ret==0) h->run_flags|=EXIT_R_F;
776
+				h->last_retcode=ret;
777
+			} else {
778
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
779
+			}
780
+			break;
781
+		case MODULE6_T:
782
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
783
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
784
+				ret=((cmd_function6)f)(msg,
785
+										(char*)a->val[2].u.data,
786
+										(char*)a->val[3].u.data,
787
+										(char*)a->val[4].u.data,
788
+										(char*)a->val[5].u.data,
789
+										(char*)a->val[6].u.data,
790
+										(char*)a->val[7].u.data
791
+									);
792
+				if (ret==0) h->run_flags|=EXIT_R_F;
793
+				h->last_retcode=ret;
794
+			} else {
795
+				LOG(L_CRIT,"BUG: do_action: bad module call\n");
796
+			}
797
+			break;
798
+		case MODULEX_T:
799
+			if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
800
+					(f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
801
+				ret=((cmd_function_var)f)(msg,
802
+											a->val[1].u.number,
803
+											&a->val[2]
804
+										);
725 805
 				if (ret==0) h->run_flags|=EXIT_R_F;
726 806
 				h->last_retcode=ret;
727 807
 			} 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 2360
 		$$=0; yyerror("bad argument, [proto:]host[:port] expected");
2360 2361
 	}
2361 2362
 	| 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	{
2363
+	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST,
2364
+			0); } LPAREN func_params RPAREN	{
2363 2365
 		mod_func_action->val[0].u.data = 
2364 2366
 			find_export_record($1, mod_func_action->val[1].u.number, rt,
2365 2367
 								&u_tmp);
... ...
@@ -2372,6 +2374,33 @@ cmd:
2372 2374
 			}
2373 2375
 			pkg_free(mod_func_action);
2374 2376
 			mod_func_action=0;
2377
+		}else{
2378
+			switch( ((union cmd_export_u*)
2379
+						mod_func_action->val[0].u.data)->c.param_no){
2380
+				case 0:
2381
+				case 1:
2382
+				case 2:
2383
+					/* MODULE_T used for 0-2 params */
2384
+					break;
2385
+				case 3:
2386
+					mod_func_action->type=MODULE3_T;
2387
+					break;
2388
+				case 4:
2389
+					mod_func_action->type=MODULE4_T;
2390
+					break;
2391
+				case 5:
2392
+					mod_func_action->type=MODULE5_T;
2393
+					break;
2394
+				case 6:
2395
+					mod_func_action->type=MODULE6_T;
2396
+					break;
2397
+				case VAR_PARAM_NO:
2398
+					mod_func_action->type=MODULEX_T;
2399
+					break;
2400
+				default:
2401
+					yyerror("too many parameters for function\n");
2402
+					break;
2403
+			}
2375 2404
 		}
2376 2405
 		$$ = mod_func_action;
2377 2406
 	}
... ...
@@ -2385,8 +2414,10 @@ func_params:
2385 2414
 func_param:
2386 2415
         NUMBER {
2387 2416
 		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;
2417
+			mod_func_action->val[mod_func_action->val[1].u.number+2].type =
2418
+				NUMBER_ST;
2419
+			mod_func_action->val[mod_func_action->val[1].u.number+2].u.number =
2420
+				$1;
2390 2421
 			mod_func_action->val[1].u.number++;
2391 2422
 		} else {
2392 2423
 			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", \