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