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