From 7d70bad74e6329dff0d22c3b215be8a56d696f79 Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Fri, 2 Jan 2015 18:58:00 +0100 Subject: [PATCH] dialplan: using $(avp("key")[*]) on match rules --- modules/dialplan/dp_repl.c | 290 ++++++++++++++++++++++++++++++++++--- 1 file changed, 271 insertions(+), 19 deletions(-) diff --git a/modules/dialplan/dp_repl.c b/modules/dialplan/dp_repl.c index 12ba230dbbf..9c15dee34d9 100644 --- a/modules/dialplan/dp_repl.c +++ b/modules/dialplan/dp_repl.c @@ -32,15 +32,174 @@ #include #include "../../re.h" +#include "../../str_list.h" #include "../../mem/shm_mem.h" #include "dialplan.h" +typedef struct dpl_dyn_pcre +{ + pcre *re; + int cnt; + str expr; -pcre *dpl_dynamic_pcre(sip_msg_t *msg, str *expr, int *cap_cnt) + struct dpl_dyn_pcre * next; /* next rule */ +} dpl_dyn_pcre_t, *dpl_dyn_pcre_p; + +static void dpl_get_avp_val(avp_t *avp, str *dst) { + avp_value_t val; + + if (avp==0 || dst==0) return; + + /* Warning! it uses static buffer from int2str !!! */ + + get_avp_val(avp, &val); + if (avp->flags & AVP_VAL_STR) { + *dst = val.s; + } + else { /* probably (!) number */ + dst->s = int2str(val.n, &dst->len); + } +} + +int dpl_dyn_printf_s(sip_msg_t *msg, const pv_elem_p elem, + const pv_elem_p avp_elem, str *val, pv_elem_p *elem_prev, str *vexpr) +{ + pv_elem_p e = NULL; + pv_elem_p t = NULL; + str s = STR_NULL; + int ret = -1; + + if(elem==NULL||avp_elem==NULL||elem_prev==NULL) return -1; + if(str_append(&(avp_elem->text), val, &s)<0) return -1; + + if(pv_parse_format(&s, &e)<0) { + LM_ERR("parsing expression: %.*s\n", s.len, s.s); + goto clean; + } + if(*elem_prev==NULL && elem!=avp_elem) { + LM_DBG("search for elem_prev\n"); + for(t=elem; t!=NULL; t=t->next) { + if(t->next==avp_elem) { *elem_prev = t; + LM_DBG("found!\n"); + } + } + } + if(*elem_prev) (*elem_prev)->next = e; + e->next = avp_elem->next; + if(pv_printf_s(msg, e, vexpr)<0){ + LM_ERR("cannot get avp pcre dynamic expression value\n"); + goto clean; + } + ret = 0; +clean: + if(s.s) pkg_free(s.s); + if(e) pkg_free(e); + if(*elem_prev) (*elem_prev)->next = avp_elem; + return ret; +} + +int dpl_get_avp_values(sip_msg_t *msg, const pv_elem_p elem, + const pv_elem_p avp_elem, struct str_list **out) +{ + struct usr_avp *avp = NULL; + unsigned short name_type; + int_str avp_name, avp_value; + struct search_state state; + int sum = 0; + str s = STR_NULL; + str ts = STR_NULL; + pv_elem_p elem_prev = NULL; + struct str_list *tl = NULL; + + if(elem==NULL||avp_elem==NULL||out==NULL||*out==NULL) { + LM_ERR("wrong parameters\n"); + return -1; + } + if(pv_get_avp_name(msg, &(avp_elem->spec->pvp), &avp_name, &name_type)!=0) { + LM_ERR("invalid avp name\n"); + return -1; + } + avp = search_first_avp(name_type, avp_name, &avp_value, &state); + if(avp==NULL) { + LM_ERR("can't find first avp\n"); + return -1; + } + tl = *out; + dpl_get_avp_val(avp, &s); + dpl_dyn_printf_s(msg, elem, avp_elem, &s, &elem_prev, &tl->s); + /*LM_DBG("elem[%p] avp_elem[%p], elem_prev[%p] [%.*s]\n", + elem, avp_elem, elem_prev, tl->s.len, tl->s.s);*/ + sum = tl->s.len; + while ((avp=search_next_avp(&state, &avp_value))!=0) { + dpl_get_avp_val(avp, &s); + dpl_dyn_printf_s(msg, elem, avp_elem, &s, &elem_prev, &ts); + if(append_str_list(ts.s, ts.len, &tl, &sum)==NULL) { + while(*out) { + tl = (*out)->next; + pkg_free(*out); + *out = tl; + } + return -1; + } + /*LM_DBG("elem[%p] avp_elem[%p], elem_prev[%p] [%.*s] out[%p] out->next[%p]\n", + elem, avp_elem, elem_prev, tl->s.len, tl->s.s, + *out, (*out)->next); */ + } + return 0; +} + +int dpl_detect_avp_indx(const pv_elem_p elem, pv_elem_p *avp) +{ + int num, num_avp_all; + pv_elem_p e = elem;; + if(elem==NULL||avp==NULL) return -1; + + for(e=elem, num=num_avp_all=0; e!=NULL; e=e->next, num++) { + if(e->spec!=NULL && e->spec->type==PVT_AVP && + e->spec->pvp.pvi.type==PV_IDX_ALL) + { + *avp = e; + num_avp_all++; + } + } + if(num_avp_all==1) return 1; /* just one avp_indx supported */ + return 0; +} + +pcre *dpl_dyn_pcre_comp(sip_msg_t *msg, str *expr, str *vexpr, int *cap_cnt) { - pv_elem_t *pelem = NULL; pcre *re = NULL; int ccnt = 0; + + if(expr==NULL || expr->s==NULL || expr->len<=0 || + vexpr==NULL || vexpr->s==NULL || vexpr->len<=0) + return NULL; + + re = reg_ex_comp(vexpr->s, &ccnt, 1); + if(!re) { + if(expr!=vexpr) + LM_ERR("failed to compile pcre expression: %.*s (%.*s)\n", + expr->len, expr->s, vexpr->len, vexpr->s); + else + LM_ERR("failed to compile pcre expression: %.*s\n", + vexpr->len, vexpr->s); + return NULL; + } + if(cap_cnt) { + *cap_cnt = ccnt; + } + if(expr!=vexpr) + LM_DBG("compiled dynamic pcre expression: %.*s (%.*s) %d\n", + expr->len, expr->s, vexpr->len, vexpr->s, ccnt); + else + LM_DBG("compiled dynamic pcre expression: %.*s %d\n", + vexpr->len, vexpr->s, ccnt); + return re; +} + +pcre *dpl_dynamic_pcre(sip_msg_t *msg, str *expr, int *cap_cnt) +{ + pv_elem_t *pelem = NULL; str vexpr; if(expr==NULL || expr->s==NULL || expr->len<=0) @@ -59,18 +218,96 @@ pcre *dpl_dynamic_pcre(sip_msg_t *msg, str *expr, int *cap_cnt) } pv_elem_free_all(pelem); - re = reg_ex_comp(vexpr.s, &ccnt, 1); - if(!re) { - LM_ERR("failed to compile pcre expression: %.*s (%.*s)\n", - expr->len, expr->s, vexpr.len, vexpr.s); + return dpl_dyn_pcre_comp(msg, expr, &vexpr, cap_cnt); +} + +dpl_dyn_pcre_p dpl_dynamic_pcre_list(sip_msg_t *msg, str *expr) +{ + pv_elem_p elem = NULL; + pv_elem_p avp_elem = NULL; + dpl_dyn_pcre_p re_list = NULL; + dpl_dyn_pcre_p rt = NULL; + struct str_list *l = NULL; + struct str_list *t = NULL; + pcre *re = NULL; + int cnt = 0; + str vexpr = STR_NULL; + + if(expr==NULL || expr->s==NULL || expr->len<=0) + { + LM_ERR("wrong parameters\n"); return NULL; } - if(cap_cnt) { - *cap_cnt = ccnt; + + if(pv_parse_format(expr, &elem)<0) { + LM_ERR("parsing pcre expression: %.*s\n", + expr->len, expr->s); + return NULL; } - LM_DBG("compiled dynamic pcre expression: %.*s (%.*s) %d\n", - expr->len, expr->s, vexpr.len, vexpr.s, ccnt); - return re; + LM_DBG("parsed pcre expression: %.*s\n", expr->len, expr->s); + if(dpl_detect_avp_indx(elem, &avp_elem)) { + l = pkg_malloc(sizeof(struct str_list)); + if(l==NULL) { + PKG_MEM_ERROR; + return NULL; + } + memset(l, 0, sizeof(struct str_list)); + if(dpl_get_avp_values(msg, elem, avp_elem, &l)<0) { + LM_ERR("can't get list of avp values\n"); + goto error; + } + t = l; + while(t) { + re = dpl_dyn_pcre_comp(msg, &(t->s), &(t->s), &cnt); + if(re!=NULL) { + rt = pkg_malloc(sizeof(dpl_dyn_pcre_t)); + if(rt==NULL) { + PKG_MEM_ERROR; + goto error; + } + rt->re = re; + rt->expr.s = t->s.s; + rt->expr.len = t->s.len; + rt->cnt = cnt; + rt->next = re_list; + re_list = rt; + } + t = t->next; + } + } + else { + if(pv_printf_s(msg, elem, &vexpr)<0){ + LM_ERR("cannot get pcre dynamic expression value: %.*s\n", + expr->len, expr->s); + goto error; + } + re = dpl_dyn_pcre_comp(msg, expr, &vexpr, &cnt); + if(re!=NULL) { + rt = pkg_malloc(sizeof(dpl_dyn_pcre_t)); + if(rt==NULL) { + PKG_MEM_ERROR; + goto error; + } + rt->re = re; + rt->expr.s = expr->s; + rt->expr.len = expr->len; + rt->cnt = cnt; + rt->next = re_list; + re_list = rt; + } + } + goto clean; +error: + while(re_list) { + rt = re_list->next; + if(re_list->re) pcre_free(re_list->re); + pkg_free(re_list); + re_list = rt; + } +clean: + if(elem) pv_elem_free_all(elem); + while(l) { t = l->next; pkg_free(l); l = t;} + return re_list; } void repl_expr_free(struct subst_expr *se) @@ -156,6 +393,7 @@ struct subst_expr* repl_exp_parse(str subst) } + #define MAX_PHONE_NB_DIGITS 127 static char dp_output_buf[MAX_PHONE_NB_DIGITS+1]; int rule_translate(sip_msg_t *msg, str string, dpl_node_t * rule, @@ -366,7 +604,8 @@ int translate(sip_msg_t *msg, str input, str *output, dpl_id_p idp, dpl_index_p indexp; int user_len, rez; char b; - pcre *match_re; + dpl_dyn_pcre_p re_list = NULL; + dpl_dyn_pcre_p rt = NULL; if(!input.s || !input.len) { LM_ERR("invalid input string\n"); @@ -391,18 +630,31 @@ int translate(sip_msg_t *msg, str input, str *output, dpl_id_p idp, LM_DBG("regex operator testing over [%.*s]\n", input.len, input.s); if(rulep->tflags&DP_TFLAGS_PV_MATCH) { - match_re = dpl_dynamic_pcre(msg, &rulep->match_exp, NULL); - if(match_re==NULL) { + re_list = dpl_dynamic_pcre_list(msg, &rulep->match_exp); + if(re_list==NULL) { /* failed to compile dynamic pcre -- ignore */ + LM_DBG("failed to compile dynamic pcre[%.*s]\n", + rulep->match_exp.len, rulep->match_exp.s); continue; } + rez = -1; + do { + if(rez<0) { + rez = pcre_exec(re_list->re, NULL, input.s, input.len, + 0, 0, NULL, 0); + LM_DBG("match check: [%.*s] %d\n", + re_list->expr.len, re_list->expr.s, rez); + } + else LM_DBG("match check skipped: [%.*s] %d\n", + re_list->expr.len, re_list->expr.s, rez); + rt = re_list->next; + pcre_free(re_list->re); + pkg_free(re_list); + re_list = rt; + } while(re_list); } else { - match_re = rulep->match_comp; - } - rez = pcre_exec(match_re, NULL, input.s, input.len, + rez = pcre_exec(rulep->match_comp, NULL, input.s, input.len, 0, 0, NULL, 0); - if(rulep->tflags&DP_TFLAGS_PV_MATCH) { - pcre_free(match_re); } break;