[SR-Dev] git:andrei/switch: script engine: while() support

Andrei Pelinescu-Onciul andrei at iptel.org
Tue Feb 10 22:39:30 CET 2009


Module: sip-router
Branch: andrei/switch
Commit: dfda974cfb1c073fb751f74fab18a66f4bb341ec
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=dfda974cfb1c073fb751f74fab18a66f4bb341ec

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at iptel.org>
Date:   Tue Feb 10 22:21:12 2009 +0100

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.

---

 action.c       |   27 +++++++++++++++++++++++++-
 cfg_core.c     |    3 ++
 cfg_core.h     |    1 +
 config.h       |    3 ++
 route.c        |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 route_struct.h |    2 +-
 6 files changed, 89 insertions(+), 4 deletions(-)

diff --git a/action.c b/action.c
index 82e187c..079bbfe 100644
--- a/action.c
+++ b/action.c
@@ -112,9 +112,10 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 	struct sip_uri *u;
 	unsigned short port;
 	str* dst_host;
-	int i;
+	int i, flags;
 	struct switch_cond_table* sct;
 	struct switch_jmp_table*  sjt;
+	struct rval_expr* rve;
 
 
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
@@ -906,6 +907,30 @@ sw_jt_def:
 											   returns passthrough */
 			}
 			break;
+		case WHILE_T:
+			i=0;
+			flags=0;
+			rve=(struct rval_expr*)a->val[0].u.data;
+			ret=1;
+			while(!(flags & BREAK_R_F) && 
+					(rval_expr_eval_int(h, msg, &v, rve) == 0) && v){
+				i++;
+				if (unlikely(i > cfg_get(core, core_cfg, max_while_loops))){
+					LOG(L_ERR, "ERROR: runaway while (%d, %d): more then"
+								" %d loops\n", 
+								rve->fpos.s_line, rve->fpos.s_col,
+								cfg_get(core, core_cfg, max_while_loops));
+					ret=-1;
+					break;
+				}
+				if (likely(a->val[1].u.data)){
+					ret=run_actions(h, (struct action*)a->val[1].u.data, msg);
+					flags|=h->run_flags;
+					h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+												   returns passthrough */
+				}
+			}
+			break;
 		case FORCE_RPORT_T:
 			msg->msg_flags|=FL_FORCE_RPORT;
 			ret=1; /* continue processing */
diff --git a/cfg_core.c b/cfg_core.c
index f3c511e..9a2b0b2 100644
--- a/cfg_core.c
+++ b/cfg_core.c
@@ -88,6 +88,7 @@ struct cfg_group_core default_core_cfg = {
 #ifdef SHM_MEM
 	0, /* mem_dump_shm */
 #endif
+	DEFAULT_MAX_WHILE_LOOPS, /* max_while_loops */
 };
 
 void	*core_cfg = &default_core_cfg;
@@ -177,5 +178,7 @@ cfg_def_t core_cfg_def[] = {
 	{"mem_dump_shm",	CFG_VAR_INT,	0, 0, mem_dump_shm_fixup, 0,
 		"dump shared memory status"},
 #endif
+	{"max_while_loops",	CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
+		"maximum iterations allowed for a while loop" },
 	{0, 0, 0, 0, 0, 0}
 };
diff --git a/cfg_core.h b/cfg_core.h
index d916563..8e5457a 100644
--- a/cfg_core.h
+++ b/cfg_core.h
@@ -85,6 +85,7 @@ struct cfg_group_core {
 #ifdef SHM_MEM
 	int mem_dump_shm;
 #endif
+	int max_while_loops;
 };
 
 extern struct cfg_group_core default_core_cfg;
diff --git a/config.h b/config.h
index 393d1f3..0832eb0 100644
--- a/config.h
+++ b/config.h
@@ -208,4 +208,7 @@
 
 #define DEFAULT_DID "_default"
 
+/*  maximum allowed iterations for a while (to catch runaways) */
+#define DEFAULT_MAX_WHILE_LOOPS 100
+
 #endif
diff --git a/route.c b/route.c
index 5587f12..54e3236 100644
--- a/route.c
+++ b/route.c
@@ -623,6 +623,10 @@ int fix_actions(struct action* a)
 	struct ip_addr ip;
 	struct socket_info* si;
 	struct lvalue* lval;
+	struct rval_expr* rve;
+	struct rval_expr* err_rve;
+	enum rval_type rve_type, err_type, expected_type;
+
 	
 	char buf[30]; /* tmp buffer needed for module param fixups */
 
@@ -701,12 +705,12 @@ int fix_actions(struct action* a)
 			case SWITCH_T:
 				if (t->val[0].type!=RVE_ST){
 					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
-								"%d for if (should be expr)\n",
+								"%d for switch() (should be expr)\n",
 								t->val[0].type);
 					return E_BUG;
 				}else if (t->val[1].type!=CASE_ST){
 					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
-								"%d for switch(...){...}(should be action)\n",
+								"%d for switch(...){...}(should be case)\n",
 								t->val[1].type);
 					return E_BUG;
 				}
@@ -721,6 +725,55 @@ int fix_actions(struct action* a)
 				if ((ret=fix_switch(t))<0)
 					return ret;
 				break;
+			case WHILE_T:
+				if (t->val[0].type!=RVE_ST){
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+								"%d for while() (should be expr)\n",
+								t->val[0].type);
+					return E_BUG;
+				}else if (t->val[1].type!=ACTIONS_ST){
+					LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+								"%d for while(...){...}(should be action)\n",
+								t->val[1].type);
+					return E_BUG;
+				}
+				rve=(struct rval_expr*)t->val[0].u.data;
+				if (rve){
+					err_rve=0;
+					if (!rve_check_type(&rve_type, rve, &err_rve,
+											&err_type, &expected_type)){
+						if (err_rve)
+							LOG(L_ERR, "fix_actions: invalid expression "
+									"(%d,%d): subexpression (%d,%d) has type"
+									" %s,  but %s is expected\n",
+									rve->fpos.s_line, rve->fpos.s_col,
+									err_rve->fpos.s_line, err_rve->fpos.s_col,
+									rval_type_name(err_type),
+									rval_type_name(expected_type) );
+						else
+							LOG(L_ERR, "fix_actions: invalid expression "
+									"(%d,%d): type mismatch?",
+									rve->fpos.s_line, rve->fpos.s_col);
+						return E_UNSPEC;
+					}
+					if (rve_type!=RV_INT && rve_type!=RV_NONE){
+						LOG(L_ERR, "fix_actions: invalid expression (%d,%d):"
+								" bad type, integer expected\n",
+								rve->fpos.s_line, rve->fpos.s_col);
+						return E_UNSPEC;
+					}
+					if ((ret=fix_rval_expr((void**)&rve))<0)
+						return ret;
+				}else{
+					LOG(L_CRIT, "BUG: fix_actions: null while()"
+							" expression\n");
+					return E_BUG;
+				}
+				if ( t->val[1].u.data && 
+					((ret= fix_actions((struct action*)t->val[1].u.data))<0)){
+					return ret;
+				}
+				break;
 			case ASSIGN_T:
 			case ADD_T:
 				if (t->val[0].type !=LVAL_ST) {
diff --git a/route_struct.h b/route_struct.h
index a8cfe8f..85242af 100644
--- a/route_struct.h
+++ b/route_struct.h
@@ -71,7 +71,7 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T,
 		SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
 		IF_T, SWITCH_T /* only until fixup*/,
-		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T,
+		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, WHILE_T,
 		MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
 		AVPFLAG_OPER_T,




More information about the sr-dev mailing list