dialplan: migrate to pcre2
authorVictor Seva <linuxmaniac@torreviejawireless.org>
Mon, 21 Aug 2023 10:27:43 +0000 (12:27 +0200)
committerVictor Seva <vseva@debian.org>
Fri, 29 Sep 2023 14:40:26 +0000 (15:40 +0100)
Gbp-Pq: Topic upstream
Gbp-Pq: Name dialplan-migrate-to-pcre2.patch

src/modules/dialplan/Makefile
src/modules/dialplan/dialplan.c
src/modules/dialplan/dialplan.h
src/modules/dialplan/dp_db.c
src/modules/dialplan/dp_repl.c

index abb4bf8388b92a74b21a3ac9950d154bbb3e07d4..9fd2419bf454d71d6549eed3a1fa8d3fd3e0fb53 100644 (file)
@@ -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)
index 80b83a7088373675e5db46fb76d22ff6cd3dfe74..e163173821e7543abfac6d28a2d1bab3d6e2188a 100644 (file)
@@ -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;
 
index c47d53e46b8f85d0c6a39a8385ba78f1d133427b..33b17bd3175f9af05dcc8866bd3fc3d4386eadba 100644 (file)
@@ -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 <pcre.h>
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
 #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
index 4275f0260d7e8e6cbc25135496048bdb78e2271c..94b4aadef6956318f5fb4fa607a42349f9c1e288 100644 (file)
@@ -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)
index 05949c82894fdc722150ade008ce7b682d113a48..92565f54482820eca9cdf2719c59814331446e62 100644 (file)
@@ -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);