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 906
 											   returns passthrough */
907 907
 			}
908 908
 			break;
909
+		case WHILE_T:
910
+			i=0;
911
+			flags=0;
912
+			rve=(struct rval_expr*)a->val[0].u.data;
913
+			ret=1;
914
+			while(!(flags & BREAK_R_F) && 
915
+					(rval_expr_eval_int(h, msg, &v, rve) == 0) && v){
916
+				i++;
917
+				if (unlikely(i > cfg_get(core, core_cfg, max_while_loops))){
918
+					LOG(L_ERR, "ERROR: runaway while (%d, %d): more then"
919
+								" %d loops\n", 
920
+								rve->fpos.s_line, rve->fpos.s_col,
921
+								cfg_get(core, core_cfg, max_while_loops));
922
+					ret=-1;
923
+					break;
924
+				}
925
+				if (likely(a->val[1].u.data)){
926
+					ret=run_actions(h, (struct action*)a->val[1].u.data, msg);
927
+					flags|=h->run_flags;
928
+					h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
929
+												   returns passthrough */
930
+				}
931
+			}
932
+			break;
909 933
 		case FORCE_RPORT_T:
910 934
 			msg->msg_flags|=FL_FORCE_RPORT;
911 935
 			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 177
 	{"mem_dump_shm",	CFG_VAR_INT,	0, 0, mem_dump_shm_fixup, 0,
178 178
 		"dump shared memory status"},
179 179
 #endif
180
+	{"max_while_loops",	CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
181
+		"maximum iterations allowed for a while loop" },
180 182
 	{0, 0, 0, 0, 0, 0}
181 183
 };
... ...
@@ -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 701
 			case SWITCH_T:
702 702
 				if (t->val[0].type!=RVE_ST){
703 703
 					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
704
-								"%d for if (should be expr)\n",
704
+								"%d for switch() (should be expr)\n",
705 705
 								t->val[0].type);
706 706
 					return E_BUG;
707 707
 				}else if (t->val[1].type!=CASE_ST){
708 708
 					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
709
-								"%d for switch(...){...}(should be action)\n",
709
+								"%d for switch(...){...}(should be case)\n",
710 710
 								t->val[1].type);
711 711
 					return E_BUG;
712 712
 				}
... ...
@@ -721,6 +725,55 @@ int fix_actions(struct action* a)
721 721
 				if ((ret=fix_switch(t))<0)
722 722
 					return ret;
723 723
 				break;
724
+			case WHILE_T:
725
+				if (t->val[0].type!=RVE_ST){
726
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
727
+								"%d for while() (should be expr)\n",
728
+								t->val[0].type);
729
+					return E_BUG;
730
+				}else if (t->val[1].type!=ACTIONS_ST){
731
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
732
+								"%d for while(...){...}(should be action)\n",
733
+								t->val[1].type);
734
+					return E_BUG;
735
+				}
736
+				rve=(struct rval_expr*)t->val[0].u.data;
737
+				if (rve){
738
+					err_rve=0;
739
+					if (!rve_check_type(&rve_type, rve, &err_rve,
740
+											&err_type, &expected_type)){
741
+						if (err_rve)
742
+							LOG(L_ERR, "fix_actions: invalid expression "
743
+									"(%d,%d): subexpression (%d,%d) has type"
744
+									" %s,  but %s is expected\n",
745
+									rve->fpos.s_line, rve->fpos.s_col,
746
+									err_rve->fpos.s_line, err_rve->fpos.s_col,
747
+									rval_type_name(err_type),
748
+									rval_type_name(expected_type) );
749
+						else
750
+							LOG(L_ERR, "fix_actions: invalid expression "
751
+									"(%d,%d): type mismatch?",
752
+									rve->fpos.s_line, rve->fpos.s_col);
753
+						return E_UNSPEC;
754
+					}
755
+					if (rve_type!=RV_INT && rve_type!=RV_NONE){
756
+						LOG(L_ERR, "fix_actions: invalid expression (%d,%d):"
757
+								" bad type, integer expected\n",
758
+								rve->fpos.s_line, rve->fpos.s_col);
759
+						return E_UNSPEC;
760
+					}
761
+					if ((ret=fix_rval_expr((void**)&rve))<0)
762
+						return ret;
763
+				}else{
764
+					LOG(L_CRIT, "BUG: fix_actions: null while()"
765
+							" expression\n");
766
+					return E_BUG;
767
+				}
768
+				if ( t->val[1].u.data && 
769
+					((ret= fix_actions((struct action*)t->val[1].u.data))<0)){
770
+					return ret;
771
+				}
772
+				break;
724 773
 			case ASSIGN_T:
725 774
 			case ADD_T:
726 775
 				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,