From 374227b15ff7fbed8660beb93d52da15dcb4ba9e Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Mon, 21 Aug 2023 12:27:43 +0200 Subject: [PATCH] dialplan: migrate to pcre2 --- src/modules/dialplan/Makefile | 11 +--- src/modules/dialplan/dialplan.c | 5 ++ src/modules/dialplan/dialplan.h | 20 ++++--- src/modules/dialplan/dp_db.c | 103 +++++++++++++++++++------------- src/modules/dialplan/dp_repl.c | 56 +++++++++++------ 5 files changed, 121 insertions(+), 74 deletions(-) --- a/src/modules/dialplan/Makefile +++ b/src/modules/dialplan/Makefile @@ -6,20 +6,15 @@ auto_gen= NAME=dialplan.so ifeq ($(CROSS_COMPILE),) -PCRE_BUILDER = $(shell \ - if pkg-config --exists libcre; then \ - echo 'pkg-config libpcre'; \ - else \ - which pcre-config; \ - fi) +PCRE_BUILDER = $(shell command -v pcre2-config) endif ifeq ($(PCRE_BUILDER),) PCREDEFS=-I$(LOCALBASE)/include - PCRELIBS=-L$(LOCALBASE)/lib -lpcre + PCRELIBS=-L$(LOCALBASE)/lib -lpcre2-8 else PCREDEFS = $(shell $(PCRE_BUILDER) --cflags) - PCRELIBS = $(shell $(PCRE_BUILDER) --libs) + PCRELIBS = $(shell $(PCRE_BUILDER) --libs8) endif DEFS+=$(PCREDEFS) LIBS=$(PCRELIBS) --- a/src/modules/dialplan/dialplan.c +++ b/src/modules/dialplan/dialplan.c @@ -5,6 +5,8 @@ * * Copyright (C) 2014 Olle E. Johansson, Edvina AB * + * Copyright (C) 2023 Victor Seva + * * This file is part of Kamailio, a free SIP server. * * Kamailio is free software; you can redistribute it and/or modify @@ -79,6 +81,9 @@ static int ki_dp_translate_vars( int dp_replace_fixup(void **param, int param_no); int dp_replace_fixup_free(void **param, int param_no); +pcre2_general_context *dpl_gctx = NULL; +pcre2_compile_context *dpl_ctx = NULL; + str dp_attr_pvar_s = STR_NULL; pv_spec_t *dp_attr_pvar = NULL; --- a/src/modules/dialplan/dialplan.h +++ b/src/modules/dialplan/dialplan.h @@ -13,8 +13,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ @@ -30,7 +30,8 @@ #ifndef _DP_DIALPLAN_H #define _DP_DIALPLAN_H -#include +#define PCRE2_CODE_UNIT_WIDTH 8 +#include #include "../../core/pvar.h" #include "../../core/parser/msg_parser.h" @@ -43,6 +44,9 @@ #define DP_TFLAGS_PV_MATCH (1 << 0) #define DP_TFLAGS_PV_SUBST (1 << 1) +extern pcre2_general_context *dpl_gctx; +extern pcre2_compile_context *dpl_ctx; + typedef struct dpl_node { int dpid; /* dialplan id */ @@ -52,8 +56,8 @@ typedef struct dpl_node str match_exp; /* match-first string */ str subst_exp; /* match string with subtitution groupping */ str repl_exp; /* replacement expression string */ - pcre *match_comp; /* compiled matching expression */ - pcre *subst_comp; /* compiled substitution expression */ + pcre2_code *match_comp; /* compiled matching expression */ + pcre2_code *subst_comp; /* compiled substitution expression */ struct subst_expr *repl_comp; /* compiled replacement */ str attrs; /* attributes string */ unsigned int tflags; /* flags for type of values for matching */ @@ -103,8 +107,8 @@ struct subst_expr *repl_exp_parse(str su void repl_expr_free(struct subst_expr *se); int dp_translate_helper( sip_msg_t *msg, str *user_name, str *repl_user, dpl_id_p idp, str *); -int rule_translate( - sip_msg_t *msg, str *instr, dpl_node_t *rule, pcre *subst_comp, str *); +int rule_translate(sip_msg_t *msg, str *instr, dpl_node_t *rule, + pcre2_code *subst_comp, str *); -pcre *reg_ex_comp(const char *pattern, int *cap_cnt, int mtype); +pcre2_code *reg_ex_comp(const char *pattern, int *cap_cnt, int mtype); #endif --- a/src/modules/dialplan/dp_db.c +++ b/src/modules/dialplan/dp_db.c @@ -196,11 +196,31 @@ void dp_disconnect_db(void) } } +static void *pcre2_malloc(size_t size, void *ext) +{ + return shm_malloc(size); +} + +static void pcre2_free(void *ptr, void *ext) +{ + shm_free(ptr); + ptr = NULL; +} int init_data(void) { int *p; + if((dpl_gctx = pcre2_general_context_create(pcre2_malloc, pcre2_free, NULL)) + == NULL) { + LM_ERR("pcre2 general context creation failed\n"); + return -1; + } + if((dpl_ctx = pcre2_compile_context_create(dpl_gctx)) == NULL) { + LM_ERR("pcre2 compile context creation failed\n"); + return -1; + } + dp_rules_hash = (dpl_id_p *)shm_malloc(2 * sizeof(dpl_id_p)); if(!dp_rules_hash) { LM_ERR("out of shm memory\n"); @@ -227,6 +247,14 @@ int init_data(void) void destroy_data(void) { + if(dpl_ctx) { + pcre2_compile_context_free(dpl_ctx); + } + + if(dpl_gctx) { + pcre2_general_context_free(dpl_gctx); + } + if(dp_rules_hash) { destroy_hash(0); destroy_hash(1); @@ -373,55 +401,50 @@ int dpl_str_to_shm(str src, str *dest, i /* Compile pcre pattern - * if mtype==0 - return pointer to shm copy of result - * if mtype==1 - return pcre pointer that has to be pcre_free() */ -pcre *reg_ex_comp(const char *pattern, int *cap_cnt, int mtype) -{ - pcre *re, *result; - const char *error; - int rc, err_offset; - size_t size; + * if mtype==0 - return pointer using shm + * if mtype==1 - return pcre2_code pointer that has to be pcre2_code_free() */ +pcre2_code *reg_ex_comp(const char *pattern, int *cap_cnt, int mtype) +{ + pcre2_code *re; + int pcre_error_num = 0; + char pcre_error[128]; + size_t pcre_erroffset; + int rc; - re = pcre_compile(pattern, 0, &error, &err_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, 0, + &pcre_error_num, &pcre_erroffset, mtype == 0 ? dpl_ctx : NULL); if(re == NULL) { - LM_ERR("PCRE compilation of '%s' failed at offset %d: %s\n", pattern, - err_offset, error); - return (pcre *)0; - } - rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size); - if(rc != 0) { - pcre_free(re); - LM_ERR("pcre_fullinfo on compiled pattern '%s' yielded error: %d\n", - pattern, rc); - return (pcre *)0; + switch(pcre2_get_error_message( + pcre_error_num, (PCRE2_UCHAR *)pcre_error, 128)) { + case PCRE2_ERROR_NOMEMORY: + snprintf(pcre_error, 128, + "unknown error[%d]: pcre2 error buffer too small", + pcre_error_num); + break; + case PCRE2_ERROR_BADDATA: + snprintf(pcre_error, 128, "unknown pcre2 error[%d]", + pcre_error_num); + break; + } + LM_ERR("PCRE compilation of '%s' failed at offset %zu: %s\n", pattern, + pcre_erroffset, pcre_error); + return NULL; } - rc = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, cap_cnt); + rc = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, cap_cnt); if(rc != 0) { - pcre_free(re); + pcre2_code_free(re); LM_ERR("pcre_fullinfo on compiled pattern '%s' yielded error: %d\n", pattern, rc); - return (pcre *)0; - } - if(mtype == 0) { - result = (pcre *)shm_malloc(size); - if(result == NULL) { - pcre_free(re); - LM_ERR("not enough shared memory for compiled PCRE pattern\n"); - return (pcre *)0; - } - memcpy(result, re, size); - pcre_free(re); - return result; - } else { - return re; + return NULL; } + return re; } /*compile the expressions, and if ok, build the rule */ dpl_node_t *build_rule(db_val_t *values) { - pcre *match_comp, *subst_comp; + pcre2_code *match_comp, *subst_comp; struct subst_expr *repl_comp; dpl_node_t *new_rule; str match_exp, subst_exp, repl_exp, attrs; @@ -544,9 +567,9 @@ dpl_node_t *build_rule(db_val_t *values) err: if(match_comp) - shm_free(match_comp); + pcre2_code_free(match_comp); if(subst_comp) - shm_free(subst_comp); + pcre2_code_free(subst_comp); if(repl_comp) repl_expr_free(repl_comp); if(new_rule) @@ -692,10 +715,10 @@ void destroy_rule(dpl_node_t *rule) LM_DBG("destroying rule with priority %i\n", rule->pr); if(rule->match_comp) - shm_free(rule->match_comp); + pcre2_code_free(rule->match_comp); if(rule->subst_comp) - shm_free(rule->subst_comp); + pcre2_code_free(rule->subst_comp); /*destroy repl_exp*/ if(rule->repl_comp) --- a/src/modules/dialplan/dp_repl.c +++ b/src/modules/dialplan/dp_repl.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ @@ -38,7 +38,7 @@ typedef struct dpl_dyn_pcre { - pcre *re; + pcre2_code *re; int cnt; str expr; @@ -186,9 +186,10 @@ int dpl_detect_avp_indx(const pv_elem_p return 0; } -pcre *dpl_dyn_pcre_comp(sip_msg_t *msg, str *expr, str *vexpr, int *cap_cnt) +pcre2_code *dpl_dyn_pcre_comp( + sip_msg_t *msg, str *expr, str *vexpr, int *cap_cnt) { - pcre *re = NULL; + pcre2_code *re = NULL; int ccnt = 0; if(expr == NULL || expr->s == NULL || expr->len <= 0 || vexpr == NULL @@ -225,7 +226,7 @@ dpl_dyn_pcre_p dpl_dynamic_pcre_list(sip dpl_dyn_pcre_p rt = NULL; struct str_list *l = NULL; struct str_list *t = NULL; - pcre *re = NULL; + pcre2_code *re = NULL; int cnt = 0; str vexpr = STR_NULL; @@ -294,7 +295,7 @@ error: while(re_list) { rt = re_list->next; if(re_list->re) - pcre_free(re_list->re); + pcre2_code_free(re_list->re); pkg_free(re_list); re_list = rt; } @@ -400,15 +401,16 @@ error: #define MAX_PHONE_NB_DIGITS 127 static char dp_output_buf[MAX_PHONE_NB_DIGITS + 1]; int rule_translate(sip_msg_t *msg, str *instr, dpl_node_t *rule, - pcre *subst_comp, str *result) + pcre2_code *subst_comp, str *result) { int repl_nb, offset, match_nb, rc, cap_cnt; struct replace_with token; struct subst_expr *repl_comp; + pcre2_match_data *pcre_md = NULL; str match; pv_value_t sv; str *uri; - int ovector[3 * (MAX_REPLACE_WITH + 1)]; + PCRE2_SIZE *ovector = NULL; char *p; int size; @@ -424,7 +426,7 @@ int rule_translate(sip_msg_t *msg, str * if(subst_comp) { /*just in case something went wrong at load time*/ - rc = pcre_fullinfo(subst_comp, NULL, PCRE_INFO_CAPTURECOUNT, &cap_cnt); + rc = pcre2_pattern_info(subst_comp, PCRE2_INFO_CAPTURECOUNT, &cap_cnt); if(rc != 0) { LM_ERR("pcre_fullinfo on compiled pattern yielded error: %d\n", rc); return -1; @@ -441,15 +443,19 @@ int rule_translate(sip_msg_t *msg, str * } /*search for the pattern from the compiled subst_exp*/ - if(pcre_exec(subst_comp, NULL, instr->s, instr->len, 0, 0, ovector, - 3 * (MAX_REPLACE_WITH + 1)) + pcre_md = pcre2_match_data_create_from_pattern(subst_comp, NULL); + if(pcre2_match(subst_comp, (PCRE2_SPTR)instr->s, (PCRE2_SIZE)instr->len, + 0, 0, pcre_md, NULL) <= 0) { LM_DBG("the string %.*s matched " "the match_exp %.*s but not the subst_exp %.*s!\n", instr->len, instr->s, rule->match_exp.len, rule->match_exp.s, rule->subst_exp.len, rule->subst_exp.s); + if(pcre_md) + pcre2_match_data_free(pcre_md); return -1; } + ovector = pcre2_get_ovector_pointer(pcre_md); } /*simply copy from the replacing string*/ @@ -463,6 +469,8 @@ int rule_translate(sip_msg_t *msg, str * memcpy(result->s, repl_comp->replacement.s, repl_comp->replacement.len); result->len = repl_comp->replacement.len; result->s[result->len] = '\0'; + if(pcre_md) + pcre2_match_data_free(pcre_md); return 0; } @@ -571,11 +579,15 @@ int rule_translate(sip_msg_t *msg, str * } result->s[result->len] = '\0'; + if(pcre_md) + pcre2_match_data_free(pcre_md); return 0; error: result->s = 0; result->len = 0; + if(pcre_md) + pcre2_match_data_free(pcre_md); return -1; } @@ -584,6 +596,7 @@ static char dp_attrs_buf[DP_MAX_ATTRS_LE int dp_translate_helper( sip_msg_t *msg, str *input, str *output, dpl_id_p idp, str *attrs) { + pcre2_match_data *pcre_md = NULL; dpl_node_p rulep; dpl_index_p indexp; int user_len, rez; @@ -624,21 +637,28 @@ search_rule: rez = -1; do { if(rez < 0) { - rez = pcre_exec(re_list->re, NULL, input->s, - input->len, 0, 0, NULL, 0); + pcre_md = pcre2_match_data_create_from_pattern( + re_list->re, NULL); + rez = pcre2_match(re_list->re, (PCRE2_SPTR)input->s, + (PCRE2_SIZE)input->len, 0, 0, pcre_md, + NULL); 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); + pcre2_match_data_free(pcre_md); + pcre2_code_free(re_list->re); pkg_free(re_list); re_list = rt; } while(re_list); } else { - rez = pcre_exec(rulep->match_comp, NULL, input->s, - input->len, 0, 0, NULL, 0); + pcre_md = pcre2_match_data_create_from_pattern( + rulep->match_comp, NULL); + rez = pcre2_match(rulep->match_comp, (PCRE2_SPTR)input->s, + (PCRE2_SIZE)input->len, 0, 0, pcre_md, 0); + pcre2_match_data_free(pcre_md); } break; @@ -728,7 +748,7 @@ repl: LM_DBG("subst check skipped: [%.*s] %d\n", re_list->expr.len, re_list->expr.s, rez); rt = re_list->next; - pcre_free(re_list->re); + pcre2_code_free(re_list->re); pkg_free(re_list); re_list = rt; } while(re_list);