Module: sip-router Branch: andrei/switch Commit: cfeefb4a0564d4b08cdbe33477a8a3e8c498f357 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=cfeefb4a...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Thu Feb 19 23:38:37 2009 +0100
script engine: string switch execution
- support for matching strings and regular expressions in a string switch (MATCH_T).
---
action.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ route_struct.h | 4 +- switch.h | 32 +++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 4 deletions(-)
diff --git a/action.c b/action.c index 079bbfe..cf7ac9c 100644 --- a/action.c +++ b/action.c @@ -116,6 +116,11 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg) struct switch_cond_table* sct; struct switch_jmp_table* sjt; struct rval_expr* rve; + struct match_cond_table* mct; + struct rvalue* rv; + struct rvalue* rv1; + struct rval_cache c1; + str s;
/* reset the value of error to E_UNSPEC so avoid unknowledgable @@ -907,6 +912,68 @@ sw_jt_def: returns passthrough */ } break; + case MATCH_COND_T: + mct=(struct match_cond_table*)a->val[1].u.data; + rval_cache_init(&c1); + rv=0; + rv1=0; + ret=rval_expr_eval_rvint(h, msg, &rv, &v, + (struct rval_expr*)a->val[0].u.data, &c1); + + if (unlikely( ret<0)){ + /* handle error in expression => use default */ + ret=-1; + goto match_cond_def; + } + if (h->run_flags & EXIT_R_F){ + ret=0; + break; + } + h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break + in expr */ + if (likely(rv)){ + rv1=rval_convert(h, msg, RV_STR, rv, &c1); + if (unlikely(rv1==0)){ + ret=-1; + goto match_cond_def; + } + s=rv1->v.s; + }else{ + /* int result in v */ + rval_cache_clean(&c1); + s.s=sint2str(v, &s.len); + } + ret=1; /* default is continue */ + for(i=0; i<mct->n; i++) + if (( mct->match[i].type==MATCH_STR && + mct->match[i].l.s.len==s.len && + memcmp(mct->match[i].l.s.s, s.s, s.len) == 0 ) || + ( mct->match[i].type==MATCH_RE && + regexec(mct->match[i].l.regex, s.s, 0, 0, 0) == 0) + ){ + if (likely(mct->jump[i])){ + ret=run_actions(h, mct->jump[i], msg); + h->run_flags &= ~BREAK_R_F; /* catch breaks, but let + returns passthrough */ + } + goto match_cleanup; + } +match_cond_def: + if (mct->def){ + ret=run_actions(h, mct->def, msg); + h->run_flags &= ~BREAK_R_F; /* catch breaks, but let + returns passthrough */ + } +match_cleanup: + if (rv1){ + rval_destroy(rv1); + rval_destroy(rv); + rval_cache_clean(&c1); + }else if (rv){ + rval_destroy(rv); + rval_cache_clean(&c1); + } + break; case WHILE_T: i=0; flags=0; diff --git a/route_struct.h b/route_struct.h index 85242af..888fadf 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, WHILE_T, + BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, MATCH_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, @@ -99,7 +99,7 @@ enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST, SELECT_ST, PVAR_ST, LVAL_ST, RVE_ST, RETCODE_ST, CASE_ST, - BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST + BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST, MATCH_CONDTABLE_ST };
/* run flags */ diff --git a/switch.h b/switch.h index e92cbad..a598a07 100644 --- a/switch.h +++ b/switch.h @@ -27,15 +27,24 @@ #ifndef __switch_h #define __switch_h
+#include <regex.h> + #include "route_struct.h"
+ struct case_stms{ struct rval_expr* ct_rve; struct action* actions; struct case_stms* next; struct case_stms** append; - int int_label; + int type; /**< type: MATCH_UNKOWN, MATCH_INT, MATCH_STR, MATCH_RE */ + int re_flags; /**< used only for REs */ int is_default; + union { + int match_int; + str match_str; + regex_t* match_re; + } label; /**< fixed case argument */ };
@@ -43,7 +52,7 @@ struct switch_cond_table{ int n; /**< size */ int* cond; /**< int labels array */ struct action** jump; /**< jump points array */ - struct action* def; /**< default jump */ + struct action* def; /**< default jump */ };
@@ -54,6 +63,25 @@ struct switch_jmp_table{ struct switch_cond_table rest; /**< normal cond. table for the rest */ };
+ +enum match_str_type { MATCH_UNKNOWN, MATCH_INT, MATCH_STR, MATCH_RE }; + +struct match_str{ + enum match_str_type type;/**< string or RE */ + int flags; /**< flags for re */ + union{ + str s; /* string */ + regex_t* regex; /**< compiled regex */ + }l; +}; + +struct match_cond_table{ + int n; /**< size */ + struct match_str* match; /**< match array */ + struct action** jump; /**< jump points array */ + struct action* def; /**< default jmp */ +}; + int fix_switch(struct action* t);
#endif /*__switch_h*/