diff --git a/debian/patches/series b/debian/patches/series index e6d1ed6f2..e0a358bea 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -75,6 +75,8 @@ upstream/avpops-add-avp_subst_pv.patch ### relevant for upstream sipwise/fix_error_in_cfgt_module.patch sipwise/pv_headers-store-To-info-in-xavp_parsed_name.r-on-re.patch +## +sipwise/pv_headers-full-rework.patch # ### Don't just put stuff in any order ### use gbp pq import/export tooling to help maintain patches diff --git a/debian/patches/sipwise/pv_headers-full-rework.patch b/debian/patches/sipwise/pv_headers-full-rework.patch new file mode 100644 index 000000000..a114e6b90 --- /dev/null +++ b/debian/patches/sipwise/pv_headers-full-rework.patch @@ -0,0 +1,2005 @@ +From: Victor Seva +Date: Wed, 29 Jan 2020 17:05:47 +0100 +Subject: pv_headers: full rework +--- + src/modules/pv_headers/README | 19 +- + src/modules/pv_headers/doc/pv_headers_admin.xml | 2 +- + src/modules/pv_headers/pv_headers.c | 408 ++++++++++++++++-------- + src/modules/pv_headers/pv_headers.h | 16 +- + src/modules/pv_headers/pvh_func.c | 202 +++++------- + src/modules/pv_headers/pvh_func.h | 18 +- + src/modules/pv_headers/pvh_hash.c | 12 +- + src/modules/pv_headers/pvh_hash.h | 12 +- + src/modules/pv_headers/pvh_hdr.c | 74 ++++- + src/modules/pv_headers/pvh_hdr.h | 18 +- + src/modules/pv_headers/pvh_str.c | 12 +- + src/modules/pv_headers/pvh_str.h | 12 +- + src/modules/pv_headers/pvh_xavp.c | 306 ++++++++++-------- + src/modules/pv_headers/pvh_xavp.h | 47 ++- + 14 files changed, 711 insertions(+), 447 deletions(-) + +diff --git a/src/modules/pv_headers/README b/src/modules/pv_headers/README +index b99cc42..1967529 100644 +--- a/src/modules/pv_headers/README ++++ b/src/modules/pv_headers/README +@@ -42,7 +42,7 @@ Victor Seva + 4.3. pvh_reset_headers() + 4.4. pvh_check_header(hname) + 4.5. pvh_append_header(hname, hvalue) +- 4.6. pvh_modify_header(hname, [idx], hvalue) ++ 4.6. pvh_modify_header(hname, hvalue, [idx]) + 4.7. pvh_remove_header(hname, [idx]) + + 5. Exported Variables +@@ -84,7 +84,7 @@ Chapter 1. Admin Guide + 4.3. pvh_reset_headers() + 4.4. pvh_check_header(hname) + 4.5. pvh_append_header(hname, hvalue) +- 4.6. pvh_modify_header(hname, [idx], hvalue) ++ 4.6. pvh_modify_header(hname, hvalue, [idx]) + 4.7. pvh_remove_header(hname, [idx]) + + 5. Exported Variables +@@ -140,7 +140,8 @@ modparam("pv_headers", "xavp_name", "pvh") + + 3.2. header_value_size (int) + +- ??????. ++ Defines an internal maximum SIP header value size. Header values longer ++ than this setting will be stripped down when collected or applied. + + Default value is 1024. + +@@ -151,7 +152,9 @@ modparam("pv_headers", "header_value_size", 512) + + 3.3. header_collect_flag (int) + +- ??????. ++ Used to mark that headers are collected for the SIP message, leading to ++ subsequent headers collection on this message to be declined with an ++ error. Should be used only in branches and replies. + + Default value is 27. + +@@ -162,7 +165,9 @@ modparam("pv_headers", "header_collect_flag", 37) + + 3.4. header_apply_flag (int) + +- ??????. ++ Used to mark that headers are applied for the SIP message, leading to ++ subsequent headers applies on this message to be declined with an ++ error. Should be used only in branches and replies. + + Default value is 28. + +@@ -233,7 +238,7 @@ modparam("pvh", "auto_msg", 1) + 4.3. pvh_reset_headers() + 4.4. pvh_check_header(hname) + 4.5. pvh_append_header(hname, hvalue) +- 4.6. pvh_modify_header(hname, [idx], hvalue) ++ 4.6. pvh_modify_header(hname, hvalue, [idx]) + 4.7. pvh_remove_header(hname, [idx]) + + \ +@@ -288,7 +293,7 @@ modparam("pvh", "auto_msg", 1) + This function can be used from ANY_ROUTE but only after + pvh_collect_headers() or with "auto_msg" parameter enabled. + +-4.6. pvh_modify_header(hname, [idx], hvalue) ++4.6. pvh_modify_header(hname, hvalue, [idx]) + + Modifies an existing header in the XAVP "hname" with the value "hvalue" + into the XAVP. Index order is top to bottom. Please note that +diff --git a/src/modules/pv_headers/doc/pv_headers_admin.xml b/src/modules/pv_headers/doc/pv_headers_admin.xml +index 9c5c009..44e84f2 100644 +--- a/src/modules/pv_headers/doc/pv_headers_admin.xml ++++ b/src/modules/pv_headers/doc/pv_headers_admin.xml +@@ -64,7 +64,7 @@ + + + +- ++ +
+ Exported Variables + +diff --git a/src/modules/pv_headers/pv_headers.c b/src/modules/pv_headers/pv_headers.c +index 9730847..84ac0c1 100644 +--- a/src/modules/pv_headers/pv_headers.c ++++ b/src/modules/pv_headers/pv_headers.c +@@ -1,16 +1,18 @@ + /* + * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +@@ -22,76 +24,99 @@ + */ + + #include "../../core/sr_module.h" +-#include "../../core/mod_fix.h" + #include "../../core/script_cb.h" ++#include "../../core/mod_fix.h" + #include "../../modules/tm/tm_load.h" + #include "../../core/kemi.h" + + #include "pv_headers.h" + #include "pvh_func.h" +-#include "pvh_xavp.h" + #include "pvh_hash.h" ++#include "pvh_xavp.h" + + MODULE_VERSION + + #define MODULE_NAME "pv_headers" +- + #define XAVP_NAME "headers" + +-#define FL_NAME_PV_HDRS_COLLECTED "pv_headers_collected" +-#define FL_NAME_PV_HDRS_APPLIED "pv_headers_applied" +- +-int FL_PV_HDRS_COLLECTED = 27; +-int FL_PV_HDRS_APPLIED = 28; +- + uac_api_t uac; + static tm_api_t tmb; + + str xavp_name = str_init(XAVP_NAME); +- ++str xavp_helper_xname = str_init("modparam_pv_headers"); + str xavp_parsed_xname = str_init("parsed_pv_headers"); ++unsigned int header_name_size = 255; ++unsigned int header_value_size = 1024; ++int FL_PV_HDRS_COLLECTED = 27; ++int FL_PV_HDRS_APPLIED = 28; + static str skip_headers_param = + str_init("Record-Route,Via,Route,Content-Length,Max-Forwards,CSeq"); + static str split_headers_param = STR_NULL; +-static int auto_msg_param = 1; +- + static str single_headers_param = str_init(""); ++static int auto_msg_param = 1; + + str _hdr_from = {"From", 4}; + str _hdr_to = {"To", 2}; +- +-unsigned int header_name_size = 255; +-unsigned int header_value_size = 1024; +- ++str _hdr_reply_reason = {"@Reply-Reason", 13}; ++int _branch = T_BR_UNDEFINED; ++int _reply_counter = -1; + + static void mod_destroy(void); + static int mod_init(void); + + static void handle_tm_t(tm_cell_t *t, int type, struct tmcb_params *params); + static int handle_msg_cb(struct sip_msg *msg, unsigned int flags, void *cb); ++static int handle_msg_branch_cb( ++ struct sip_msg *msg, unsigned int flags, void *cb); ++static int handle_msg_reply_cb( ++ struct sip_msg *msg, unsigned int flags, void *cb); + + static int w_pvh_collect_headers(struct sip_msg *msg, char *p1, char *p2) + { +- return pvh_collect_headers(msg, 0); ++ sr_xavp_t **backup_xavps = NULL; ++ ++ if(pvh_get_branch_index(msg, &_branch) < 0) ++ return -1; ++ if(msg->first_line.type == SIP_REPLY) { ++ if((_reply_counter = pvh_reply_append(backup_xavps)) < 0) { ++ return -1; ++ } ++ } ++ return pvh_collect_headers(msg); + } + + static int ki_pvh_collect_headers(struct sip_msg *msg) + { +- return pvh_collect_headers(msg, 0); ++ sr_xavp_t **backup_xavps = NULL; ++ ++ if(pvh_get_branch_index(msg, &_branch) < 0) ++ return -1; ++ if(msg->first_line.type == SIP_REPLY) { ++ if((_reply_counter = pvh_reply_append(backup_xavps)) < 0) { ++ return -1; ++ } ++ } ++ return pvh_collect_headers(msg); + } + + static int w_pvh_apply_headers(struct sip_msg *msg, char *p1, char *p2) + { +- return pvh_apply_headers(msg, 0); ++ if(pvh_get_branch_index(msg, &_branch) < 0) ++ return -1; ++ return pvh_apply_headers(msg); + } + + static int ki_pvh_apply_headers(struct sip_msg *msg) + { +- return pvh_apply_headers(msg, 0); ++ if(pvh_get_branch_index(msg, &_branch) < 0) ++ return -1; ++ return pvh_apply_headers(msg); + } + + static int w_pvh_reset_headers(struct sip_msg *msg, char *p1, char *p2) + { ++ if(pvh_get_branch_index(msg, &_branch) < 0) ++ return -1; + return pvh_reset_headers(msg); + } + +@@ -151,79 +176,83 @@ static int w_pvh_remove_header( + return pvh_remove_header(msg, &hname, indx); + } + +-/* +- * Exported functions +- */ ++/* clang-format off */ + static cmd_export_t cmds[] = { +- {"pvh_collect_headers", (cmd_function)w_pvh_collect_headers, 0, 0, 0, +- ANY_ROUTE}, +- {"pvh_apply_headers", (cmd_function)w_pvh_apply_headers, 0, 0, 0, +- ANY_ROUTE}, +- {"pvh_reset_headers", (cmd_function)w_pvh_reset_headers, 0, 0, 0, +- ANY_ROUTE}, +- {"pvh_check_header", (cmd_function)w_pvh_check_header, 1, +- fixup_spve_null, fixup_free_spve_null, ANY_ROUTE}, +- {"pvh_append_header", (cmd_function)w_pvh_append_header, 2, +- fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE}, +- {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 2, +- fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE}, +- {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 3, +- fixup_spve_all, fixup_free_spve_all, ANY_ROUTE}, +- {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 1, +- fixup_spve_null, fixup_free_spve_null, ANY_ROUTE}, +- {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 2, +- fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE}, +- {0, 0, 0, 0, 0, 0}}; ++ {"pvh_collect_headers", (cmd_function)w_pvh_collect_headers, 0, 0, 0, ++ ANY_ROUTE}, ++ {"pvh_apply_headers", (cmd_function)w_pvh_apply_headers, 0, 0, 0, ++ ANY_ROUTE}, ++ {"pvh_reset_headers", (cmd_function)w_pvh_reset_headers, 0, 0, 0, ++ ANY_ROUTE}, ++ {"pvh_check_header", (cmd_function)w_pvh_check_header, 1, ++ fixup_spve_null, fixup_free_spve_null, ANY_ROUTE}, ++ {"pvh_append_header", (cmd_function)w_pvh_append_header, 2, ++ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE}, ++ {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 2, ++ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE}, ++ {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 3, ++ fixup_spve_all, fixup_free_spve_all, ANY_ROUTE}, ++ {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 1, ++ fixup_spve_null, fixup_free_spve_null, ANY_ROUTE}, ++ {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 2, ++ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE}, ++ {0, 0, 0, 0, 0, 0} ++}; + + static pv_export_t mod_pvs[] = { +- {{"x_hdr", (sizeof("x_hdr") - 1)}, PVT_OTHER, pvh_get_header, +- pvh_set_header, pvh_parse_header_name, pv_parse_index, 0, 0}, +- {{"x_fu", (sizeof("x_fu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, +- 0, pv_init_iname, 1}, +- {{"x_fU", (sizeof("x_fU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, +- 0, pv_init_iname, 2}, +- {{"x_fd", (sizeof("x_fd") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, +- 0, pv_init_iname, 3}, +- {{"x_fn", (sizeof("x_fn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, +- 0, pv_init_iname, 4}, +- {{"x_ft", (sizeof("x_ft") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0, +- 0, pv_init_iname, 5}, +- {{"x_tu", (sizeof("x_tu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, +- 0, pv_init_iname, 6}, +- {{"x_tU", (sizeof("x_tU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, +- 0, pv_init_iname, 7}, +- {{"x_td", (sizeof("x_td") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, +- 0, pv_init_iname, 8}, +- {{"x_tn", (sizeof("x_tn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, +- 0, pv_init_iname, 9}, +- {{"x_tt", (sizeof("x_tt") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0, +- 0, pv_init_iname, 10}, +- {{"x_rs", (sizeof("x_rs") - 1)}, PVT_OTHER, pvh_get_reply_sr, +- pvh_set_reply_sr, 0, 0, pv_init_iname, 1}, +- {{"x_rr", (sizeof("x_rr") - 1)}, PVT_OTHER, pvh_get_reply_sr, +- pvh_set_reply_sr, 0, 0, pv_init_iname, 2}, +- {{0, 0}, 0, 0, 0, 0, 0, 0, 0}}; +- +-static param_export_t params[] = {{"xavp_name", PARAM_STR, &xavp_name}, +- {"header_value_size", PARAM_INT, &header_value_size}, +- {"header_collect_flag", PARAM_INT, &FL_PV_HDRS_COLLECTED}, +- {"header_apply_flag", PARAM_INT, &FL_PV_HDRS_APPLIED}, +- {"skip_headers", PARAM_STR, &skip_headers_param}, +- {"split_headers", PARAM_STR, &split_headers_param}, +- {"auto_msg", PARAM_INT, &auto_msg_param}, {0, 0, 0}}; ++ {{"x_hdr", (sizeof("x_hdr") - 1)}, PVT_OTHER, pvh_get_header, ++ pvh_set_header, pvh_parse_header_name, pv_parse_index, 0, 0}, ++ {{"x_fu", (sizeof("x_fu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, ++ 0, pv_init_iname, 1}, ++ {{"x_fU", (sizeof("x_fU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, ++ 0, pv_init_iname, 2}, ++ {{"x_fd", (sizeof("x_fd") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, ++ 0, pv_init_iname, 3}, ++ {{"x_fn", (sizeof("x_fn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, ++ 0, pv_init_iname, 4}, ++ {{"x_ft", (sizeof("x_ft") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0, ++ 0, pv_init_iname, 5}, ++ {{"x_tu", (sizeof("x_tu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, ++ 0, pv_init_iname, 6}, ++ {{"x_tU", (sizeof("x_tU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, ++ 0, pv_init_iname, 7}, ++ {{"x_td", (sizeof("x_td") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, ++ 0, pv_init_iname, 8}, ++ {{"x_tn", (sizeof("x_tn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0, ++ 0, pv_init_iname, 9}, ++ {{"x_tt", (sizeof("x_tt") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0, ++ 0, pv_init_iname, 10}, ++ {{"x_rs", (sizeof("x_rs") - 1)}, PVT_OTHER, pvh_get_reply_sr, ++ pvh_set_reply_sr, 0, 0, pv_init_iname, 1}, ++ {{"x_rr", (sizeof("x_rr") - 1)}, PVT_OTHER, pvh_get_reply_sr, ++ pvh_set_reply_sr, 0, 0, pv_init_iname, 2}, ++ {{0, 0}, 0, 0, 0, 0, 0, 0, 0} ++}; ++ ++static param_export_t params[] = { ++ {"xavp_name", PARAM_STR, &xavp_name}, ++ {"header_value_size", PARAM_INT, &header_value_size}, ++ {"header_collect_flag", PARAM_INT, &FL_PV_HDRS_COLLECTED}, ++ {"header_apply_flag", PARAM_INT, &FL_PV_HDRS_APPLIED}, ++ {"skip_headers", PARAM_STR, &skip_headers_param}, ++ {"split_headers", PARAM_STR, &split_headers_param}, ++ {"auto_msg", PARAM_INT, &auto_msg_param}, ++ {0, 0, 0} ++}; + + struct module_exports exports = { +- MODULE_NAME, /* module name */ +- DEFAULT_DLFLAGS, /* dlopen flags */ +- cmds, /* exported functions */ +- params, /* exported parameters */ +- 0, /* RPC method exports */ +- mod_pvs, /* exported pseudo-variables */ +- 0, /* response handling function */ +- mod_init, /* module initialization function */ +- 0, /* per-child init function */ +- mod_destroy /* module destroy function */ ++ MODULE_NAME, /* module name */ ++ DEFAULT_DLFLAGS, /* dlopen flags */ ++ cmds, /* exported functions */ ++ params, /* exported parameters */ ++ 0, /* RPC method exports */ ++ mod_pvs, /* exported pseudo-variables */ ++ 0, /* response handling function */ ++ mod_init, /* module initialization function */ ++ 0, /* per-child init function */ ++ mod_destroy /* module destroy function */ + }; ++/* clang-format on */ + + int mod_init(void) + { +@@ -238,19 +267,25 @@ int mod_init(void) + LM_NOTICE("could not bind to the 'tm' module, automatic headers " + "collect/apply is disabled\n"); + auto_msg_param = 0; +- } else { +- if(auto_msg_param +- && register_script_cb( +- handle_msg_cb, PRE_SCRIPT_CB | REQUEST_CB, 0) +- < 0) { +- LM_ERR("cannot register PRE_SCRIPT_CB callbacks\n"); ++ } ++ if(auto_msg_param) { ++ if(register_script_cb(handle_msg_cb, PRE_SCRIPT_CB | REQUEST_CB, 0) ++ < 0) { ++ LM_ERR("cannot register PRE_SCRIPT_CB REQUEST_CB callbacks\n"); ++ return -1; ++ } ++ if(register_script_cb( ++ handle_msg_branch_cb, PRE_SCRIPT_CB | BRANCH_CB, 0) ++ < 0) { ++ LM_ERR("cannot register PRE_SCRIPT_CB BRANCH_CB callbacks\n"); ++ return -1; ++ } ++ if(register_script_cb( ++ handle_msg_reply_cb, PRE_SCRIPT_CB | ONREPLY_CB, 0) ++ < 0) { ++ LM_ERR("cannot register PRE_SCRIPT_CB ONREPLY_CB callbacks\n"); + return -1; + } +- } +- +- if(header_value_size == 0) { +- LM_ERR("header_value_size must be >=0\n"); +- return -1; + } + + pvh_str_hash_init(&skip_headers, &skip_headers_param, "skip_headers"); +@@ -262,25 +297,81 @@ int mod_init(void) + + void mod_destroy(void) + { +- pvh_str_hash_free(&skip_headers); +- pvh_str_hash_free(&split_headers); +- pvh_str_hash_free(&single_headers); +- pvh_free_xavp(&xavp_name); +- pvh_free_xavp(&xavp_parsed_xname); + LM_INFO("%s module unload...\n", MODULE_NAME); + } + ++/* just for debug */ ++static inline char *tm_type_to_string(int type) ++{ ++ switch(type) { ++ case TMCB_REQUEST_IN: ++ return "TMCB_REQUEST_IN"; ++ case TMCB_RESPONSE_IN: ++ return "TMCB_RESPONSE_IN"; ++ case TMCB_E2EACK_IN: ++ return "TMCB_E2EACK_IN"; ++ case TMCB_REQUEST_PENDING: ++ return "TMCB_REQUEST_PENDING"; ++ case TMCB_REQUEST_FWDED: ++ return "TMCB_REQUEST_FWDED"; ++ case TMCB_RESPONSE_FWDED: ++ return "TMCB_RESPONSE_FWDED"; ++ case TMCB_ON_FAILURE_RO: ++ return "TMCB_ON_FAILURE_RO"; ++ case TMCB_ON_FAILURE: ++ return "TMCB_ON_FAILURE"; ++ case TMCB_REQUEST_OUT: ++ return "TMCB_REQUEST_OUT"; ++ case TMCB_RESPONSE_OUT: ++ return "TMCB_RESPONSE_OUT"; ++ case TMCB_LOCAL_COMPLETED: ++ return "TMCB_LOCAL_COMPLETED"; ++ case TMCB_LOCAL_RESPONSE_OUT: ++ return "TMCB_LOCAL_RESPONSE_OUT"; ++ case TMCB_ACK_NEG_IN: ++ return "TMCB_ACK_NEG_IN"; ++ case TMCB_REQ_RETR_IN: ++ return "TMCB_REQ_RETR_IN"; ++ case TMCB_LOCAL_RESPONSE_IN: ++ return "TMCB_LOCAL_RESPONSE_IN"; ++ case TMCB_LOCAL_REQUEST_IN: ++ return "TMCB_LOCAL_REQUEST_IN"; ++ case TMCB_DLG: ++ return "TMCB_DLG"; ++ case TMCB_DESTROY: ++ return "TMCB_DESTROY"; ++ case TMCB_E2ECANCEL_IN: ++ return "TMCB_E2ECANCEL_IN"; ++ case TMCB_E2EACK_RETR_IN: ++ return "TMCB_E2EACK_RETR_IN"; ++ case TMCB_RESPONSE_READY: ++ return "TMCB_RESPONSE_READY"; ++ case TMCB_DONT_ACK: ++ return "TMCB_DONT_ACK"; ++ case TMCB_REQUEST_SENT: ++ return "TMCB_REQUEST_SENT"; ++ case TMCB_RESPONSE_SENT: ++ return "TMCB_RESPONSE_SENT"; ++ case TMCB_ON_BRANCH_FAILURE: ++ return "TMCB_ON_BRANCH_FAILURE"; ++ case TMCB_ON_BRANCH_FAILURE_RO: ++ return "TMCB_ON_BRANCH_FAILURE_RO"; ++ case TMCB_MAX: ++ return "TMCB_MAX"; ++ } ++ ++ return "UNKNOWN"; ++} ++ + void handle_tm_t(tm_cell_t *t, int type, struct tmcb_params *params) + { + struct sip_msg *msg = NULL; + +- if(type & TMCB_RESPONSE_IN) { +- msg = params->rpl; +- if(msg != NULL && msg != FAKED_REPLY) { +- pvh_reset_headers(msg); +- pvh_collect_headers(msg, 1); +- } +- } else if(type & TMCB_REQUEST_FWDED) { ++ LM_DBG("T:%p params->branch:%d type:%s\n", t, params->branch, ++ tm_type_to_string(type)); ++ ++ ++ if(type & TMCB_REQUEST_FWDED) { + msg = params->req; + } else if(type & (TMCB_ON_BRANCH_FAILURE | TMCB_RESPONSE_FWDED)) { + msg = params->rpl; +@@ -289,26 +380,93 @@ void handle_tm_t(tm_cell_t *t, int type, struct tmcb_params *params) + return; + } + +- if(msg != NULL && msg != FAKED_REPLY) +- pvh_apply_headers(msg, 1); + ++ LM_DBG("T:%p picked_branch:%d label:%d branches:%d\n", t, ++ tmb.t_get_picked_branch(), t->label, t->nr_of_outgoings); ++ ++ if(msg != NULL && msg != FAKED_REPLY) { ++ pvh_get_branch_index(msg, &_branch); ++ LM_DBG("T:%p set branch:%d\n", t, _branch); ++ pvh_apply_headers(msg); ++ } + return; + } + ++static int msg_cbs = ++ TMCB_REQUEST_FWDED | TMCB_RESPONSE_FWDED | TMCB_ON_BRANCH_FAILURE; ++ + int handle_msg_cb(struct sip_msg *msg, unsigned int flags, void *cb) + { +- int cbs = TMCB_REQUEST_FWDED | TMCB_RESPONSE_FWDED | TMCB_RESPONSE_IN +- | TMCB_ON_BRANCH_FAILURE; ++ if(pvh_parse_msg(msg) != 0) ++ return 1; + +- if(flags & (PRE_SCRIPT_CB | REQUEST_CB)) { +- if(tmb.register_tmcb(msg, 0, cbs, handle_tm_t, 0, 0) <= 0) { +- LM_ERR("cannot register TM callbacks\n"); +- return -1; +- } +- pvh_collect_headers(msg, 1); ++ if(tmb.register_tmcb(msg, 0, msg_cbs, handle_tm_t, 0, 0) <= 0) { ++ LM_ERR("cannot register TM callbacks\n"); ++ return -1; ++ } ++ ++ _branch = 0; ++ LM_DBG("msg:%p set branch:%d\n", msg, _branch); ++ pvh_collect_headers(msg); ++ return 1; ++} ++ ++int handle_msg_branch_cb(struct sip_msg *msg, unsigned int flags, void *cb) ++{ ++ ++ LM_DBG("msg:%p previous branch:%d\n", msg, _branch); ++ ++ if(flags & PRE_SCRIPT_CB) { ++ pvh_get_branch_index(msg, &_branch); ++ LM_DBG("msg:%p set branch:%d\n", msg, _branch); ++ pvh_clone_branch_xavp(msg, &xavp_name); ++ } ++ ++ return 1; ++} ++ ++int handle_msg_reply_cb(struct sip_msg *msg, unsigned int flags, void *cb) ++{ ++ tm_cell_t *t = NULL; ++ sr_xavp_t **backup_xavps = NULL; ++ sr_xavp_t **list = NULL; ++ ++ if(pvh_parse_msg(msg) != 0) ++ return 1; ++ LM_DBG("msg:%p previous branch:%d\n", msg, _branch); ++ ++ if(tmb.t_check(msg, &_branch) == -1) { ++ LM_ERR("failed find UAC branch\n"); + } else { +- LM_ERR("unknown callback: %d\n", flags); ++ t = tmb.t_gett(); ++ if(t == NULL || t == T_UNDEFINED) { ++ LM_DBG("cannot lookup the transaction\n"); ++ } else { ++ LM_DBG("T:%p t_check-branch:%d xavp_list:%p branches:%d\n", t, ++ _branch, &t->xavps_list, t->nr_of_outgoings); ++ list = &t->xavps_list; ++ backup_xavps = xavp_set_list(&t->xavps_list); ++ } ++ } ++ ++ pvh_get_branch_index(msg, &_branch); ++ LM_DBG("T:%p set branch:%d picked_branch:%d\n", t, _branch, ++ tmb.t_get_picked_branch()); ++ ++ if((_reply_counter = pvh_reply_append(list)) < 0) { ++ return -1; ++ } ++ pvh_collect_headers(msg); ++ if(backup_xavps) { ++ xavp_set_list(backup_xavps); ++ LM_DBG("restored backup_xavps:%p\n", *backup_xavps); ++ } ++ if(t) { ++ tmb.unref_cell(t); ++ LM_DBG("T:%p unref\n", t); + } ++ tmb.t_sett(T_UNDEFINED, T_BR_UNDEFINED); ++ LM_DBG("reset tm\n"); + + return 1; + } +diff --git a/src/modules/pv_headers/pv_headers.h b/src/modules/pv_headers/pv_headers.h +index 556b7bf..4d53318 100644 +--- a/src/modules/pv_headers/pv_headers.h ++++ b/src/modules/pv_headers/pv_headers.h +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +@@ -38,12 +40,16 @@ extern uac_api_t uac; + + extern str xavp_name; + extern str xavp_parsed_xname; ++extern str xavp_helper_xname; + + extern unsigned int header_name_size; + extern unsigned int header_value_size; + + extern str _hdr_from; + extern str _hdr_to; ++extern str _hdr_reply_reason; ++extern int _branch; ++extern int _reply_counter; + + extern int FL_PV_HDRS_COLLECTED; + extern int FL_PV_HDRS_APPLIED; +diff --git a/src/modules/pv_headers/pvh_func.c b/src/modules/pv_headers/pvh_func.c +index 88a6497..b3749a6 100644 +--- a/src/modules/pv_headers/pvh_func.c ++++ b/src/modules/pv_headers/pvh_func.c +@@ -1,16 +1,18 @@ + /* + * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +@@ -21,18 +23,38 @@ + * + */ + +-#include "../../core/dset.h" ++#include "../../core/strutils.h" + + #include "pv_headers.h" ++#include "pvh_func.h" ++#include "pvh_xavp.h" + #include "pvh_str.h" +-#include "pvh_hdr.h" + #include "pvh_hash.h" +-#include "pvh_xavp.h" ++#include "pvh_hdr.h" + +-static str xavp_helper_xname = str_init("modparam_pv_headers"); + static str xavp_helper_name = str_init("xavp_name"); + +-int pvh_collect_headers(struct sip_msg *msg, int is_auto) ++int pvh_parse_msg(sip_msg_t *msg) ++{ ++ if(msg->first_line.type == SIP_REQUEST) { ++ if(!IS_SIP(msg)) { ++ LM_DBG("non SIP request message\n"); ++ return 1; ++ } ++ } else if(msg->first_line.type == SIP_REPLY) { ++ if(!IS_SIP_REPLY(msg)) { ++ LM_DBG("non SIP reply message\n"); ++ return 1; ++ } ++ } else { ++ LM_DBG("non SIP message\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int pvh_collect_headers(struct sip_msg *msg) + { + struct hdr_field *hf = NULL; + str name = STR_NULL; +@@ -40,22 +62,10 @@ int pvh_collect_headers(struct sip_msg *msg, int is_auto) + char hvals[header_name_size][header_value_size]; + int idx = 0, d_size = 0; + str val_part = STR_NULL; +- int br_idx; +- +- pvh_get_branch_index(msg, &br_idx); +- LM_DBG("br_idx: %d\n", br_idx); +- if(!is_auto) { +- if(msg->first_line.type == SIP_REPLY) { +- if(isflagset(msg, FL_PV_HDRS_COLLECTED) == 1) { +- LM_ERR("headers are already collected\n"); +- return -1; +- } +- } else { +- if(isbflagset(br_idx, FL_PV_HDRS_COLLECTED) == 1) { +- LM_ERR("headers are already collected\n"); +- return -1; +- } +- } ++ ++ if(pvh_hdrs_collected(msg)) { ++ LM_ERR("headers are already collected\n"); ++ return -1; + } + + if(parse_headers(msg, HDR_EOH_F, 0) < 0) { +@@ -63,38 +73,35 @@ int pvh_collect_headers(struct sip_msg *msg, int is_auto) + return -1; + } + +- if(pvh_str_new(&name, header_name_size) < 0) +- goto err; +- if(pvh_str_new(&val, header_value_size) < 0) +- goto err; +- +- if(name.s == NULL || val.s == NULL) +- goto err; +- + for(hf = msg->headers; hf; hf = hf->next) { + LM_DBG("collect header[%.*s]: %.*s\n", hf->name.len, hf->name.s, + hf->body.len, hf->body.s); + + switch(hf->type) { + case HDR_FROM_T: +- pvh_str_copy(&name, &_hdr_from, header_name_size); ++ name.len = _hdr_from.len; ++ name.s = _hdr_from.s; + LM_DBG("force [From] as key\n"); + break; + case HDR_TO_T: +- pvh_str_copy(&name, &_hdr_to, header_name_size); ++ name.len = _hdr_to.len; ++ name.s = _hdr_to.s; + LM_DBG("force [To] as key\n"); + break; + default: +- pvh_str_copy(&name, &hf->name, header_name_size); ++ name.len = hf->name.len; ++ name.s = hf->name.s; + } +- pvh_str_copy(&val, &hf->body, header_value_size); ++ val.len = hf->body.len; ++ val.s = hf->body.s; + +- if(str_hash_get(&split_headers, name.s, name.len) +- && strchr(val.s, ',') != NULL) { ++ if(strchr(val.s, ',') != NULL ++ && str_hash_get(&split_headers, name.s, name.len)) { + + if(pvh_split_values(&val, hvals, &d_size, 1) < 0) { +- LM_ERR("could not parse Diversion header comma separated " +- "value"); ++ LM_ERR("could not parse %.*s header comma separated " ++ "value", ++ name.len, name.s); + return -1; + } + +@@ -104,61 +111,43 @@ int pvh_collect_headers(struct sip_msg *msg, int is_auto) + if(pvh_set_xavp(msg, &xavp_name, &name, &val_part, SR_XTYPE_STR, + 0, 1) + < 0) +- goto err; ++ return -1; + } + continue; + } + if(pvh_set_xavp(msg, &xavp_name, &name, &val, SR_XTYPE_STR, 0, 1) < 0) +- goto err; ++ return -1; + } + + if(pvh_set_xavp(msg, &xavp_helper_xname, &xavp_helper_name, &xavp_name, + SR_XTYPE_STR, 0, 0) + < 0) +- goto err; +- +- pvh_str_free(&name); +- pvh_str_free(&val); ++ return -1; + +- msg->first_line.type == SIP_REPLY ? setflag(msg, FL_PV_HDRS_COLLECTED) +- : setbflag(br_idx, FL_PV_HDRS_COLLECTED); ++ pvh_hdrs_set_collected(msg); + + return 1; +- +-err: +- pvh_str_free(&name); +- pvh_str_free(&val); +- return -1; + } + +-int pvh_apply_headers(struct sip_msg *msg, int is_auto) ++int pvh_apply_headers(struct sip_msg *msg) + { + sr_xavp_t *xavp = NULL; + sr_xavp_t *sub = NULL; +- str display = STR_NULL; +- str uri = STR_NULL; + struct str_hash_table rm_hdrs; + int from_cnt = 0, to_cnt = 0; +- int skip_from_to = 0; +- int br_idx, keys_count; ++ char t[header_name_size]; ++ char tv[2][header_value_size]; ++ str display = {tv[0], header_value_size}; ++ str uri = {tv[1], header_value_size}; ++ str br_xname = {t, header_name_size}; ++ int skip_from_to = 0, keys_count = 0; + int res = -1; + +- rm_hdrs.size = 0; +- +- pvh_get_branch_index(msg, &br_idx); ++ memset(&rm_hdrs, 0, sizeof(struct str_hash_table)); + +- if(!is_auto) { +- if(msg->first_line.type == SIP_REPLY) { +- if(isflagset(msg, FL_PV_HDRS_APPLIED) == 1) { +- LM_ERR("headers are already applied\n"); +- return -1; +- } +- } else { +- if(isbflagset(br_idx, FL_PV_HDRS_APPLIED) == 1) { +- LM_ERR("headers are already applied\n"); +- return -1; +- } +- } ++ if(pvh_hdrs_applied(msg)) { ++ LM_ERR("headers are already applied\n"); ++ return -1; + } + + if(parse_headers(msg, HDR_EOH_F, 0) < 0) { +@@ -166,28 +155,30 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto) + return -1; + } + +- if(pvh_str_new(&display, header_value_size) < 0) +- goto err; +- if(pvh_str_new(&uri, header_value_size) < 0) +- goto err; ++ pvh_get_branch_xname(msg, &xavp_name, &br_xname); + +- if((xavp = pvh_xavp_get(msg, &xavp_name)) == NULL) { +- LM_ERR("missing xavp %.*s, run pv_collect_headers() first\n", +- xavp_name.len, xavp_name.s); +- goto err; ++ if((xavp = xavp_get(&br_xname, NULL)) == NULL ++ && (xavp = xavp_get(&xavp_name, NULL)) == NULL) { ++ LM_ERR("missing xavp %s, run pv_collect_headers() first\n", ++ xavp_name.s); ++ return -1; ++ } ++ if(xavp->val.type != SR_XTYPE_XAVP) { ++ LM_ERR("not xavp child type %s\n", xavp_name.s); ++ return -1; + } + + if((sub = xavp->val.v.xavp) == NULL) { + LM_ERR("invalid xavp structure: %s\n", xavp_name.s); +- goto err; ++ return -1; + } + keys_count = pvh_xavp_keys_count(&sub); + if(str_hash_alloc(&rm_hdrs, keys_count) < 0) { + PKG_MEM_ERROR; +- goto err; ++ return -1; + } +- LM_DBG("xavp->name:%.*s keys_count: %d\n", xavp->name.len, xavp->name.s, +- keys_count); ++ LM_DBG("xavp->name:%.*s br_xname:%.*s keys_count: %d\n", xavp->name.len, ++ xavp->name.s, br_xname.len, br_xname.s, keys_count); + str_hash_init(&rm_hdrs); + + if(msg->first_line.type == SIP_REPLY +@@ -207,13 +198,12 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto) + if(pvh_skip_header(&sub->name)) + continue; + +- if(strncasecmp(sub->name.s, _hdr_from.s, sub->name.len) == 0) { ++ if(cmpi_str(&sub->name, &_hdr_from) == 0) { + if(skip_from_to) { + LM_DBG("skip From header change in reply messages\n"); + continue; + } +- if(strncmp(sub->val.v.s.s, msg->from->body.s, sub->val.v.s.len) +- == 0) { ++ if(cmp_str(&sub->val.v.s, &msg->from->body) == 0) { + LM_DBG("skip unchanged From header\n"); + continue; + } +@@ -240,13 +230,12 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto) + continue; + } + +- if(strncasecmp(sub->name.s, _hdr_to.s, sub->name.len) == 0) { ++ if(cmpi_str(&sub->name, &_hdr_to) == 0) { + if(skip_from_to) { + LM_DBG("skip To header change in reply messages\n"); + continue; + } +- if(strncmp(sub->val.v.s.s, msg->to->body.s, sub->val.v.s.len) +- == 0) { ++ if(cmp_str(&sub->val.v.s, &msg->to->body) == 0) { + LM_DBG("skip unchanged To header\n"); + continue; + } +@@ -273,7 +262,7 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto) + continue; + } + +- if(strncasecmp(sub->name.s, "@Reply-Reason", sub->name.len) == 0) { ++ if(cmpi_str(&sub->name, &_hdr_reply_reason) == 0) { + if(str_hash_get(&rm_hdrs, sub->name.s, sub->name.len)) + continue; + pvh_real_replace_reply_reason(msg, &sub->val.v.s); +@@ -299,14 +288,11 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto) + } + } while((sub = sub->next) != NULL); + +- msg->first_line.type == SIP_REPLY ? setflag(msg, FL_PV_HDRS_APPLIED) +- : setbflag(br_idx, FL_PV_HDRS_APPLIED); ++ pvh_hdrs_set_applied(msg); + + res = 1; + + err: +- pvh_str_free(&display); +- pvh_str_free(&uri); + if(rm_hdrs.size) + pvh_str_hash_free(&rm_hdrs); + return res; +@@ -314,29 +300,17 @@ err: + + int pvh_reset_headers(struct sip_msg *msg) + { +- str br_xname = STR_NULL; +- int br_idx; ++ char t[header_name_size]; ++ str br_xname = {t, header_name_size}; + +- if(pvh_str_new(&br_xname, header_name_size) < 0) +- return -1; +- +- pvh_get_branch_index(msg, &br_idx); + pvh_get_branch_xname(msg, &xavp_name, &br_xname); +- /* LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s); */ ++ LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s); + pvh_free_xavp(&br_xname); + pvh_get_branch_xname(msg, &xavp_parsed_xname, &br_xname); +- /* LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s); */ ++ LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s); + pvh_free_xavp(&br_xname); + +- if(msg->first_line.type == SIP_REPLY) { +- resetflag(msg, FL_PV_HDRS_COLLECTED); +- resetflag(msg, FL_PV_HDRS_APPLIED); +- } else { +- resetbflag(br_idx, FL_PV_HDRS_COLLECTED); +- resetbflag(br_idx, FL_PV_HDRS_APPLIED); +- } +- +- pvh_str_free(&br_xname); ++ pvh_hdrs_reset_flags(msg); + + return 1; + } +diff --git a/src/modules/pv_headers/pvh_func.h b/src/modules/pv_headers/pvh_func.h +index 0fe5524..6aaf5aa 100644 +--- a/src/modules/pv_headers/pvh_func.h ++++ b/src/modules/pv_headers/pvh_func.h +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +@@ -26,8 +28,10 @@ + + #include "../../core/parser/msg_parser.h" + +-int pvh_collect_headers(struct sip_msg *msg, int is_auto); +-int pvh_apply_headers(struct sip_msg *msg, int is_auto); ++int pvh_parse_msg(sip_msg_t *msg); ++ ++int pvh_collect_headers(struct sip_msg *msg); ++int pvh_apply_headers(struct sip_msg *msg); + int pvh_reset_headers(struct sip_msg *msg); + + int pvh_check_header(struct sip_msg *msg, str *hname); +diff --git a/src/modules/pv_headers/pvh_hash.c b/src/modules/pv_headers/pvh_hash.c +index f269868..6c99c43 100644 +--- a/src/modules/pv_headers/pvh_hash.c ++++ b/src/modules/pv_headers/pvh_hash.c +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +diff --git a/src/modules/pv_headers/pvh_hash.h b/src/modules/pv_headers/pvh_hash.h +index 8828cc6..d7e25f8 100644 +--- a/src/modules/pv_headers/pvh_hash.h ++++ b/src/modules/pv_headers/pvh_hash.h +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +diff --git a/src/modules/pv_headers/pvh_hdr.c b/src/modules/pv_headers/pvh_hdr.c +index 70be9ac..d83a646 100644 +--- a/src/modules/pv_headers/pvh_hdr.c ++++ b/src/modules/pv_headers/pvh_hdr.c +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +@@ -22,15 +24,73 @@ + */ + + #include "../../core/data_lump.h" ++#include "../../core/dset.h" + + #include "pvh_hdr.h" + ++int pvh_hdrs_collected(struct sip_msg *msg) ++{ ++ if(msg->first_line.type == SIP_REPLY) { ++ if(isflagset(msg, FL_PV_HDRS_COLLECTED) == 1) { ++ return 1; ++ } ++ } else { ++ if(isbflagset(_branch, FL_PV_HDRS_COLLECTED) == 1) { ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++int pvh_hdrs_applied(struct sip_msg *msg) ++{ ++ if(msg->first_line.type == SIP_REPLY) { ++ if(isflagset(msg, FL_PV_HDRS_APPLIED) == 1) { ++ return 1; ++ } ++ } else { ++ if(isbflagset(_branch, FL_PV_HDRS_APPLIED) == 1) { ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++void pvh_hdrs_set_applied(struct sip_msg *msg) ++{ ++ if(msg->first_line.type == SIP_REPLY) { ++ setflag(msg, FL_PV_HDRS_APPLIED); ++ } else { ++ setbflag(_branch, FL_PV_HDRS_APPLIED); ++ } ++} ++ ++void pvh_hdrs_set_collected(struct sip_msg *msg) ++{ ++ if(msg->first_line.type == SIP_REPLY) { ++ setflag(msg, FL_PV_HDRS_COLLECTED); ++ } else { ++ setbflag(_branch, FL_PV_HDRS_COLLECTED); ++ } ++} ++ ++void pvh_hdrs_reset_flags(struct sip_msg *msg) ++{ ++ if(msg->first_line.type == SIP_REPLY) { ++ resetflag(msg, FL_PV_HDRS_COLLECTED); ++ resetflag(msg, FL_PV_HDRS_APPLIED); ++ } else { ++ resetbflag(_branch, FL_PV_HDRS_COLLECTED); ++ resetbflag(_branch, FL_PV_HDRS_APPLIED); ++ } ++} ++ + int pvh_real_hdr_append(struct sip_msg *msg, str *hname, str *hvalue) + { + struct lump *anchor = NULL; + hdr_field_t *hf = NULL; + hdr_field_t *m_hf = NULL; +- str new_h; ++ str new_h = STR_NULL; + + if(hname->s == NULL || hvalue->s == NULL) { + LM_ERR("header name/value cannot be empty"); +@@ -75,7 +135,7 @@ int pvh_real_hdr_replace(struct sip_msg *msg, str *hname, str *hvalue) + { + struct lump *anchor = NULL; + hdr_field_t *hf = NULL; +- str new_h; ++ str new_h = STR_NULL; + int new = 1; + + if(hname->s == NULL || hvalue->s == NULL) { +diff --git a/src/modules/pv_headers/pvh_hdr.h b/src/modules/pv_headers/pvh_hdr.h +index f05d7e4..4f86953 100644 +--- a/src/modules/pv_headers/pvh_hdr.h ++++ b/src/modules/pv_headers/pvh_hdr.h +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +@@ -29,6 +31,12 @@ + + #include "pv_headers.h" + ++int pvh_hdrs_collected(struct sip_msg *msg); ++int pvh_hdrs_applied(struct sip_msg *msg); ++void pvh_hdrs_set_collected(struct sip_msg *msg); ++void pvh_hdrs_set_applied(struct sip_msg *msg); ++void pvh_hdrs_reset_flags(struct sip_msg *msg); ++ + int pvh_real_hdr_append(struct sip_msg *msg, str *hname, str *hvalue); + int pvh_real_hdr_replace(struct sip_msg *msg, str *hname, str *hvalue); + int pvh_real_hdr_del_by_name(struct sip_msg *msg, str *hname); +diff --git a/src/modules/pv_headers/pvh_str.c b/src/modules/pv_headers/pvh_str.c +index 53e2c9c..6ede032 100644 +--- a/src/modules/pv_headers/pvh_str.c ++++ b/src/modules/pv_headers/pvh_str.c +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +diff --git a/src/modules/pv_headers/pvh_str.h b/src/modules/pv_headers/pvh_str.h +index 95aa0b9..10aa216 100644 +--- a/src/modules/pv_headers/pvh_str.h ++++ b/src/modules/pv_headers/pvh_str.h +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +diff --git a/src/modules/pv_headers/pvh_xavp.c b/src/modules/pv_headers/pvh_xavp.c +index db2192c..0cfd969 100644 +--- a/src/modules/pv_headers/pvh_xavp.c ++++ b/src/modules/pv_headers/pvh_xavp.c +@@ -1,17 +1,18 @@ + /* ++ * pv_headers + * +- * PV Headers ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * Copyright (C) 2018 Kirill Solomko ++ * This file is part of Kamailio, a free SIP server. + * +- * This file is part of SIP Router, a free SIP server. +- * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +@@ -22,15 +23,75 @@ + * + */ + +-#include +- +-#include "../../core/hashes.h" +-#include "../../core/route_struct.h" ++#include "../../core/parser/parse_uri.h" + #include "../../core/strutils.h" + + #include "pvh_xavp.h" + #include "pvh_str.h" + #include "pvh_hash.h" ++#include "pvh_hdr.h" ++ ++static str reply_counter = str_init("reply_counter"); ++ ++sr_xavp_t *pvh_xavp_get_child_with_ival( ++ str *rname, str *cname, sr_xavp_t *start) ++{ ++ sr_xavp_t *ravp = NULL; ++ sr_xavp_t *vavp = NULL; ++ ++ ravp = xavp_get(rname, start); ++ if(ravp == NULL || ravp->val.type != SR_XTYPE_XAVP) ++ return NULL; ++ ++ vavp = xavp_get(cname, ravp->val.v.xavp); ++ if(vavp == NULL || vavp->val.type != SR_XTYPE_INT) ++ return NULL; ++ ++ return vavp; ++} ++ ++/** ++ * We keep a $xavp(xavp_helper_xname=>reply_counter) with the number of replies ++ * so we will use $xavp(xavp_name.r.) on reply_route ++ */ ++int pvh_reply_append(sr_xavp_t **start) ++{ ++ sr_xavp_t *xavp = NULL; ++ sr_xval_t xval; ++ ++ xavp = pvh_xavp_get_child_with_ival( ++ &xavp_helper_xname, &reply_counter, start ? *start : NULL); ++ if(xavp) { ++ xavp->val.v.i++; ++ LM_DBG("reply message: %d\n", xavp->val.v.i); ++ return xavp->val.v.i; ++ } ++ ++ memset(&xval, 0, sizeof(sr_xval_t)); ++ xval.type = SR_XTYPE_INT; ++ xval.v.i = 0; ++ ++ xavp = xavp_get(&xavp_helper_xname, start ? *start : NULL); ++ if(xavp == NULL) { ++ if(xavp_add_xavp_value(&xavp_helper_xname, &reply_counter, &xval, ++ start ? start : NULL) ++ == NULL) { ++ LM_ERR("can't create xavp:%.*s\n", xavp_helper_xname.len, ++ xavp_helper_xname.s); ++ return -1; ++ } ++ LM_DBG("xavp_name:%.*s created\n", xavp_helper_xname.len, ++ xavp_helper_xname.s); ++ } else { ++ if(xavp_add_value(&reply_counter, &xval, &xavp->val.v.xavp) == NULL) { ++ LM_ERR("can't add reply_counter value\n"); ++ return -1; ++ } ++ LM_DBG("added value\n"); ++ } ++ LM_DBG("reply message: %d\n", xval.v.i); ++ return xval.v.i; ++} + + sr_xavp_t *pvh_xavp_new_value(str *name, sr_xval_t *val) + { +@@ -109,10 +170,8 @@ int pvh_xavp_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start) + sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname) + { + sr_xavp_t *xavp = NULL; +- str br_xname = STR_NULL; +- +- if(pvh_str_new(&br_xname, header_name_size) < 0) +- return NULL; ++ char t[header_name_size]; ++ str br_xname = {t, header_name_size}; + + pvh_get_branch_xname(msg, xname, &br_xname); + if((xavp = xavp_get(&br_xname, NULL)) == NULL) { +@@ -120,8 +179,10 @@ sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname) + goto end; + if((xavp = xavp_get(xname, NULL)) == NULL) + goto end; +- /* LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n", br_xname.len, +- br_xname.s, xname->len, xname->s); */ ++ if(xname != &xavp_parsed_xname) { ++ LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n", ++ br_xname.len, br_xname.s, xname->len, xname->s); ++ } + } + + if(xavp->val.type != SR_XTYPE_XAVP) { +@@ -131,10 +192,68 @@ sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname) + } + + end: +- pvh_str_free(&br_xname); + return xavp; + } + ++int pvh_free_xavp(str *xname) ++{ ++ sr_xavp_t *xavp = NULL; ++ xavp_rm_by_name(xname, 1, NULL); ++ if((xavp = xavp_get(xname, NULL)) != NULL) ++ xavp_rm(xavp, NULL); ++ return 1; ++} ++ ++void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree) ++{ ++ struct to_param *n = NULL; ++ ++ while(param) { ++ n = param->next; ++ sfree(param); ++ param = n; ++ } ++ param = NULL; ++} ++ ++int pvh_parse_header_name(pv_spec_p sp, str *hname) ++{ ++ pv_spec_p psp = NULL; ++ ++ if(hname->s == NULL || hname->len == 0) { ++ LM_ERR("empty header name\n"); ++ return -1; ++ } ++ ++ if(hname->len >= header_name_size) { ++ LM_ERR("header name is too long\n"); ++ return -1; ++ } ++ ++ if(*hname->s == PV_MARKER) { ++ psp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t)); ++ if(psp == NULL) { ++ PKG_MEM_ERROR; ++ return -1; ++ } ++ if(pv_parse_spec(hname, psp) == NULL) { ++ LM_ERR("invalid avp name [%.*s]\n", hname->len, hname->s); ++ pv_spec_free(psp); ++ return -1; ++ } ++ sp->pvp.pvn.type = PV_NAME_PVAR; ++ sp->pvp.pvn.u.dname = (void *)psp; ++ sp->pvp.pvn.u.isname.name.s = *hname; ++ return 0; ++ } ++ ++ sp->pvp.pvn.type = PV_NAME_INTSTR; ++ sp->pvp.pvn.u.isname.type = AVP_NAME_STR; ++ sp->pvp.pvn.u.isname.name.s = *hname; ++ ++ return 0; ++} ++ + sr_xval_t *pvh_xavp_get_value( + struct sip_msg *msg, str *xname, str *name, int idx) + { +@@ -153,25 +272,20 @@ sr_xval_t *pvh_xavp_get_value( + sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name) + { + sr_xavp_t *xavp = NULL; +- str br_xname = STR_NULL; +- +- if(pvh_str_new(&br_xname, header_name_size) < 0) +- return NULL; ++ char t[header_name_size]; ++ str br_xname = {t, header_name_size}; + + pvh_get_branch_xname(msg, xname, &br_xname); + xavp = xavp_get_child(&br_xname, name); + if(xavp == NULL) { + if(cmp_str(xname, &br_xname) != 0) { + xavp = xavp_get_child(xname, name); +- /* + if(xavp) { + LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n", +- br_xname.len, br_xname.s, xname->len, xname->s); +- } */ ++ br_xname.len, br_xname.s, xname->len, xname->s); ++ } + } + } +- +- pvh_str_free(&br_xname); + return xavp; + } + +@@ -220,56 +334,6 @@ int pvh_xavp_keys_count(sr_xavp_t **start) + return cnt; + } + +-void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree) +-{ +- struct to_param *n = NULL; +- +- while(param) { +- n = param->next; +- sfree(param); +- param = n; +- } +- param = NULL; +-} +- +-int pvh_parse_header_name(pv_spec_p sp, str *hname) +-{ +- pv_spec_p psp = NULL; +- +- if(hname->s == NULL || hname->len == 0) { +- LM_ERR("empty header name\n"); +- return -1; +- } +- +- if(hname->len >= header_name_size) { +- LM_ERR("header name is too long\n"); +- return -1; +- } +- +- if(*hname->s == PV_MARKER) { +- psp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t)); +- if(psp == NULL) { +- PKG_MEM_ERROR; +- return -1; +- } +- if(pv_parse_spec(hname, psp) == NULL) { +- LM_ERR("invalid avp name [%.*s]\n", hname->len, hname->s); +- pv_spec_free(psp); +- return -1; +- } +- sp->pvp.pvn.type = PV_NAME_PVAR; +- sp->pvp.pvn.u.dname = (void *)psp; +- sp->pvp.pvn.u.isname.name.s = *hname; +- return 0; +- } +- +- sp->pvp.pvn.type = PV_NAME_INTSTR; +- sp->pvp.pvn.u.isname.type = AVP_NAME_STR; +- sp->pvp.pvn.u.isname.name.s = *hname; +- +- return 0; +-} +- + int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, + sr_xtype_t type, int idx, int append) + { +@@ -277,17 +341,14 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, + sr_xavp_t *root = NULL; + sr_xval_t root_xval; + sr_xval_t xval; +- str br_xname = STR_NULL; +- int br_idx; ++ char t[header_name_size]; ++ str br_xname = {t, header_name_size}; + + if(xname == NULL || name == NULL) { + LM_ERR("missing xavp/pv name\n"); + return -1; + } + +- pvh_get_branch_index(msg, &br_idx); +- if(pvh_str_new(&br_xname, header_name_size) < 0) +- return -1; + pvh_get_branch_xname(msg, xname, &br_xname); + LM_DBG("br_xname: %.*s name: %.*s\n", br_xname.len, br_xname.s, name->len, + name->s); +@@ -302,7 +363,7 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, + xval.v.data = (sr_data_t *)shm_malloc(sizeof(sr_data_t)); + if(xval.v.data == NULL) { + SHM_MEM_ERROR; +- goto err; ++ return -1; + } + memset(xval.v.data, 0, sizeof(sr_data_t)); + xval.v.data->p = data; +@@ -311,10 +372,8 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, + + root = xavp_get(&br_xname, NULL); + +- if(root == NULL && br_idx > 0) { +- LM_DBG("clone xavp:%.*s br_xname:%.*s\n", xname->len, xname->s, +- br_xname.len, br_xname.s); +- pvh_clone_branch_xavp(msg, xname, &br_xname); ++ if(root == NULL && _branch > 0) { ++ pvh_clone_branch_xavp(msg, xname); + root = xavp_get(&br_xname, NULL); + } + +@@ -328,7 +387,7 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, + + if((root = xavp_add_value(&br_xname, &root_xval, NULL)) == NULL) { + LM_ERR("error create xavp %s\n", br_xname.s); +- goto err; ++ return -1; + } + xavp = &root->val.v.xavp; + } else if(xavp_get_child(&br_xname, name) == NULL) { +@@ -339,30 +398,16 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, + if(pvh_xavp_append_value(name, &xval, xavp) < 0) { + LM_ERR("error append xavp=>name %s=>%.*s\n", br_xname.s, name->len, + name->s); +- goto err; ++ return -1; + } + } else { + if(pvh_xavp_set_value(name, &xval, idx, xavp) < 0) { + LM_ERR("error modify xavp=>name %s=>%.*s idx=%d\n", br_xname.s, + name->len, name->s, idx); +- goto err; ++ return -1; + } + } + +- pvh_str_free(&br_xname); +- return 1; +- +-err: +- pvh_str_free(&br_xname); +- return -1; +-} +- +-int pvh_free_xavp(str *xname) +-{ +- sr_xavp_t *xavp = NULL; +- xavp_rm_by_name(xname, 1, NULL); +- if((xavp = xavp_get(xname, NULL)) != NULL) +- xavp_rm(xavp, NULL); + return 1; + } + +@@ -394,7 +439,6 @@ int pvh_get_branch_index(struct sip_msg *msg, int *br_idx) + + int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst) + { +- int br_idx; + int os = 0; + char br_idx_s[32]; + char br_idx_len = 0; +@@ -406,9 +450,8 @@ int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst) + memcpy(dst->s, xname->s, xname->len); + os += xname->len; + +- pvh_get_branch_index(msg, &br_idx); +- if(br_idx > 0) { +- sprintf(br_idx_s, "%d", br_idx - 1); ++ if(_branch > 0) { ++ snprintf(br_idx_s, 32, "%d", _branch - 1); + br_idx_len = strlen(br_idx_s); + memcpy(dst->s + os, ".", 1); + os += 1; +@@ -416,8 +459,10 @@ int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst) + os += br_idx_len; + } + if(msg->first_line.type == SIP_REPLY) { +- memcpy(dst->s + os, ".r", 2); +- os += 2; ++ snprintf(br_idx_s, 32, ".r.%d", _reply_counter); ++ br_idx_len = strlen(br_idx_s); ++ memcpy(dst->s + os, br_idx_s, br_idx_len); ++ os += br_idx_len; + } + dst->len = os; + dst->s[dst->len] = '\0'; +@@ -425,12 +470,15 @@ int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst) + return 1; + } + +-int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname) ++int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname) + { + sr_xavp_t *xavp = NULL; + sr_xavp_t *br_xavp = NULL; + sr_xavp_t *sub = NULL; + sr_xval_t root_xval; ++ char t[header_name_size]; ++ str br_xname = {t, header_name_size}; ++ int i = 0; + + if((xavp = xavp_get(xname, NULL)) == NULL) { + LM_ERR("cannot clone xavp from non existing %s\n", xname->s); +@@ -447,17 +495,18 @@ int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname) + return -1; + } + ++ pvh_get_branch_xname(msg, xname, &br_xname); ++ + memset(&root_xval, 0, sizeof(sr_xval_t)); + root_xval.type = SR_XTYPE_XAVP; + root_xval.v.xavp = NULL; + +- if((br_xavp = xavp_add_value(br_xname, &root_xval, NULL)) == NULL) { +- LM_ERR("error create xavp %s\n", br_xname->s); ++ if((br_xavp = xavp_add_value(&br_xname, &root_xval, NULL)) == NULL) { ++ LM_ERR("error create xavp %s\n", br_xname.s); + return -1; + } + +- if(strncmp(xname->s, xavp_parsed_xname.s, xname->len) == 0) { +- LM_DBG("skip clone\n"); ++ if(cmp_str(xname, &xavp_parsed_xname) == 0) { + return 1; + } + +@@ -471,8 +520,10 @@ int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname) + LM_ERR("cannot clone xavp %s\n", sub->name.s); + return -1; + } ++ ++i; + } while((sub = sub->next) != NULL); +- ++ LM_DBG("cloned %.*s[%d] => %.*s\n", xname->len, xname->s, i, br_xname.len, ++ br_xname.s); + return 1; + } + +@@ -663,12 +714,10 @@ int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) + str sval = STR_NULL; + int ival = 0; + int is_strint = 0; +- str hname = STR_NULL; ++ char t[header_name_size]; ++ str hname = {t, header_name_size - 1}; + + p_no = param->pvn.u.isname.name.n; +- if(pvh_str_new(&hname, header_name_size) < 0) +- goto err; +- + if(p_no >= 1 && p_no <= 5) + pvh_str_copy(&hname, &_hdr_from, header_name_size); + else if(p_no >= 6 && p_no <= 10) +@@ -689,8 +738,7 @@ int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) + c_data = (xavp_c_data_t *)xval_pd->v.data->p; + } + +- if(c_data != NULL +- && strncmp(xval->v.s.s, c_data->value.s, c_data->value.len) != 0) { ++ if(c_data != NULL && cmp_str(&xval->v.s, &c_data->value) != 0) { + /* LM_DBG("xval:%.*s != c_data->value:%.*s\n", xval->v.s.len, xval->v.s.s, + c_data->value.len, c_data->value.s); */ + c_data = NULL; +@@ -726,13 +774,11 @@ int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) + LM_ERR("unknown get uri op\n"); + } + /* LM_DBG("p_no:%d sval:%.*s\n", p_no, sval.len, sval.s); */ +- pvh_str_free(&hname); + return sval.s ? is_strint ? pv_get_strintval(msg, param, res, &sval, ival) + : pv_get_strval(msg, param, res, &sval) + : pv_get_null(msg, param, res); + + err: +- pvh_str_free(&hname); + return pv_get_null(msg, param, res); + } + +@@ -743,12 +789,11 @@ int pvh_set_uri(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) + pv_elem_p pv_format = NULL; + int p_no = 0; + enum action_type a_type; +- str hname; ++ char t[header_name_size]; ++ str hname = {t, header_name_size - 1}; + str fval; + + p_no = param->pvn.u.isname.name.n; +- if(pvh_str_new(&hname, header_name_size) < 0) +- goto err; + if(p_no >= 1 && p_no <= 5) + pvh_str_copy(&hname, &_hdr_from, header_name_size); + else if(p_no >= 6 && p_no <= 10) +@@ -814,13 +859,11 @@ int pvh_set_uri(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) + < 0) + goto err; + +- pvh_str_free(&hname); + if(pv_format) + pv_elem_free_all(pv_format); + return 1; + + err: +- pvh_str_free(&hname); + if(pv_format) + pv_elem_free_all(pv_format); + return -1; +@@ -986,7 +1029,6 @@ int pvh_get_reply_sr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) + { + sr_xval_t *xval = NULL; + int p_no = 0; +- str rhname = {"@Reply-Reason", 13}; + + p_no = param->pvn.u.isname.name.n; + +@@ -1000,7 +1042,7 @@ int pvh_get_reply_sr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) + &msg->first_line.u.reply.status); + break; + case 2: // reason +- xval = pvh_xavp_get_value(msg, &xavp_name, &rhname, 0); ++ xval = pvh_xavp_get_value(msg, &xavp_name, &_hdr_reply_reason, 0); + return pv_get_strval(msg, param, res, + xval && xval->v.s.s ? &xval->v.s + : &msg->first_line.u.reply.reason); +@@ -1018,7 +1060,6 @@ int pvh_set_reply_sr( + pv_elem_p pv_format = NULL; + int p_no = 0; + unsigned int code = 0; +- str rhname = {"@Reply-Reason", 13}; + str fval; + + p_no = param->pvn.u.isname.name.n; +@@ -1069,7 +1110,8 @@ int pvh_set_reply_sr( + msg->first_line.u.reply.status.s[0] = code + '0'; + break; + case 2: // reason +- if(pvh_set_xavp(msg, &xavp_name, &rhname, &fval, SR_XTYPE_STR, 0, 0) ++ if(pvh_set_xavp(msg, &xavp_name, &_hdr_reply_reason, &fval, ++ SR_XTYPE_STR, 0, 0) + < 0) { + LM_ERR("set reply: cannot set reply reason\n"); + goto err; +diff --git a/src/modules/pv_headers/pvh_xavp.h b/src/modules/pv_headers/pvh_xavp.h +index d9e9299..7d4aa30 100644 +--- a/src/modules/pv_headers/pvh_xavp.h ++++ b/src/modules/pv_headers/pvh_xavp.h +@@ -1,16 +1,18 @@ + /* +- * PV Headers ++ * pv_headers + * +- * Copyright (C) 2018 Kirill Solomko ++ * Copyright (C) ++ * 2020 Victor Seva ++ * 2018 Kirill Solomko + * +- * This file is part of SIP Router, a free SIP server. ++ * This file is part of Kamailio, a free SIP server. + * +- * SIP Router is free software; you can redistribute it and/or modify ++ * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * +- * SIP Router is distributed in the hope that it will be useful, ++ * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +@@ -24,44 +26,41 @@ + #ifndef PV_XAVP_H + #define PV_XAVP_H + +-#include "../../core/parser/parse_uri.h" ++#include "../../core/str.h" + #include "../../core/xavp.h" +-#include "../../core/pvar.h" + + #include "pv_headers.h" + +-sr_xavp_t *pvh_xavp_new_value(str *name, sr_xval_t *val); +-int pvh_xavp_append_value(str *name, sr_xval_t *val, sr_xavp_t **start); +-int pvh_xavp_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start); +-sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname); +-sr_xval_t *pvh_xavp_get_value( +- struct sip_msg *msg, str *xname, str *name, int idx); +-sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name); +-int pvh_xavp_is_null(sr_xavp_t *xavp); +-void pvh_xavp_free_data(void *p, sr_xavp_sfree_f sfree); +-int pvh_xavp_keys_count(sr_xavp_t **start); +-void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree); ++int pvh_reply_append(sr_xavp_t **start); ++ + int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, + sr_xtype_t type, int idx, int append); + int pvh_free_xavp(str *xname); +-int pvh_parse_header_name(pv_spec_p sp, str *hname); ++int pvh_xavp_is_null(sr_xavp_t *avp); ++int pvh_xavp_keys_count(sr_xavp_t **start); ++sr_xval_t *pvh_xavp_get_value( ++ struct sip_msg *msg, str *xname, str *name, int idx); ++sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name); + ++int pvh_get_branch_index(struct sip_msg *msg, int *br_idx); ++int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst); ++int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname); ++ ++int pvh_parse_header_name(pv_spec_p sp, str *hname); + int pvh_get_header(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); + int pvh_set_header( + struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val); + xavp_c_data_t *pvh_set_parsed( + struct sip_msg *msg, str *hname, str *cur, str *new); +-int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); ++ + int pvh_set_uri( + struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val); ++int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); + int pvh_merge_uri(struct sip_msg *msg, enum action_type type, str *cur, + str *new, xavp_c_data_t *c_data); ++ + int pvh_get_reply_sr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); + int pvh_set_reply_sr( + struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val); + +-int pvh_get_branch_index(struct sip_msg *msg, int *br_idx); +-int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst); +-int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname); +- + #endif /* PV_XAVP_H */