Browse code

script engine: while() support

- support the same while() loops as kamailio (the only difference
being that max_while_loops can be changed at runtime):
while(<int expr>) { .... } with break exiting the while.

Andrei Pelinescu-Onciul authored on 10/02/2009 21:21:12
Showing 6 changed files
... ...
@@ -112,9 +112,10 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
112 112
 	struct sip_uri *u;
113 113
 	unsigned short port;
114 114
 	str* dst_host;
115
-	int i;
115
+	int i, flags;
116 116
 	struct switch_cond_table* sct;
117 117
 	struct switch_jmp_table*  sjt;
118
+	struct rval_expr* rve;
118 119
 
119 120
 
120 121
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
... ...
@@ -906,6 +907,30 @@ sw_jt_def:
906 907
 											   returns passthrough */
907 908
 			}
908 909
 			break;
910
+		case WHILE_T:
911
+			i=0;
912
+			flags=0;
913
+			rve=(struct rval_expr*)a->val[0].u.data;
914
+			ret=1;
915
+			while(!(flags & BREAK_R_F) && 
916
+					(rval_expr_eval_int(h, msg, &v, rve) == 0) && v){
917
+				i++;
918
+				if (unlikely(i > cfg_get(core, core_cfg, max_while_loops))){
919
+					LOG(L_ERR, "ERROR: runaway while (%d, %d): more then"
920
+								" %d loops\n", 
921
+								rve->fpos.s_line, rve->fpos.s_col,
922
+								cfg_get(core, core_cfg, max_while_loops));
923
+					ret=-1;
924
+					break;
925
+				}
926
+				if (likely(a->val[1].u.data)){
927
+					ret=run_actions(h, (struct action*)a->val[1].u.data, msg);
928
+					flags|=h->run_flags;
929
+					h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
930
+												   returns passthrough */
931
+				}
932
+			}
933
+			break;
909 934
 		case FORCE_RPORT_T:
910 935
 			msg->msg_flags|=FL_FORCE_RPORT;
911 936
 			ret=1; /* continue processing */
... ...
@@ -88,6 +88,7 @@ struct cfg_group_core default_core_cfg = {
88 88
 #ifdef SHM_MEM
89 89
 	0, /* mem_dump_shm */
90 90
 #endif
91
+	DEFAULT_MAX_WHILE_LOOPS, /* max_while_loops */
91 92
 };
92 93
 
93 94
 void	*core_cfg = &default_core_cfg;
... ...
@@ -177,5 +178,7 @@ cfg_def_t core_cfg_def[] = {
177 178
 	{"mem_dump_shm",	CFG_VAR_INT,	0, 0, mem_dump_shm_fixup, 0,
178 179
 		"dump shared memory status"},
179 180
 #endif
181
+	{"max_while_loops",	CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
182
+		"maximum iterations allowed for a while loop" },
180 183
 	{0, 0, 0, 0, 0, 0}
181 184
 };
... ...
@@ -85,6 +85,7 @@ struct cfg_group_core {
85 85
 #ifdef SHM_MEM
86 86
 	int mem_dump_shm;
87 87
 #endif
88
+	int max_while_loops;
88 89
 };
89 90
 
90 91
 extern struct cfg_group_core default_core_cfg;
... ...
@@ -208,4 +208,7 @@
208 208
 
209 209
 #define DEFAULT_DID "_default"
210 210
 
211
+/*  maximum allowed iterations for a while (to catch runaways) */
212
+#define DEFAULT_MAX_WHILE_LOOPS 100
213
+
211 214
 #endif
... ...
@@ -623,6 +623,10 @@ int fix_actions(struct action* a)
623 623
 	struct ip_addr ip;
624 624
 	struct socket_info* si;
625 625
 	struct lvalue* lval;
626
+	struct rval_expr* rve;
627
+	struct rval_expr* err_rve;
628
+	enum rval_type rve_type, err_type, expected_type;
629
+
626 630
 	
627 631
 	char buf[30]; /* tmp buffer needed for module param fixups */
628 632
 
... ...
@@ -701,12 +705,12 @@ int fix_actions(struct action* a)
701 705
 			case SWITCH_T:
702 706
 				if (t->val[0].type!=RVE_ST){
703 707
 					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
704
-								"%d for if (should be expr)\n",
708
+								"%d for switch() (should be expr)\n",
705 709
 								t->val[0].type);
706 710
 					return E_BUG;
707 711
 				}else if (t->val[1].type!=CASE_ST){
708 712
 					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
709
-								"%d for switch(...){...}(should be action)\n",
713
+								"%d for switch(...){...}(should be case)\n",
710 714
 								t->val[1].type);
711 715
 					return E_BUG;
712 716
 				}
... ...
@@ -721,6 +725,55 @@ int fix_actions(struct action* a)
721 725
 				if ((ret=fix_switch(t))<0)
722 726
 					return ret;
723 727
 				break;
728
+			case WHILE_T:
729
+				if (t->val[0].type!=RVE_ST){
730
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
731
+								"%d for while() (should be expr)\n",
732
+								t->val[0].type);
733
+					return E_BUG;
734
+				}else if (t->val[1].type!=ACTIONS_ST){
735
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
736
+								"%d for while(...){...}(should be action)\n",
737
+								t->val[1].type);
738
+					return E_BUG;
739
+				}
740
+				rve=(struct rval_expr*)t->val[0].u.data;
741
+				if (rve){
742
+					err_rve=0;
743
+					if (!rve_check_type(&rve_type, rve, &err_rve,
744
+											&err_type, &expected_type)){
745
+						if (err_rve)
746
+							LOG(L_ERR, "fix_actions: invalid expression "
747
+									"(%d,%d): subexpression (%d,%d) has type"
748
+									" %s,  but %s is expected\n",
749
+									rve->fpos.s_line, rve->fpos.s_col,
750
+									err_rve->fpos.s_line, err_rve->fpos.s_col,
751
+									rval_type_name(err_type),
752
+									rval_type_name(expected_type) );
753
+						else
754
+							LOG(L_ERR, "fix_actions: invalid expression "
755
+									"(%d,%d): type mismatch?",
756
+									rve->fpos.s_line, rve->fpos.s_col);
757
+						return E_UNSPEC;
758
+					}
759
+					if (rve_type!=RV_INT && rve_type!=RV_NONE){
760
+						LOG(L_ERR, "fix_actions: invalid expression (%d,%d):"
761
+								" bad type, integer expected\n",
762
+								rve->fpos.s_line, rve->fpos.s_col);
763
+						return E_UNSPEC;
764
+					}
765
+					if ((ret=fix_rval_expr((void**)&rve))<0)
766
+						return ret;
767
+				}else{
768
+					LOG(L_CRIT, "BUG: fix_actions: null while()"
769
+							" expression\n");
770
+					return E_BUG;
771
+				}
772
+				if ( t->val[1].u.data && 
773
+					((ret= fix_actions((struct action*)t->val[1].u.data))<0)){
774
+					return ret;
775
+				}
776
+				break;
724 777
 			case ASSIGN_T:
725 778
 			case ADD_T:
726 779
 				if (t->val[0].type !=LVAL_ST) {
... ...
@@ -71,7 +71,7 @@ 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 73
 		IF_T, SWITCH_T /* only until fixup*/,
74
-		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T,
74
+		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, WHILE_T,
75 75
 		MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
76 76
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
77 77
 		AVPFLAG_OPER_T,