Module: sip-router
Branch: andrei/switch
Commit: dfda974cfb1c073fb751f74fab18a66f4bb341ec
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=dfda974…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)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,