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)
*
* 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
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;
#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"
#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 */
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 */
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
}
}
+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");
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);
/* 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;
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)
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)
typedef struct dpl_dyn_pcre
{
- pcre *re;
+ pcre2_code *re;
int cnt;
str expr;
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
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;
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;
}
#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;
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;
}
/*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*/
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;
}
}
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;
}
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;
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;
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);