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, 19 Jan 2024 11:20:37 +0000 (12:20 +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 48df131a209819c7f61b075e325f4ac0396ce1c6..43aa6cd5a1bf111a7f3c188b05a5d346f90080ea 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
@@ -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;
 
index c769d004c33b5c91d489a41333f12e0e14d0cf7a..bdf2c3f42c052c43ec192856b7b81209ebd3d2d3 100644 (file)
@@ -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 */
@@ -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 subst);
 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
index cc4ebeb2beaac0ad9bfe8c961d3f1f2b219a0a3f..857a2e43e753da5d6c3c2c6d36d94a6710ea525f 100644 (file)
@@ -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, 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;
@@ -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)
index fccbb46fc7318cd632a8578d23f876da7d57d703..42ba3b4abe66b560245dc024b659b8fcbb8386c5 100644 (file)
@@ -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 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 || vexpr == NULL
@@ -225,7 +226,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;
 
@@ -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 *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);
                        return -1;
@@ -441,15 +443,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))
+               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 *instr, dpl_node_t *rule,
                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 *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;
 }
 
@@ -584,6 +596,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;
@@ -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);