From 7b54ed3fc09c7a570b365dfcc93fa56c329b8eee 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 Gbp-Pq: Topic upstream Gbp-Pq: Name dialplan-migrate-to-pcre2.patch --- src/modules/dialplan/Makefile | 11 +--- src/modules/dialplan/dialplan.c | 5 ++ src/modules/dialplan/dialplan.h | 18 +++--- src/modules/dialplan/dp_db.c | 103 +++++++++++++++++++------------- src/modules/dialplan/dp_repl.c | 54 +++++++++++------ 5 files changed, 117 insertions(+), 74 deletions(-) diff --git a/src/modules/dialplan/Makefile b/src/modules/dialplan/Makefile index abb4bf83..9fd2419b 100644 --- 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) diff --git a/src/modules/dialplan/dialplan.c b/src/modules/dialplan/dialplan.c index 80b83a70..e1631738 100644 --- 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 @@ -80,6 +82,9 @@ static int ki_dp_translate_vars(sip_msg_t* msg, int id, str *input, str *output) 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; diff --git a/src/modules/dialplan/dialplan.h b/src/modules/dialplan/dialplan.h index c47d53e4..33b17bd3 100644 --- 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 */ int pr; /* priority */ @@ -51,8 +55,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 */ @@ -99,7 +103,7 @@ 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 *); + 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 diff --git a/src/modules/dialplan/dp_db.c b/src/modules/dialplan/dp_db.c index 4275f026..94b4aade 100644 --- a/src/modules/dialplan/dp_db.c +++ b/src/modules/dialplan/dp_db.c @@ -193,11 +193,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"); @@ -224,6 +244,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); @@ -368,55 +396,50 @@ int dpl_str_to_shm(str src, str *dest, int mterm) /* 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) + * 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) { - pcre *re, *result; - const char *error; - int rc, err_offset; - size_t size; - - re = pcre_compile(pattern, 0, &error, &err_offset, NULL); + pcre2_code *re; + int pcre_error_num = 0; + char pcre_error[128]; + size_t pcre_erroffset; + int rc; + + 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; @@ -537,8 +560,8 @@ dpl_node_t * build_rule(db_val_t * values) return new_rule; err: - if(match_comp) shm_free(match_comp); - if(subst_comp) shm_free(subst_comp); + if(match_comp) pcre2_code_free(match_comp); + if(subst_comp) pcre2_code_free(subst_comp); if(repl_comp) repl_expr_free(repl_comp); if(new_rule) destroy_rule(new_rule); return NULL; @@ -682,10 +705,10 @@ void destroy_rule(dpl_node_t * rule){ 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) diff --git a/src/modules/dialplan/dp_repl.c b/src/modules/dialplan/dp_repl.c index 05949c82..92565f54 100644 --- 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; @@ -175,9 +175,9 @@ int dpl_detect_avp_indx(const pv_elem_p elem, pv_elem_p *avp) 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 || @@ -214,7 +214,7 @@ dpl_dyn_pcre_p dpl_dynamic_pcre_list(sip_msg_t *msg, str *expr) 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; @@ -285,7 +285,7 @@ dpl_dyn_pcre_p dpl_dynamic_pcre_list(sip_msg_t *msg, str *expr) error: while(re_list) { rt = re_list->next; - if(re_list->re) pcre_free(re_list->re); + if(re_list->re) pcre2_code_free(re_list->re); pkg_free(re_list); re_list = rt; } @@ -387,15 +387,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; @@ -411,8 +412,7 @@ int rule_translate(sip_msg_t *msg, str *instr, dpl_node_t *rule, 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); @@ -430,15 +430,19 @@ int rule_translate(sip_msg_t *msg, str *instr, dpl_node_t *rule, } /*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)) <= 0) { + 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*/ @@ -562,11 +566,15 @@ int rule_translate(sip_msg_t *msg, str *instr, dpl_node_t *rule, } 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; } @@ -575,6 +583,7 @@ static char dp_attrs_buf[DP_MAX_ATTRS_LEN+1]; 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; @@ -615,21 +624,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; @@ -720,7 +736,7 @@ repl: else 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); -- 2.30.2