From 68064ab3c4e38afe0144ea57589e5e89ba6d74a1 Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Wed, 27 May 2020 09:27:35 +0200 Subject: [PATCH] TT#81803 pv_headers use $xavi instead of $xavp Change-Id: If1f3a4dc82435e7c071238bfaf6921dc20b62d02 --- debian/patches/series | 6 +- .../sipwise/add_pv_headers_module.patch | 825 ++++------ ...et-xavi-list-after-message-processin.patch | 18 + ...ke-xavp-but-with-insensitive-case-na.patch | 1152 ++++++++++++++ .../upstream/pv-define-xavi-types.patch | 23 + ...vi-.-config-variables-implementation.patch | 1389 +++++++++++++++++ ...ss-xavi-list-in-transaction-contexts.patch | 205 +++ 7 files changed, 3125 insertions(+), 493 deletions(-) create mode 100644 debian/patches/upstream/core-receive-reset-xavi-list-after-message-processin.patch create mode 100644 debian/patches/upstream/core-xavi-api-like-xavp-but-with-insensitive-case-na.patch create mode 100644 debian/patches/upstream/pv-define-xavi-types.patch create mode 100644 debian/patches/upstream/pv-xavi-.-config-variables-implementation.patch create mode 100644 debian/patches/upstream/tm-process-xavi-list-in-transaction-contexts.patch diff --git a/debian/patches/series b/debian/patches/series index 64537f3b7..33cbf4a8f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -15,7 +15,6 @@ sipwise/fix_lcr_rate_wrong_id.patch sipwise/add_tcap_module.patch sipwise/add_presence_dfks_module.patch sipwise/presence_dfks_null_ptr_fixes.patch -# ** https://github.com/kamailio/kamailio/pull/2156 sipwise/add_pv_headers_module.patch ## General Patches sipwise/usrloc_dbro.patch @@ -66,6 +65,11 @@ upstream/cfgt-fix-implicit-declaration-of-strcasestr.patch upstream/core-str-helper-macro-to-set-ending-zero-with-backup.patch upstream/core-str-fixed-wrong-undo-ed-version-of-STR_ZTOV-mac.patch upstream/jansson-use-the-core-macros-for-ending-string-value-.patch +upstream/core-xavi-api-like-xavp-but-with-insensitive-case-na.patch +upstream/pv-define-xavi-types.patch +upstream/core-receive-reset-xavi-list-after-message-processin.patch +upstream/tm-process-xavi-list-in-transaction-contexts.patch +upstream/pv-xavi-.-config-variables-implementation.patch ## backport from kamailio trunk (5.3) # ### relevant for upstream diff --git a/debian/patches/sipwise/add_pv_headers_module.patch b/debian/patches/sipwise/add_pv_headers_module.patch index 2c701991e..7c9709682 100644 --- a/debian/patches/sipwise/add_pv_headers_module.patch +++ b/debian/patches/sipwise/add_pv_headers_module.patch @@ -5,25 +5,25 @@ Subject: add_pv_headers_module --- src/Makefile.groups | 3 +- src/modules/pv_headers/Makefile | 12 + - src/modules/pv_headers/README | 337 ++++++ + src/modules/pv_headers/README | 337 +++++++ src/modules/pv_headers/doc/Makefile | 4 + src/modules/pv_headers/doc/functions.xml | 131 +++ src/modules/pv_headers/doc/params.xml | 186 ++++ src/modules/pv_headers/doc/pv_headers.xml | 39 + - src/modules/pv_headers/doc/pv_headers_admin.xml | 116 ++ - src/modules/pv_headers/pv_headers.c | 519 +++++++++ - src/modules/pv_headers/pv_headers.h | 57 + - src/modules/pv_headers/pvh_func.c | 360 ++++++ + src/modules/pv_headers/doc/pv_headers_admin.xml | 116 +++ + src/modules/pv_headers/pv_headers.c | 548 +++++++++++ + src/modules/pv_headers/pv_headers.h | 57 ++ + src/modules/pv_headers/pvh_func.c | 360 +++++++ src/modules/pv_headers/pvh_func.h | 42 + src/modules/pv_headers/pvh_hash.c | 134 +++ src/modules/pv_headers/pvh_hash.h | 41 + - src/modules/pv_headers/pvh_hdr.c | 295 +++++ + src/modules/pv_headers/pvh_hdr.c | 295 ++++++ src/modules/pv_headers/pvh_hdr.h | 47 + src/modules/pv_headers/pvh_str.c | 146 +++ src/modules/pv_headers/pvh_str.h | 40 + - src/modules/pv_headers/pvh_xavp.c | 1355 +++++++++++++++++++++++ - src/modules/pv_headers/pvh_xavp.h | 69 ++ - 20 files changed, 3932 insertions(+), 1 deletion(-) + src/modules/pv_headers/pvh_xavp.c | 1173 +++++++++++++++++++++++ + src/modules/pv_headers/pvh_xavp.h | 63 ++ + 20 files changed, 3773 insertions(+), 1 deletion(-) create mode 100644 src/modules/pv_headers/Makefile create mode 100644 src/modules/pv_headers/README create mode 100644 src/modules/pv_headers/doc/Makefile @@ -78,7 +78,7 @@ index 0000000..42b80dd +include ../../Makefile.modules diff --git a/src/modules/pv_headers/README b/src/modules/pv_headers/README new file mode 100644 -index 0000000..1967529 +index 0000000..f637eb2 --- /dev/null +++ b/src/modules/pv_headers/README @@ -0,0 +1,337 @@ @@ -111,7 +111,7 @@ index 0000000..1967529 + + 3. Parameters + -+ 3.1. xavp_name (string) ++ 3.1. xavi_name (string) + 3.2. header_value_size (int) + 3.3. header_collect_flag (int) + 3.4. header_apply_flag (int) @@ -133,7 +133,7 @@ index 0000000..1967529 + + List of Examples + -+ 1.1. Set xavp_name parameter ++ 1.1. Set xavi_name parameter + 1.2. Set header_value_size parameter + 1.3. Set header_collect_flag parameter + 1.4. Set header_apply_flag parameter @@ -153,7 +153,7 @@ index 0000000..1967529 + + 3. Parameters + -+ 3.1. xavp_name (string) ++ 3.1. xavi_name (string) + 3.2. header_value_size (int) + 3.3. header_collect_flag (int) + 3.4. header_apply_flag (int) @@ -176,7 +176,7 @@ index 0000000..1967529 +1. Overview + + The main goal of the module is to offload the intermediate header -+ processing into the XAVP dynamic container as well as provide with high ++ processing into the XAVI dynamic container as well as provide with high + level methods and pseudovariables to simplify SIP message header + modifications. + @@ -200,7 +200,7 @@ index 0000000..1967529 + +3. Parameters + -+ 3.1. xavp_name (string) ++ 3.1. xavi_name (string) + 3.2. header_value_size (int) + 3.3. header_collect_flag (int) + 3.4. header_apply_flag (int) @@ -208,19 +208,19 @@ index 0000000..1967529 + 3.6. split_headers (string) + 3.7. auto_msg (int) + -+3.1. xavp_name (string) ++3.1. xavi_name (string) + -+ Name of the XAVP there the collected headers are stored. ++ Name of the XAVI where the collected headers are stored. + + Default value is "headers". + -+ Example 1.1. Set xavp_name parameter ++ Example 1.1. Set xavi_name parameter +... -+modparam("pv_headers", "xavp_name", "pvh") ++modparam("pv_headers", "xavi_name", "headers") +... + -+ Result: $xavp(headers[0]=>From) $xavp(headers[0]=>To) -+ $xavp(headers[0]=>Call-ID) ++ Result: $xavi(headers[0]=>From) $xavi(headers[0]=>To) ++ $xavi(headers[0]=>Call-ID) + +3.2. header_value_size (int) + @@ -312,7 +312,7 @@ index 0000000..1967529 + + Example 1.7. Set auto_msg parameter +... -+modparam("pvh", "auto_msg", 1) ++modparam("pv_headers", "auto_msg", 1) +... + +4. Functions @@ -568,7 +568,7 @@ index 0000000..ef7f133 + diff --git a/src/modules/pv_headers/doc/params.xml b/src/modules/pv_headers/doc/params.xml new file mode 100644 -index 0000000..83e74d6 +index 0000000..2bc6ddc --- /dev/null +++ b/src/modules/pv_headers/doc/params.xml @@ -0,0 +1,186 @@ @@ -587,10 +587,10 @@ index 0000000..83e74d6 + + + Parameters -+
-+ <varname>xavp_name</varname> (string) ++
++ <varname>xavi_name</varname> (string) + -+ Name of the XAVP there the collected headers are stored. ++ Name of the XAVI where the collected headers are stored. + + + @@ -598,24 +598,24 @@ index 0000000..83e74d6 + + + -+ Set <varname>xavp_name</varname> parameter ++ Set <varname>xavi_name</varname> parameter + +... -+modparam("pv_headers", "xavp_name", "pvh") ++modparam("pv_headers", "xavi_name", "headers") +... + + + Result: -+ $xavp(headers[0]=>From) -+ $xavp(headers[0]=>To) -+ $xavp(headers[0]=>Call-ID) ++ $xavi(headers[0]=>From) ++ $xavi(headers[0]=>To) ++ $xavi(headers[0]=>Call-ID) + + +
+
+ <varname>header_value_size</varname> (int) + -+ Defines an internal maximum SIP header value size. Header values ++ Defines an internal maximum &sip; header value size. Header values + longer than this setting will be stripped down when collected or applied. + + @@ -752,7 +752,7 @@ index 0000000..83e74d6 + Set <varname>auto_msg</varname> parameter + +... -+modparam("pvh", "auto_msg", 1) ++modparam("pv_headers", "auto_msg", 1) +... + + @@ -806,7 +806,7 @@ index 0000000..a5211b9 + diff --git a/src/modules/pv_headers/doc/pv_headers_admin.xml b/src/modules/pv_headers/doc/pv_headers_admin.xml new file mode 100644 -index 0000000..44e84f2 +index 0000000..3fd9b0b --- /dev/null +++ b/src/modules/pv_headers/doc/pv_headers_admin.xml @@ -0,0 +1,116 @@ @@ -831,7 +831,7 @@ index 0000000..44e84f2 + Overview + + The main goal of the module is to offload the intermediate header processing -+ into the XAVP dynamic container as well as provide with high level methods ++ into the XAVI dynamic container as well as provide with high level methods + and pseudovariables to simplify &sip; message header modifications. + +
@@ -928,10 +928,10 @@ index 0000000..44e84f2 + diff --git a/src/modules/pv_headers/pv_headers.c b/src/modules/pv_headers/pv_headers.c new file mode 100644 -index 0000000..6faaf64 +index 0000000..6dfac3d --- /dev/null +++ b/src/modules/pv_headers/pv_headers.c -@@ -0,0 +1,519 @@ +@@ -0,0 +1,548 @@ +/* + * pv_headers + * @@ -976,9 +976,9 @@ index 0000000..6faaf64 +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"); ++str xavi_name = str_init(XAVP_NAME); ++str xavi_helper_xname = str_init("modparam_pv_headers"); ++str xavi_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; @@ -1005,14 +1005,43 @@ index 0000000..6faaf64 +static int handle_msg_reply_cb( + struct sip_msg *msg, unsigned int flags, void *cb); + ++/** ++ * ++ */ ++static int pvh_get_branch_index(struct sip_msg *msg, int *br_idx) ++{ ++ int os = 0; ++ int len = 0; ++ char parsed_br_idx[header_value_size]; ++ ++ if(msg->add_to_branch_len > header_value_size) { ++ LM_ERR("branch name is too long\n"); ++ return -1; ++ } ++ ++ os = msg->add_to_branch_len; ++ while(os > 0 && memcmp(msg->add_to_branch_s + os - 1, ".", 1)) ++ os--; ++ len = msg->add_to_branch_len - os; ++ if(os > 0 && len > 0) { ++ memcpy(parsed_br_idx, msg->add_to_branch_s + os, len); ++ parsed_br_idx[len] = '\0'; ++ *br_idx = atoi(parsed_br_idx) + 1; ++ } else { ++ *br_idx = 0; ++ } ++ ++ return 1; ++} ++ +static int w_pvh_collect_headers(struct sip_msg *msg, char *p1, char *p2) +{ -+ sr_xavp_t **backup_xavps = NULL; ++ sr_xavp_t **backup_xavis = 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) { ++ if((_reply_counter = pvh_reply_append(backup_xavis)) < 0) { + return -1; + } + } @@ -1021,12 +1050,12 @@ index 0000000..6faaf64 + +static int ki_pvh_collect_headers(struct sip_msg *msg) +{ -+ sr_xavp_t **backup_xavps = NULL; ++ sr_xavp_t **backup_xavis = 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) { ++ if((_reply_counter = pvh_reply_append(backup_xavis)) < 0) { + return -1; + } + } @@ -1164,7 +1193,7 @@ index 0000000..6faaf64 +}; + +static param_export_t params[] = { -+ {"xavp_name", PARAM_STR, &xavp_name}, ++ {"xavi_name", PARAM_STR, &xavi_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}, @@ -1353,7 +1382,7 @@ index 0000000..6faaf64 + 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); ++ pvh_clone_branch_xavi(msg, &xavi_name); + } + + return 1; @@ -1362,7 +1391,7 @@ index 0000000..6faaf64 +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 **backup_xavis = NULL; + sr_xavp_t **list = NULL; + + if(pvh_parse_msg(msg) != 0) @@ -1376,10 +1405,10 @@ index 0000000..6faaf64 + 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); ++ LM_DBG("T:%p t_check-branch:%d xavi_list:%p branches:%d\n", t, ++ _branch, &t->xavis_list, t->nr_of_outgoings); ++ list = &t->xavis_list; ++ backup_xavis = xavi_set_list(&t->xavis_list); + } + } + @@ -1391,9 +1420,9 @@ index 0000000..6faaf64 + return -1; + } + pvh_collect_headers(msg); -+ if(backup_xavps) { -+ xavp_set_list(backup_xavps); -+ LM_DBG("restored backup_xavps:%p\n", *backup_xavps); ++ if(backup_xavis) { ++ xavi_set_list(backup_xavis); ++ LM_DBG("restored backup_xavis:%p\n", *backup_xavis); + } + if(t) { + tmb.unref_cell(t); @@ -1453,7 +1482,7 @@ index 0000000..6faaf64 +} diff --git a/src/modules/pv_headers/pv_headers.h b/src/modules/pv_headers/pv_headers.h new file mode 100644 -index 0000000..4d53318 +index 0000000..5ee4efc --- /dev/null +++ b/src/modules/pv_headers/pv_headers.h @@ -0,0 +1,57 @@ @@ -1497,9 +1526,9 @@ index 0000000..4d53318 + +extern uac_api_t uac; + -+extern str xavp_name; -+extern str xavp_parsed_xname; -+extern str xavp_helper_xname; ++extern str xavi_name; ++extern str xavi_parsed_xname; ++extern str xavi_helper_xname; + +extern unsigned int header_name_size; +extern unsigned int header_value_size; @@ -1516,7 +1545,7 @@ index 0000000..4d53318 +#endif /* PV_HEADERS_H */ diff --git a/src/modules/pv_headers/pvh_func.c b/src/modules/pv_headers/pvh_func.c new file mode 100644 -index 0000000..97f89aa +index 0000000..1e1a9cc --- /dev/null +++ b/src/modules/pv_headers/pvh_func.c @@ -0,0 +1,360 @@ @@ -1554,7 +1583,7 @@ index 0000000..97f89aa +#include "pvh_hash.h" +#include "pvh_hdr.h" + -+static str xavp_helper_name = str_init("xavp_name"); ++static str xavi_helper_name = str_init("xavi_name"); + +int pvh_parse_msg(sip_msg_t *msg) +{ @@ -1630,18 +1659,18 @@ index 0000000..97f89aa + for(idx = 0; idx < d_size; idx++) { + val_part.s = hvals[idx]; + val_part.len = strlen(hvals[idx]); -+ if(pvh_set_xavp(msg, &xavp_name, &name, &val_part, SR_XTYPE_STR, ++ if(pvh_set_xavi(msg, &xavi_name, &name, &val_part, SR_XTYPE_STR, + 0, 1) + < 0) + return -1; + } + continue; + } -+ if(pvh_set_xavp(msg, &xavp_name, &name, &val, SR_XTYPE_STR, 0, 1) < 0) ++ if(pvh_set_xavi(msg, &xavi_name, &name, &val, SR_XTYPE_STR, 0, 1) < 0) + return -1; + } + -+ if(pvh_set_xavp(msg, &xavp_helper_xname, &xavp_helper_name, &xavp_name, ++ if(pvh_set_xavi(msg, &xavi_helper_xname, &xavi_helper_name, &xavi_name, + SR_XTYPE_STR, 0, 0) + < 0) + return -1; @@ -1653,7 +1682,7 @@ index 0000000..97f89aa + +int pvh_apply_headers(struct sip_msg *msg) +{ -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = NULL; + sr_xavp_t *sub = NULL; + struct str_hash_table rm_hdrs; + int from_cnt = 0, to_cnt = 0; @@ -1677,30 +1706,30 @@ index 0000000..97f89aa + return -1; + } + -+ pvh_get_branch_xname(msg, &xavp_name, &br_xname); ++ pvh_get_branch_xname(msg, &xavi_name, &br_xname); + -+ if((xavp = pvh_xavp_get(&br_xname, NULL)) == NULL -+ && (xavp = pvh_xavp_get(&xavp_name, NULL)) == NULL) { -+ LM_ERR("missing xavp %s, run pv_collect_headers() first\n", -+ xavp_name.s); ++ if((xavi = xavi_get(&br_xname, NULL)) == NULL ++ && (xavi = xavi_get(&xavi_name, NULL)) == NULL) { ++ LM_ERR("missing xavi %.*s, run pv_collect_headers() first\n", ++ xavi_name.len, xavi_name.s); + return -1; + } -+ if(xavp->val.type != SR_XTYPE_XAVP) { -+ LM_ERR("not xavp child type %s\n", xavp_name.s); ++ if(xavi->val.type != SR_XTYPE_XAVP) { ++ LM_ERR("not xavp child type %.*s\n", xavi_name.len, xavi_name.s); + return -1; + } + -+ if((sub = xavp->val.v.xavp) == NULL) { -+ LM_ERR("invalid xavp structure: %s\n", xavp_name.s); ++ if((sub = xavi->val.v.xavp) == NULL) { ++ LM_ERR("invalid xavp structure: %.*s\n", xavi_name.len, xavi_name.s); + return -1; + } -+ keys_count = pvh_xavp_keys_count(&sub); ++ keys_count = pvh_xavi_keys_count(&sub); + if(str_hash_alloc(&rm_hdrs, keys_count) < 0) { + PKG_MEM_ERROR; + return -1; + } -+ 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); ++ LM_DBG("xavi->name:%.*s br_xname:%.*s keys_count: %d\n", xavi->name.len, ++ xavi->name.s, br_xname.len, br_xname.s, keys_count); + str_hash_init(&rm_hdrs); + + if(msg->first_line.type == SIP_REPLY @@ -1793,7 +1822,7 @@ index 0000000..97f89aa + } + + if(!str_hash_case_get(&rm_hdrs, sub->name.s, sub->name.len)) { -+ if(!pvh_xavp_is_null(sub) && pvh_xavp_count(&sub->name, &sub) == 1) { ++ if(!pvh_avp_is_null(sub) && xavi_count(&sub->name, &sub) == 1) { + LM_DBG("replace header[%s]: %s\n", sub->name.s, sub->val.v.s.s); + pvh_real_hdr_replace(msg, &sub->name, &sub->val.v.s); + pvh_str_hash_add_key(&rm_hdrs, &sub->name); @@ -1804,7 +1833,7 @@ index 0000000..97f89aa + pvh_str_hash_add_key(&rm_hdrs, &sub->name); + } + -+ if(!pvh_xavp_is_null(sub) && !pvh_single_header(&sub->name)) { ++ if(!pvh_avp_is_null(sub) && !pvh_single_header(&sub->name)) { + pvh_real_hdr_append(msg, &sub->name, &sub->val.v.s); + LM_DBG("append header[%s]: %s\n", sub->name.s, sub->val.v.s.s); + } @@ -1825,12 +1854,12 @@ index 0000000..97f89aa + char t[header_name_size]; + str br_xname = {t, header_name_size}; + -+ pvh_get_branch_xname(msg, &xavp_name, &br_xname); -+ 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); -+ pvh_free_xavp(&br_xname); ++ pvh_get_branch_xname(msg, &xavi_name, &br_xname); ++ LM_DBG("clean xavi:%.*s\n", br_xname.len, br_xname.s); ++ pvh_free_xavi(&br_xname); ++ pvh_get_branch_xname(msg, &xavi_parsed_xname, &br_xname); ++ LM_DBG("clean xavi:%.*s\n", br_xname.len, br_xname.s); ++ pvh_free_xavi(&br_xname); + + pvh_hdrs_reset_flags(msg); + @@ -1840,7 +1869,7 @@ index 0000000..97f89aa +int pvh_check_header(struct sip_msg *msg, str *hname) +{ + -+ if(pvh_xavp_get_child(msg, &xavp_name, hname) == NULL) ++ if(pvh_xavi_get_child(msg, &xavi_name, hname) == NULL) + return -1; + + return 1; @@ -1848,12 +1877,12 @@ index 0000000..97f89aa + +int pvh_append_header(struct sip_msg *msg, str *hname, str *hvalue) +{ -+ return pvh_set_xavp(msg, &xavp_name, hname, hvalue, SR_XTYPE_STR, 0, 1); ++ return pvh_set_xavi(msg, &xavi_name, hname, hvalue, SR_XTYPE_STR, 0, 1); +} + +int pvh_modify_header(struct sip_msg *msg, str *hname, str *hvalue, int indx) +{ -+ return pvh_set_xavp(msg, &xavp_name, hname, hvalue, SR_XTYPE_STR, indx, 0); ++ return pvh_set_xavi(msg, &xavi_name, hname, hvalue, SR_XTYPE_STR, indx, 0); +} + +int pvh_remove_header(struct sip_msg *msg, str *hname, int indx) @@ -1861,19 +1890,19 @@ index 0000000..97f89aa + sr_xavp_t *avp = NULL; + int count = 0; + -+ if((avp = pvh_xavp_get_child(msg, &xavp_name, hname)) == NULL) ++ if((avp = pvh_xavi_get_child(msg, &xavi_name, hname)) == NULL) + return 1; + + if(indx < 0) { -+ count = pvh_xavp_count(hname, &avp); ++ count = xavi_count(hname, &avp); + do { -+ if(pvh_set_xavp( -+ msg, &xavp_name, hname, NULL, SR_XTYPE_STR, indx++, 0) ++ if(pvh_set_xavi( ++ msg, &xavi_name, hname, NULL, SR_XTYPE_STR, indx++, 0) + < 1) + return -1; + } while(indx < count); + } else { -+ if(pvh_set_xavp(msg, &xavp_name, hname, NULL, SR_XTYPE_STR, indx, 0) ++ if(pvh_set_xavi(msg, &xavi_name, hname, NULL, SR_XTYPE_STR, indx, 0) + < 1) + return -1; + } @@ -2672,10 +2701,10 @@ index 0000000..10aa216 \ No newline at end of file diff --git a/src/modules/pv_headers/pvh_xavp.c b/src/modules/pv_headers/pvh_xavp.c new file mode 100644 -index 0000000..72235b1 +index 0000000..3c0950a --- /dev/null +++ b/src/modules/pv_headers/pvh_xavp.c -@@ -0,0 +1,1355 @@ +@@ -0,0 +1,1173 @@ +/* + * pv_headers + * @@ -2711,66 +2740,60 @@ index 0000000..72235b1 + +static str reply_counter = str_init("reply_counter"); + -+// internal forward declarations -+sr_xavp_t *pvh_xavp_add_value_casei(str *name, sr_xval_t *val, sr_xavp_t **list); -+sr_xavp_t *pvh_xavp_add_xavp_value_casei(str *rname, str *name, sr_xval_t *val, sr_xavp_t **list); -+sr_xavp_t *pvh_xavp_set_value_casei(str *name, int idx, sr_xval_t *val, sr_xavp_t **list); -+sr_xavp_t *pvh_xavp_get_internal_casei(str *name, sr_xavp_t **list, int idx, sr_xavp_t **prv); -+sr_xavp_t* pvh_xavp_get_child_casei(str *rname, str *cname); -+int pvh_xavp_rm_internal_casei(str *name, sr_xavp_t **head, int idx); -+int pvh_xavp_rm_by_name_casei(str *name, int all, sr_xavp_t **head); -+ -+sr_xavp_t *pvh_xavp_get_child_with_ival( ++/** ++ * ++ */ ++static sr_xavp_t *pvh_xavi_get_child_with_ival( + str *rname, str *cname, sr_xavp_t *start) +{ -+ sr_xavp_t *ravp = NULL; -+ sr_xavp_t *vavp = NULL; ++ sr_xavp_t *ravi = NULL; ++ sr_xavp_t *vavi = NULL; + -+ ravp = pvh_xavp_get(rname, start); -+ if(ravp == NULL || ravp->val.type != SR_XTYPE_XAVP) ++ ravi = xavi_get(rname, start); ++ if(ravi == NULL || ravi->val.type != SR_XTYPE_XAVP) + return NULL; + -+ vavp = pvh_xavp_get(cname, ravp->val.v.xavp); -+ if(vavp == NULL || vavp->val.type != SR_XTYPE_INT) ++ vavi = xavi_get(cname, ravi->val.v.xavp); ++ if(vavi == NULL || vavi->val.type != SR_XTYPE_INT) + return NULL; + -+ return vavp; ++ return vavi; +} + +/** -+ * 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 ++ * We keep a $xavi(xavi_helper_xname=>reply_counter) with the number of replies ++ * so we will use $xavi(xavi_name.r.) on reply_route + */ +int pvh_reply_append(sr_xavp_t **start) +{ -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = 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; ++ xavi = pvh_xavi_get_child_with_ival( ++ &xavi_helper_xname, &reply_counter, start ? *start : NULL); ++ if(xavi) { ++ xavi->val.v.i++; ++ LM_DBG("reply message: %d\n", xavi->val.v.i); ++ return xavi->val.v.i; + } + + memset(&xval, 0, sizeof(sr_xval_t)); + xval.type = SR_XTYPE_INT; + xval.v.i = 0; + -+ xavp = pvh_xavp_get(&xavp_helper_xname, start ? *start : NULL); -+ if(xavp == NULL) { -+ if(pvh_xavp_add_xavp_value_casei(&xavp_helper_xname, &reply_counter, &xval, ++ xavi = xavi_get(&xavi_helper_xname, start ? *start : NULL); ++ if(xavi == NULL) { ++ if(xavi_add_xavi_value(&xavi_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); ++ LM_ERR("can't create xavi:%.*s\n", xavi_helper_xname.len, ++ xavi_helper_xname.s); + return -1; + } -+ LM_DBG("xavp_name:%.*s created\n", xavp_helper_xname.len, -+ xavp_helper_xname.s); ++ LM_DBG("xavi_name:%.*s created\n", xavi_helper_xname.len, ++ xavi_helper_xname.s); + } else { -+ if(pvh_xavp_add_value_casei(&reply_counter, &xval, &xavp->val.v.xavp) == NULL) { ++ if(xavi_add_value(&reply_counter, &xval, &xavi->val.v.xavp) == NULL) { + LM_ERR("can't add reply_counter value\n"); + return -1; + } @@ -2780,7 +2803,7 @@ index 0000000..72235b1 + return xval.v.i; +} + -+sr_xavp_t *pvh_xavp_new_value(str *name, sr_xval_t *val) ++static sr_xavp_t *pvh_xavi_new_value(str *name, sr_xval_t *val) +{ + sr_xavp_t *avp = NULL; + int size; @@ -2815,83 +2838,93 @@ index 0000000..72235b1 + return avp; +} + -+int pvh_xavp_append_value(str *name, sr_xval_t *val, sr_xavp_t **start) ++int pvh_xavi_append_value(str *name, sr_xval_t *val, sr_xavp_t **start) +{ + sr_xavp_t *last = NULL; -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = NULL; + -+ if((xavp = pvh_xavp_new_value(name, val)) == NULL) ++ if((xavi = pvh_xavi_new_value(name, val)) == NULL) + return -1; + + if(*start == NULL) { -+ xavp->next = *start; -+ *start = xavp; ++ xavi->next = *start; ++ *start = xavi; + return 1; + } + + last = *start; + while(last->next) + last = last->next; -+ last->next = xavp; ++ last->next = xavi; + + return 1; +} + -+int pvh_xavp_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start) ++/** ++ * ++ */ ++static int pvh_xavi_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start) +{ + int cnt = 0; + + if(idx < 0) { -+ cnt = pvh_xavp_count(name, start); ++ cnt = xavi_count(name, start); + idx = idx + cnt; -+ if(idx < 0) ++ if(idx < 0) { ++ LM_ERR("wrong calculated idx:%d\n", idx); + return -1; ++ } + } -+ LM_DBG("xavp name: %.*s\n", name->len, name->s); -+ if(pvh_xavp_set_value_casei(name, idx, val, start) == NULL) ++ LM_DBG("xavi name: %.*s\n", name->len, name->s); ++ if(xavi_set_value(name, idx, val, start) == NULL) + return -1; + + return 1; +} + -+sr_xavp_t *pvh_get_xavp(struct sip_msg *msg, str *xname) ++/** ++ * ++ */ ++static sr_xavp_t *pvh_get_xavi(struct sip_msg *msg, str *xname) +{ -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = NULL; + char t[header_name_size]; + str br_xname = {t, header_name_size}; + + pvh_get_branch_xname(msg, xname, &br_xname); -+ if((xavp = pvh_xavp_get(&br_xname, NULL)) == NULL) { ++ if((xavi = xavi_get(&br_xname, NULL)) == NULL) { + if(cmp_str(xname, &br_xname) == 0) + goto end; -+ if((xavp = pvh_xavp_get(xname, NULL)) == NULL) ++ if((xavi = xavi_get(xname, NULL)) == NULL) + goto end; -+ 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) { ++ if(xavi->val.type != SR_XTYPE_XAVP) { + LM_ERR("not xavp child type %s\n", br_xname.s); -+ xavp = NULL; ++ xavi = NULL; + goto end; + } + +end: -+ return xavp; ++ return xavi; +} + -+int pvh_free_xavp(str *xname) ++/** ++ * ++ */ ++int pvh_free_xavi(str *xname) +{ -+ sr_xavp_t *xavp = NULL; -+ pvh_xavp_rm_by_name_casei(xname, 1, NULL); -+ if((xavp = pvh_xavp_get(xname, NULL)) != NULL) -+ xavp_rm(xavp, NULL); ++ sr_xavp_t *xavi = NULL; ++ xavi_rm_by_name(xname, 1, NULL); ++ if((xavi = xavi_get(xname, NULL)) != NULL) ++ xavi_rm(xavi, NULL); + return 1; +} + -+void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree) ++/** ++ * ++ */ ++static void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree) +{ + struct to_param *n = NULL; + @@ -2903,6 +2936,9 @@ index 0000000..72235b1 + param = NULL; +} + ++/** ++ * ++ */ +int pvh_parse_header_name(pv_spec_p sp, str *hname) +{ + pv_spec_p psp = NULL; @@ -2941,79 +2977,51 @@ index 0000000..72235b1 + return 0; +} + -+sr_xval_t *pvh_xavp_get_value( ++/** ++ * ++ */ ++static sr_xval_t *pvh_xavi_get_value( + struct sip_msg *msg, str *xname, str *name, int idx) +{ -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = NULL; + sr_xavp_t *sub = NULL; + -+ if((xavp = pvh_get_xavp(msg, xname)) != NULL) { -+ /* LM_DBG("xavp:%.*s name:%.*s idx:%d\n", xavp->name.len, xavp->name.s, ++ if((xavi = pvh_get_xavi(msg, xname)) != NULL) { ++ /* LM_DBG("xavi:%.*s name:%.*s idx:%d\n", xavi->name.len, xavi->name.s, + name->len, name->s, idx); */ -+ sub = pvh_xavp_get_by_index(name, idx, &xavp->val.v.xavp); ++ sub = xavi_get_by_index(name, idx, &xavi->val.v.xavp); + } + + return sub ? &sub->val : NULL; +} + -+sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name) ++/** ++ * ++ */ ++sr_xavp_t *pvh_xavi_get_child(struct sip_msg *msg, str *xname, str *name) +{ -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = NULL; + char t[header_name_size]; + str br_xname = {t, header_name_size}; + + pvh_get_branch_xname(msg, xname, &br_xname); -+ xavp = pvh_xavp_get_child_casei(&br_xname, name); -+ if(xavp == NULL) { ++ xavi = xavi_get_child(&br_xname, name); ++ if(xavi == NULL) { + if(cmp_str(xname, &br_xname) != 0) { -+ xavp = pvh_xavp_get_child_casei(xname, name); -+ if(xavp) { -+ LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n", ++ xavi = xavi_get_child(xname, name); ++ if(xavi) { ++ LM_DBG("br_xname:%.*s is not here, using xname:%.*s\n", + br_xname.len, br_xname.s, xname->len, xname->s); + } + } + } -+ return xavp; -+} -+ -+sr_xavp_t *pvh_xavp_get(str *name, sr_xavp_t *start) -+{ -+ return pvh_xavp_get_internal_casei(name, (start)?&start:NULL, 0, NULL); -+} -+ -+sr_xavp_t *pvh_xavp_get_by_index(str *name, int idx, sr_xavp_t **start) -+{ -+ return pvh_xavp_get_internal_casei(name, start, idx, NULL); ++ return xavi; +} + -+int pvh_xavp_count(str *name, sr_xavp_t **start) -+{ -+ sr_xavp_t *avp; -+ unsigned int id; -+ int n = 0; -+ -+ if(name==NULL || name->s==NULL) -+ return -1; -+ id = get_hash1_case_raw(name->s, name->len); -+ -+ if(start) -+ avp = *start; -+ else -+ avp=*xavp_get_crt_list(); -+ while(avp) -+ { -+ if(avp->id==id && avp->name.len==name->len -+ && strncasecmp(avp->name.s, name->s, name->len)==0) -+ { -+ n++; -+ } -+ avp=avp->next; -+ } -+ -+ return n; -+} -+ -+int pvh_xavp_is_null(sr_xavp_t *avp) ++/** ++ * ++ */ ++int pvh_avp_is_null(sr_xavp_t *avp) +{ + if(avp == NULL) + return 1; @@ -3027,7 +3035,10 @@ index 0000000..72235b1 + return 0; +} + -+void pvh_xavp_free_data(void *p, sr_xavp_sfree_f sfree) ++/** ++ * ++ */ ++static void pvh_xavi_free_data(void *p, sr_xavp_sfree_f sfree) +{ + xavp_c_data_t *c_data = NULL; + @@ -3040,28 +3051,34 @@ index 0000000..72235b1 + } +} + -+int pvh_xavp_keys_count(sr_xavp_t **start) ++/** ++ * ++ */ ++int pvh_xavi_keys_count(sr_xavp_t **start) +{ -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = NULL; + int cnt = 0; + + if(*start == NULL) + return 0; + -+ xavp = *start; ++ xavi = *start; + -+ while(xavp) { ++ while(xavi) { + cnt++; -+ xavp = xavp->next; ++ xavi = xavi->next; + } + + return cnt; +} + -+int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, ++/** ++ * ++ */ ++int pvh_set_xavi(struct sip_msg *msg, str *xname, str *name, void *data, + sr_xtype_t type, int idx, int append) +{ -+ sr_xavp_t **xavp = NULL; ++ sr_xavp_t **xavi = NULL; + sr_xavp_t *root = NULL; + sr_xval_t root_xval; + sr_xval_t xval; @@ -3069,7 +3086,7 @@ index 0000000..72235b1 + str br_xname = {t, header_name_size}; + + if(xname == NULL || name == NULL) { -+ LM_ERR("missing xavp/pv name\n"); ++ LM_ERR("missing xavi/pv name\n"); + return -1; + } + @@ -3091,17 +3108,17 @@ index 0000000..72235b1 + } + memset(xval.v.data, 0, sizeof(sr_data_t)); + xval.v.data->p = data; -+ xval.v.data->pfree = pvh_xavp_free_data; ++ xval.v.data->pfree = pvh_xavi_free_data; + } + -+ root = pvh_xavp_get(&br_xname, NULL); ++ root = xavi_get(&br_xname, NULL); + + if(root == NULL && _branch > 0) { -+ pvh_clone_branch_xavp(msg, xname); -+ root = pvh_xavp_get(&br_xname, NULL); ++ pvh_clone_branch_xavi(msg, xname); ++ root = xavi_get(&br_xname, NULL); + } + -+ xavp = root ? &root->val.v.xavp : &root; ++ xavi = root ? &root->val.v.xavp : &root; + + if(root == NULL) { + append = 1; @@ -3109,25 +3126,25 @@ index 0000000..72235b1 + root_xval.type = SR_XTYPE_XAVP; + root_xval.v.xavp = NULL; + -+ if((root = pvh_xavp_add_value_casei(&br_xname, &root_xval, NULL)) == NULL) { -+ LM_ERR("error create xavp %s\n", br_xname.s); ++ if((root = xavi_add_value(&br_xname, &root_xval, NULL)) == NULL) { ++ LM_ERR("error create xavi %.*s\n", br_xname.len, br_xname.s); + return -1; + } -+ xavp = &root->val.v.xavp; -+ } else if(pvh_xavp_get_child_casei(&br_xname, name) == NULL) { ++ xavi = &root->val.v.xavp; ++ } else if(xavi_get_child(&br_xname, name) == NULL) { + append = 1; + } + + if(append) { -+ 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); ++ if(pvh_xavi_append_value(name, &xval, xavi) < 0) { ++ LM_ERR("error append xavi=>name %.*s=>%.*s\n", ++ br_xname.len, br_xname.s, name->len, name->s); + 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); ++ if(pvh_xavi_set_value(name, &xval, idx, xavi) < 0) { ++ LM_ERR("error modify xavi=>name %.*s=>%.*s idx=%d\n", ++ br_xname.len, br_xname.s, name->len, name->s, idx); + return -1; + } + } @@ -3135,32 +3152,10 @@ index 0000000..72235b1 + return 1; +} + -+int pvh_get_branch_index(struct sip_msg *msg, int *br_idx) -+{ -+ int os = 0; -+ int len = 0; -+ char parsed_br_idx[header_value_size]; -+ -+ if(msg->add_to_branch_len > header_value_size) { -+ LM_ERR("branch name is too long\n"); -+ return -1; -+ } -+ -+ os = msg->add_to_branch_len; -+ while(os > 0 && memcmp(msg->add_to_branch_s + os - 1, ".", 1)) -+ os--; -+ len = msg->add_to_branch_len - os; -+ if(os > 0 && len > 0) { -+ memcpy(parsed_br_idx, msg->add_to_branch_s + os, len); -+ parsed_br_idx[len] = '\0'; -+ *br_idx = atoi(parsed_br_idx) + 1; -+ } else { -+ *br_idx = 0; -+ } -+ -+ return 1; -+} + ++/** ++ * ++ */ +int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst) +{ + int os = 0; @@ -3194,28 +3189,32 @@ index 0000000..72235b1 + return 1; +} + -+int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname) ++/** ++ * ++ */ ++int pvh_clone_branch_xavi(struct sip_msg *msg, str *xname) +{ -+ sr_xavp_t *xavp = NULL; -+ sr_xavp_t *br_xavp = NULL; ++ sr_xavp_t *xavi = NULL; ++ sr_xavp_t *br_xavi = 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 = pvh_xavp_get(xname, NULL)) == NULL) { -+ LM_ERR("cannot clone xavp from non existing %s\n", xname->s); ++ if((xavi = xavi_get(xname, NULL)) == NULL) { ++ LM_ERR("cannot clone xavi from non existing %.*s\n", ++ xname->len, xname->s); + return -1; + } + -+ if(xavp->val.type != SR_XTYPE_XAVP) { -+ LM_ERR("not xavp child type %s\n", xavp_name.s); ++ if(xavi->val.type != SR_XTYPE_XAVP) { ++ LM_ERR("not xavp child type %.*s\n", xavi_name.len, xavi_name.s); + return -1; + } + -+ if((sub = xavp->val.v.xavp) == NULL) { -+ LM_ERR("invalid xavp structure: %s\n", xavp_name.s); ++ if((sub = xavi->val.v.xavp) == NULL) { ++ LM_ERR("invalid xavi structure: %.*s\n", xavi_name.len, xavi_name.s); + return -1; + } + @@ -3225,12 +3224,12 @@ index 0000000..72235b1 + root_xval.type = SR_XTYPE_XAVP; + root_xval.v.xavp = NULL; + -+ if((br_xavp = pvh_xavp_add_value_casei(&br_xname, &root_xval, NULL)) == NULL) { -+ LM_ERR("error create xavp %s\n", br_xname.s); ++ if((br_xavi = xavi_add_value(&br_xname, &root_xval, NULL)) == NULL) { ++ LM_ERR("error create xavi %.*s\n", br_xname.len, br_xname.s); + return -1; + } + -+ if(cmp_str(xname, &xavp_parsed_xname) == 0) { ++ if(cmp_str(xname, &xavi_parsed_xname) == 0) { + return 1; + } + @@ -3239,9 +3238,9 @@ index 0000000..72235b1 + continue; + if(sub->val.type == SR_XTYPE_DATA) + continue; -+ if(pvh_xavp_append_value(&sub->name, &sub->val, &br_xavp->val.v.xavp) ++ if(pvh_xavi_append_value(&sub->name, &sub->val, &br_xavi->val.v.xavp) + < 0) { -+ LM_ERR("cannot clone xavp %s\n", sub->name.s); ++ LM_ERR("cannot clone xavi %.*s\n", sub->name.len, sub->name.s); + return -1; + } + ++i; @@ -3251,9 +3250,12 @@ index 0000000..72235b1 + return 1; +} + ++/** ++ * ++ */ +int pvh_get_header(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) +{ -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = NULL; + sr_xval_t *xval = NULL; + pv_value_t tv; + str hname = STR_NULL; @@ -3278,16 +3280,16 @@ index 0000000..72235b1 + } + + if(idx < 0) { -+ if((xavp = pvh_xavp_get_child(msg, &xavp_name, &hname)) == NULL) ++ if((xavi = pvh_xavi_get_child(msg, &xavi_name, &hname)) == NULL) + cnt = 0; + else -+ cnt = pvh_xavp_count(&hname, &xavp); ++ cnt = xavi_count(&hname, &xavi); + idx = idx + cnt; + if(idx < 0) + pv_get_null(msg, param, res); + } + -+ xval = pvh_xavp_get_value(msg, &xavp_name, &hname, idx); ++ xval = pvh_xavi_get_value(msg, &xavi_name, &hname, idx); + + if(xval == NULL || !xval->v.s.s) + return pv_get_null(msg, param, res); @@ -3295,10 +3297,13 @@ index 0000000..72235b1 + return pv_get_strval(msg, param, res, &xval->v.s); +} + ++/** ++ * ++ */ +int pvh_set_header( + struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) +{ -+ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *xavi = NULL; + pv_elem_p pv_format = NULL; + pv_value_t tv; + str hname = STR_NULL; @@ -3330,21 +3335,21 @@ index 0000000..72235b1 + return -1; + } + -+ if((xavp = pvh_xavp_get_child(msg, &xavp_name, &hname)) == NULL) ++ if((xavi = pvh_xavi_get_child(msg, &xavi_name, &hname)) == NULL) + idx = 0; + else if(idx < 0) -+ idx = idx + pvh_xavp_count(&hname, &xavp); ++ idx = idx + xavi_count(&hname, &xavi); + + if(val == NULL || (val->flags & PV_VAL_NULL)) { + if(itype == PV_IDX_ALL) { -+ for(idx = pvh_xavp_count(&hname, &xavp) - 1; idx >= 0; idx--) { -+ if(pvh_set_xavp( -+ msg, &xavp_name, &hname, NULL, SR_XTYPE_STR, idx, 0) ++ for(idx = xavi_count(&hname, &xavi) - 1; idx >= 0; idx--) { ++ if(pvh_set_xavi( ++ msg, &xavi_name, &hname, NULL, SR_XTYPE_STR, idx, 0) + < 0) + goto err; + } + } else { -+ if(pvh_set_xavp(msg, &xavp_name, &hname, NULL, SR_XTYPE_STR, idx, 0) ++ if(pvh_set_xavi(msg, &xavi_name, &hname, NULL, SR_XTYPE_STR, idx, 0) + < 0) + goto err; + } @@ -3364,25 +3369,25 @@ index 0000000..72235b1 + } + if(strlen(orig_hname.s) > 1 + && strcmp(orig_hname.s + strlen(orig_hname.s) - 2, "])") != 0) { -+ if(pvh_set_xavp(msg, &xavp_name, &hname, &fval, SR_XTYPE_STR, 0, 1) ++ if(pvh_set_xavi(msg, &xavi_name, &hname, &fval, SR_XTYPE_STR, 0, 1) + < 0) + goto err; + } else if(itype == PV_IDX_ALL) { + idx = 0; -+ cnt = pvh_xavp_count(&hname, &xavp); ++ cnt = xavi_count(&hname, &xavi); + while(idx < cnt) { -+ if(pvh_set_xavp(msg, &xavp_name, &hname, NULL, SR_XTYPE_STR, ++ if(pvh_set_xavi(msg, &xavi_name, &hname, NULL, SR_XTYPE_STR, + idx++, 0) + < 1) + goto err; + } -+ if(pvh_set_xavp(msg, &xavp_name, &hname, &fval, SR_XTYPE_STR, 0, ++ if(pvh_set_xavi(msg, &xavi_name, &hname, &fval, SR_XTYPE_STR, 0, + cnt ? 0 : 1) + < 0) + goto err; + } else { -+ if(pvh_set_xavp( -+ msg, &xavp_name, &hname, &fval, SR_XTYPE_STR, idx, 0) ++ if(pvh_set_xavi( ++ msg, &xavi_name, &hname, &fval, SR_XTYPE_STR, idx, 0) + < 0) + goto err; + } @@ -3401,6 +3406,9 @@ index 0000000..72235b1 + return -1; +} + ++/** ++ * ++ */ +xavp_c_data_t *pvh_set_parsed( + struct sip_msg *msg, str *hname, str *cur, str *new) +{ @@ -3417,7 +3425,7 @@ index 0000000..72235b1 + val = cur; + if(pvh_merge_uri(msg, SET_URI_T, cur, val, c_data) < 0) + goto err; -+ if(pvh_set_xavp(msg, &xavp_parsed_xname, hname, c_data, SR_XTYPE_DATA, 0, 0) ++ if(pvh_set_xavi(msg, &xavi_parsed_xname, hname, c_data, SR_XTYPE_DATA, 0, 0) + < 0) + goto err; + LM_DBG("c_data from pvh_merge_uri hname:%.*s\n", hname->len, hname->s); @@ -3425,10 +3433,13 @@ index 0000000..72235b1 + return c_data; + +err: -+ // how can I call?? pvh_xavp_free_data(c_data, shm_free); ++ // how can I call?? pvh_xavi_free_data(c_data, shm_free); + return NULL; +} + ++/** ++ * ++ */ +int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) +{ + sr_xval_t *xval = NULL; @@ -3447,17 +3458,17 @@ index 0000000..72235b1 + else if(p_no >= 6 && p_no <= 10) + pvh_str_copy(&hname, &_hdr_to, header_name_size); + -+ xval = pvh_xavp_get_value(msg, &xavp_name, &hname, 0); ++ xval = pvh_xavi_get_value(msg, &xavi_name, &hname, 0); + if(xval == NULL || !xval->v.s.s) { -+ /* LM_DBG("xavp:%.*s hname:%.*s is null\n", xavp_name.len, xavp_name.s, ++ /* LM_DBG("xavi:%.*s hname:%.*s is null\n", xavi_name.len, xavi_name.s, + hname.len, hname.s); */ + goto err; + } + -+ xval_pd = pvh_xavp_get_value(msg, &xavp_parsed_xname, &hname, 0); ++ xval_pd = pvh_xavi_get_value(msg, &xavi_parsed_xname, &hname, 0); + + if(xval_pd) { -+ /* LM_DBG("p_no:%d c_data from xavp_parsed_xname hname:%.*s\n", p_no, ++ /* LM_DBG("p_no:%d c_data from xavi_parsed_xname hname:%.*s\n", p_no, + hname.len, hname.s); */ + c_data = (xavp_c_data_t *)xval_pd->v.data->p; + } @@ -3506,6 +3517,9 @@ index 0000000..72235b1 + return pv_get_null(msg, param, res); +} + ++/** ++ * ++ */ +int pvh_set_uri(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) +{ + sr_xval_t *xval = NULL; @@ -3560,7 +3574,7 @@ index 0000000..72235b1 + goto err; + } + -+ xval = pvh_xavp_get_value(msg, &xavp_name, &hname, 0); ++ xval = pvh_xavi_get_value(msg, &xavi_name, &hname, 0); + if(xval == NULL || !xval->v.s.s) + goto err; + @@ -3572,14 +3586,14 @@ index 0000000..72235b1 + memset(c_data, 0, sizeof(xavp_c_data_t)); + if(pvh_merge_uri(msg, a_type, &xval->v.s, &fval, c_data) < 0) + goto err; -+ /* LM_DBG("xavp:%.*s hname:%.*s value:%.*s\n", xavp_name.len, xavp_name.s, ++ /* LM_DBG("xavi:%.*s hname:%.*s value:%.*s\n", xavi_name.len, xavi_name.s, + hname.len, hname.s, c_data->value.len, c_data->value.s); */ -+ if(pvh_set_xavp(msg, &xavp_name, &hname, &c_data->value, SR_XTYPE_STR, 0, 0) ++ if(pvh_set_xavi(msg, &xavi_name, &hname, &c_data->value, SR_XTYPE_STR, 0, 0) + < 0) + goto err; + -+ if(pvh_set_xavp( -+ msg, &xavp_parsed_xname, &hname, c_data, SR_XTYPE_DATA, 0, 0) ++ if(pvh_set_xavi( ++ msg, &xavi_parsed_xname, &hname, c_data, SR_XTYPE_DATA, 0, 0) + < 0) + goto err; + @@ -3593,6 +3607,9 @@ index 0000000..72235b1 + return -1; +} + ++/** ++ * ++ */ +int pvh_merge_uri(struct sip_msg *msg, enum action_type type, str *cur, + str *new, xavp_c_data_t *c_data) +{ @@ -3749,6 +3766,9 @@ index 0000000..72235b1 + return -1; +} + ++/** ++ * ++ */ +int pvh_get_reply_sr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) +{ + sr_xval_t *xval = NULL; @@ -3766,7 +3786,7 @@ index 0000000..72235b1 + &msg->first_line.u.reply.status); + break; + case 2: // reason -+ xval = pvh_xavp_get_value(msg, &xavp_name, &_hdr_reply_reason, 0); ++ xval = pvh_xavi_get_value(msg, &xavi_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); @@ -3778,6 +3798,9 @@ index 0000000..72235b1 + return pv_get_null(msg, param, res); +} + ++/** ++ * ++ */ +int pvh_set_reply_sr( + struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) +{ @@ -3834,7 +3857,7 @@ index 0000000..72235b1 + msg->first_line.u.reply.status.s[0] = code + '0'; + break; + case 2: // reason -+ if(pvh_set_xavp(msg, &xavp_name, &_hdr_reply_reason, &fval, ++ if(pvh_set_xavi(msg, &xavi_name, &_hdr_reply_reason, &fval, + SR_XTYPE_STR, 0, 0) + < 0) { + LM_ERR("set reply: cannot set reply reason\n"); @@ -3855,188 +3878,12 @@ index 0000000..72235b1 + pv_elem_free_all(pv_format); + return -1; +} -+ -+sr_xavp_t *pvh_xavp_add_value_casei(str *name, sr_xval_t *val, sr_xavp_t **list) -+{ -+ sr_xavp_t *avp=0; -+ -+ avp = pvh_xavp_new_value(name, val); -+ if (avp==NULL) -+ return NULL; -+ -+ /* Prepend new value to the list */ -+ if(list) { -+ avp->next = *list; -+ *list = avp; -+ } else { -+ avp->next = *xavp_get_crt_list(); -+ *xavp_get_crt_list() = avp; -+ } -+ -+ return avp; -+} -+ -+sr_xavp_t *pvh_xavp_add_xavp_value_casei(str *rname, str *name, sr_xval_t *val, sr_xavp_t **list) -+{ -+ sr_xavp_t *ravp=0; -+ sr_xavp_t *cavp=0; -+ sr_xval_t rval; -+ -+ cavp = pvh_xavp_new_value(name, val); -+ if (cavp==NULL) -+ return NULL; -+ -+ memset(&rval, 0, sizeof(sr_xval_t)); -+ rval.type = SR_XTYPE_XAVP; -+ rval.v.xavp = cavp; -+ -+ ravp = pvh_xavp_new_value(rname, &rval); -+ if (ravp==NULL) { -+ xavp_destroy_list(&cavp); -+ return NULL; -+ } -+ -+ /* Prepend new value to the list */ -+ if(list) { -+ ravp->next = *list; -+ *list = ravp; -+ } else { -+ ravp->next = *xavp_get_crt_list(); -+ *xavp_get_crt_list() = ravp; -+ } -+ -+ return ravp; -+} -+ -+sr_xavp_t *pvh_xavp_set_value_casei(str *name, int idx, sr_xval_t *val, sr_xavp_t **list) -+{ -+ sr_xavp_t *avp; -+ sr_xavp_t *cur; -+ sr_xavp_t *prv=0; -+ -+ if(val==NULL) -+ return NULL; -+ -+ /* Find the current value */ -+ cur = pvh_xavp_get_internal_casei(name, list, idx, &prv); -+ if(cur==NULL) -+ return NULL; -+ -+ avp = pvh_xavp_new_value(name, val); -+ if (avp==NULL) -+ return NULL; -+ -+ /* Replace the current value with the new */ -+ avp->next = cur->next; -+ if(prv) -+ prv->next = avp; -+ else if(list) -+ *list = avp; -+ else -+ *xavp_get_crt_list() = avp; -+ -+ xavp_free(cur); -+ -+ return avp; -+} -+ -+sr_xavp_t *pvh_xavp_get_internal_casei(str *name, sr_xavp_t **list, int idx, sr_xavp_t **prv) -+{ -+ sr_xavp_t *avp; -+ unsigned int id; -+ int n = 0; -+ -+ if(name==NULL || name->s==NULL) -+ return NULL; -+ id = get_hash1_case_raw(name->s, name->len); -+ -+ if(list && *list) -+ avp = *list; -+ else -+ avp = *xavp_get_crt_list(); -+ while(avp) -+ { -+ if(avp->id==id && avp->name.len==name->len -+ && strncasecmp(avp->name.s, name->s, name->len)==0) -+ { -+ if(idx==n) -+ return avp; -+ n++; -+ } -+ if(prv) -+ *prv = avp; -+ avp = avp->next; -+ } -+ return NULL; -+} -+ -+sr_xavp_t* pvh_xavp_get_child_casei(str *rname, str *cname) -+{ -+ sr_xavp_t *ravp=NULL; -+ -+ ravp = pvh_xavp_get(rname, NULL); -+ if(ravp==NULL || ravp->val.type!=SR_XTYPE_XAVP) -+ return NULL; -+ -+ return pvh_xavp_get(cname, ravp->val.v.xavp); -+} -+ -+int pvh_xavp_rm_internal_casei(str *name, sr_xavp_t **head, int idx) -+{ -+ sr_xavp_t *avp; -+ sr_xavp_t *foo; -+ sr_xavp_t *prv=0; -+ unsigned int id; -+ int n=0; -+ int count=0; -+ -+ if(name==NULL || name->s==NULL) -+ return 0; -+ -+ id = get_hash1_case_raw(name->s, name->len); -+ if(head!=NULL) -+ avp = *head; -+ else -+ avp = *xavp_get_crt_list(); -+ while(avp) -+ { -+ foo = avp; -+ avp=avp->next; -+ if(foo->id==id && foo->name.len==name->len -+ && strncasecmp(foo->name.s, name->s, name->len)==0) -+ { -+ if(idx<0 || idx==n) -+ { -+ if(prv!=NULL) -+ prv->next=foo->next; -+ else if(head!=NULL) -+ *head = foo->next; -+ else -+ *xavp_get_crt_list() = foo->next; -+ xavp_free(foo); -+ if(idx>=0) -+ return 1; -+ count++; -+ } -+ n++; -+ } else { -+ prv = foo; -+ } -+ } -+ return count; -+} -+ -+int pvh_xavp_rm_by_name_casei(str *name, int all, sr_xavp_t **head) -+{ -+ return pvh_xavp_rm_internal_casei(name, head, -1*all); -+} -+ diff --git a/src/modules/pv_headers/pvh_xavp.h b/src/modules/pv_headers/pvh_xavp.h new file mode 100644 -index 0000000..a204f93 +index 0000000..c3bc978 --- /dev/null +++ b/src/modules/pv_headers/pvh_xavp.h -@@ -0,0 +1,69 @@ +@@ -0,0 +1,63 @@ +/* + * pv_headers + * @@ -4072,21 +3919,15 @@ index 0000000..a204f93 + +int pvh_reply_append(sr_xavp_t **start); + -+int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data, ++int pvh_set_xavi(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_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); -+sr_xavp_t *pvh_xavp_get(str *name, sr_xavp_t *start); -+sr_xavp_t *pvh_xavp_get_by_index(str *name, int idx, sr_xavp_t **start); -+int pvh_xavp_count(str *name, sr_xavp_t **start); -+ -+int pvh_get_branch_index(struct sip_msg *msg, int *br_idx); ++int pvh_free_xavi(str *xname); ++int pvh_xavi_keys_count(sr_xavp_t **start); ++sr_xavp_t *pvh_xavi_get_child(struct sip_msg *msg, str *xname, str *name); ++int pvh_avp_is_null(sr_xavp_t *avp); ++ +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_clone_branch_xavi(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); diff --git a/debian/patches/upstream/core-receive-reset-xavi-list-after-message-processin.patch b/debian/patches/upstream/core-receive-reset-xavi-list-after-message-processin.patch new file mode 100644 index 000000000..04a019dc2 --- /dev/null +++ b/debian/patches/upstream/core-receive-reset-xavi-list-after-message-processin.patch @@ -0,0 +1,18 @@ +From: Victor Seva +Date: Wed, 27 May 2020 09:00:19 +0200 +Subject: core: receive - reset xavi list after message processing + +--- + src/core/receive.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/core/receive.c b/src/core/receive.c +index 550ec59..e23de0f 100644 +--- a/src/core/receive.c ++++ b/src/core/receive.c +@@ -560,4 +560,5 @@ void ksr_msg_env_reset(void) + { + reset_avps(); + xavp_reset_list(); ++ xavi_reset_list(); + } diff --git a/debian/patches/upstream/core-xavi-api-like-xavp-but-with-insensitive-case-na.patch b/debian/patches/upstream/core-xavi-api-like-xavp-but-with-insensitive-case-na.patch new file mode 100644 index 000000000..7a231efec --- /dev/null +++ b/debian/patches/upstream/core-xavi-api-like-xavp-but-with-insensitive-case-na.patch @@ -0,0 +1,1152 @@ +From: Victor Seva +Date: Wed, 27 May 2020 08:57:38 +0200 +Subject: core: xavi api - like xavp but with insensitive case names + +$xavi(WhatEver=>FOo) == $xavi(whatever=>foO) +--- + src/core/xavp.c | 1034 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- + src/core/xavp.h | 43 +++ + 2 files changed, 1057 insertions(+), 20 deletions(-) + +diff --git a/src/core/xavp.c b/src/core/xavp.c +index 7351d83..4a443bd 100644 +--- a/src/core/xavp.c ++++ b/src/core/xavp.c +@@ -34,6 +34,11 @@ static sr_xavp_t *_xavp_list_head = 0; + /*! Pointer to XAVP current list */ + static sr_xavp_t **_xavp_list_crt = &_xavp_list_head; + ++/*! XAVI list head */ ++static sr_xavp_t *_xavi_list_head = 0; ++/*! Pointer to XAVI current list */ ++static sr_xavp_t **_xavi_list_crt = &_xavi_list_head; ++ + /*! Helper functions */ + static sr_xavp_t *xavp_get_internal(str *name, sr_xavp_t **list, int idx, sr_xavp_t **prv); + static int xavp_rm_internal(str *name, sr_xavp_t **head, int idx); +@@ -565,60 +570,66 @@ sr_xavp_t **xavp_get_crt_list(void) + return _xavp_list_crt; + } + +-void xavp_print_list_content(sr_xavp_t **head, int level) ++void xavx_print_list_content(char *name, sr_xavp_t **head, sr_xavp_t **rlist, int level) + { + sr_xavp_t *avp=0; + sr_xavp_t *start=0; + +- if(head!=NULL) ++ if(head!=NULL) { + start = *head; +- else +- start=*_xavp_list_crt; +- LM_INFO("+++++ start XAVP list: %p (%p) (level=%d)\n", start, head, level); ++ } else { ++ start=*rlist; ++ } ++ LM_INFO("+++++ start %s list: %p (%p) (level=%d)\n", name, start, head, level); + avp = start; + while(avp) + { +- LM_INFO(" *** (l:%d - %p) XAVP name: %s\n", level, avp, avp->name.s); +- LM_INFO(" XAVP id: %u\n", avp->id); +- LM_INFO(" XAVP value type: %d\n", avp->val.type); ++ LM_INFO(" *** (l:%d - %p) %s name: %s\n", level, avp, name, avp->name.s); ++ LM_INFO(" %s id: %u\n", name, avp->id); ++ LM_INFO(" %s value type: %d\n", name, avp->val.type); + switch(avp->val.type) { + case SR_XTYPE_NULL: +- LM_INFO(" XAVP value: \n"); ++ LM_INFO(" %s value: \n", name); + break; + case SR_XTYPE_INT: +- LM_INFO(" XAVP value (int): %d\n", avp->val.v.i); ++ LM_INFO(" %s value (int): %d\n", name, avp->val.v.i); + break; + case SR_XTYPE_STR: +- LM_INFO(" XAVP value (str): %s\n", avp->val.v.s.s); ++ LM_INFO(" %s value (str): %s\n", name, avp->val.v.s.s); + break; + case SR_XTYPE_TIME: +- LM_INFO(" XAVP value (time): %lu\n", ++ LM_INFO(" %s value (time): %lu\n", name, + (long unsigned int)avp->val.v.t); + break; + case SR_XTYPE_LONG: +- LM_INFO(" XAVP value (long): %ld\n", avp->val.v.l); ++ LM_INFO(" %s value (long): %ld\n", name, avp->val.v.l); + break; + case SR_XTYPE_LLONG: +- LM_INFO(" XAVP value (llong): %lld\n", avp->val.v.ll); ++ LM_INFO(" %s value (llong): %lld\n", name, avp->val.v.ll); + break; + case SR_XTYPE_XAVP: +- LM_INFO(" XAVP value: \n", avp->val.v.xavp); +- xavp_print_list_content(&avp->val.v.xavp, level+1); ++ LM_INFO(" %s value: \n", name, avp->val.v.xavp); ++ xavx_print_list_content(name, &avp->val.v.xavp, rlist, level+1); + break; + case SR_XTYPE_VPTR: +- LM_INFO(" XAVP value: \n", avp->val.v.vptr); ++ LM_INFO(" %s value: \n", name, avp->val.v.vptr); + break; + case SR_XTYPE_SPTR: +- LM_INFO(" XAVP value: \n", avp->val.v.vptr); ++ LM_INFO(" %s value: \n", name, avp->val.v.vptr); + break; + case SR_XTYPE_DATA: +- LM_INFO(" XAVP value: \n", avp->val.v.data); ++ LM_INFO(" %s value: \n", name, avp->val.v.data); + break; + } + LM_INFO(" *** (l:%d - %p) end\n", level, avp); + avp = avp->next; + } +- LM_INFO("----- end XAVP list: %p (level=%d)\n", start, level); ++ LM_INFO("----- end %s list: %p (level=%d)\n", name, start, level); ++} ++ ++void xavp_print_list_content(sr_xavp_t **head, int level) ++{ ++ xavx_print_list_content("XAVP", head, _xavp_list_crt, level); + } + + void xavp_print_list(sr_xavp_t **head) +@@ -1072,3 +1083,986 @@ int xavp_serialize_fields(str *rname, char *obuf, int olen) + } + return rlen; + } ++ ++ ++ ++/** ++ * ++ */ ++/*** XAVI - eXtended Attribute Value Insensitive case - implementation ***/ ++/*! Helper functions */ ++static sr_xavp_t *xavi_get_internal(str *name, sr_xavp_t **list, int idx, sr_xavp_t **prv); ++static int xavi_rm_internal(str *name, sr_xavp_t **head, int idx); ++ ++/** ++ * ++ */ ++static sr_xavp_t *xavi_new_value(str *name, sr_xval_t *val) ++{ ++ sr_xavp_t *avi; ++ int size; ++ unsigned int id; ++ ++ if(name==NULL || name->s==NULL || val==NULL) ++ return NULL; ++ id = get_hash1_case_raw(name->s, name->len); ++ ++ size = sizeof(sr_xavp_t) + name->len + 1; ++ if(val->type == SR_XTYPE_STR) ++ size += val->v.s.len + 1; ++ avi = (sr_xavp_t*)shm_malloc(size); ++ if(avi==NULL) { ++ SHM_MEM_ERROR; ++ return NULL; ++ } ++ memset(avi, 0, size); ++ avi->id = id; ++ avi->name.s = (char*)avi + sizeof(sr_xavp_t); ++ memcpy(avi->name.s, name->s, name->len); ++ avi->name.s[name->len] = '\0'; ++ avi->name.len = name->len; ++ memcpy(&avi->val, val, sizeof(sr_xval_t)); ++ if(val->type == SR_XTYPE_STR) ++ { ++ avi->val.v.s.s = avi->name.s + avi->name.len + 1; ++ memcpy(avi->val.v.s.s, val->v.s.s, val->v.s.len); ++ avi->val.v.s.s[val->v.s.len] = '\0'; ++ avi->val.v.s.len = val->v.s.len; ++ } ++ ++ return avi; ++} ++ ++/** ++ * ++ */ ++int xavi_add(sr_xavp_t *xavi, sr_xavp_t **list) ++{ ++ if (xavi==NULL) { ++ return -1; ++ } ++ /* Prepend new xavi to the list */ ++ if(list) { ++ xavi->next = *list; ++ *list = xavi; ++ } else { ++ xavi->next = *_xavi_list_crt; ++ *_xavi_list_crt = xavi; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ++ */ ++int xavi_add_last(sr_xavp_t *xavi, sr_xavp_t **list) ++{ ++ sr_xavp_t *prev; ++ sr_xavp_t *crt; ++ ++ if (xavi==NULL) { ++ return -1; ++ } ++ ++ crt = xavi_get_internal(&xavi->name, list, 0, 0); ++ ++ prev = NULL; ++ ++ while(crt) { ++ prev = crt; ++ crt = xavi_get_next(prev); ++ } ++ ++ if(prev==NULL) { ++ /* Prepend new xavi to the list */ ++ if(list) { ++ xavi->next = *list; ++ *list = xavi; ++ } else { ++ xavi->next = *_xavi_list_crt; ++ *_xavi_list_crt = xavi; ++ } ++ } else { ++ xavi->next = prev->next; ++ prev->next = xavi; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ++ */ ++int xavi_add_after(sr_xavp_t *nxavi, sr_xavp_t *pxavi) ++{ ++ if (nxavi==NULL) { ++ return -1; ++ } ++ ++ if(pxavi==NULL) { ++ nxavi->next = *_xavi_list_crt; ++ *_xavi_list_crt = nxavi; ++ } else { ++ nxavi->next = pxavi->next; ++ pxavi->next = nxavi; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ++ */ ++sr_xavp_t *xavi_add_value(str *name, sr_xval_t *val, sr_xavp_t **list) ++{ ++ sr_xavp_t *avi=0; ++ ++ avi = xavi_new_value(name, val); ++ if (avi==NULL) ++ return NULL; ++ ++ /* Prepend new value to the list */ ++ if(list) { ++ avi->next = *list; ++ *list = avi; ++ } else { ++ avi->next = *_xavi_list_crt; ++ *_xavi_list_crt = avi; ++ } ++ ++ return avi; ++} ++ ++/** ++ * ++ */ ++sr_xavp_t *xavi_add_value_after(str *name, sr_xval_t *val, sr_xavp_t *pxavi) ++{ ++ sr_xavp_t *avi=0; ++ ++ avi = xavi_new_value(name, val); ++ if (avi==NULL) ++ return NULL; ++ ++ /* link new xavi */ ++ if(pxavi) { ++ avi->next = pxavi->next; ++ pxavi->next = avi; ++ } else { ++ avi->next = *_xavi_list_crt; ++ *_xavi_list_crt = avi; ++ } ++ ++ return avi; ++} ++ ++/** ++ * ++ */ ++sr_xavp_t *xavi_add_xavi_value(str *rname, str *name, sr_xval_t *val, sr_xavp_t **list) ++{ ++ sr_xavp_t *ravi=0; ++ sr_xavp_t *cavi=0; ++ sr_xval_t rval; ++ ++ cavi = xavi_new_value(name, val); ++ if (cavi==NULL) ++ return NULL; ++ ++ memset(&rval, 0, sizeof(sr_xval_t)); ++ rval.type = SR_XTYPE_XAVP; ++ rval.v.xavp = cavi; ++ ++ ravi = xavi_new_value(rname, &rval); ++ if (ravi==NULL) { ++ xavi_destroy_list(&cavi); ++ return NULL; ++ } ++ ++ /* Prepend new value to the list */ ++ if(list) { ++ ravi->next = *list; ++ *list = ravi; ++ } else { ++ ravi->next = *_xavi_list_crt; ++ *_xavi_list_crt = ravi; ++ } ++ ++ return ravi; ++} ++ ++/** ++ * ++ */ ++sr_xavp_t *xavi_set_value(str *name, int idx, sr_xval_t *val, sr_xavp_t **list) ++{ ++ sr_xavp_t *avi; ++ sr_xavp_t *cur; ++ sr_xavp_t *prv=0; ++ ++ if(val==NULL) ++ return NULL; ++ ++ /* Find the current value */ ++ cur = xavi_get_internal(name, list, idx, &prv); ++ if(cur==NULL) ++ return NULL; ++ ++ avi = xavi_new_value(name, val); ++ if (avi==NULL) ++ return NULL; ++ ++ /* Replace the current value with the new */ ++ avi->next = cur->next; ++ if(prv) ++ prv->next = avi; ++ else if(list) ++ *list = avi; ++ else ++ *_xavi_list_crt = avi; ++ ++ xavi_free(cur); ++ ++ return avi; ++} ++ ++/** ++ * ++ */ ++static sr_xavp_t *xavi_get_internal(str *name, sr_xavp_t **list, int idx, sr_xavp_t **prv) ++{ ++ sr_xavp_t *avi; ++ unsigned int id; ++ int n = 0; ++ ++ if(name==NULL || name->s==NULL) ++ return NULL; ++ id = get_hash1_case_raw(name->s, name->len); ++ ++ if(list && *list) ++ avi = *list; ++ else ++ avi = *_xavi_list_crt; ++ while(avi) ++ { ++ if(avi->id==id && avi->name.len==name->len ++ && strncasecmp(avi->name.s, name->s, name->len)==0) ++ { ++ if(idx==n) ++ return avi; ++ n++; ++ } ++ if(prv) ++ *prv = avi; ++ avi = avi->next; ++ } ++ return NULL; ++} ++ ++/** ++ * ++ */ ++sr_xavp_t *xavi_get(str *name, sr_xavp_t *start) ++{ ++ return xavi_get_internal(name, (start)?&start:NULL, 0, NULL); ++} ++ ++/** ++ * ++ */ ++sr_xavp_t *xavi_get_by_index(str *name, int idx, sr_xavp_t **start) ++{ ++ return xavi_get_internal(name, start, idx, NULL); ++} ++ ++/** ++ * ++ */ ++sr_xavp_t *xavi_get_next(sr_xavp_t *start) ++{ ++ sr_xavp_t *avi; ++ ++ if(start==NULL) ++ return NULL; ++ ++ avi = start->next; ++ while(avi) ++ { ++ if(avi->id==start->id && avi->name.len==start->name.len ++ && strncasecmp(avi->name.s, start->name.s, start->name.len)==0) ++ return avi; ++ avi=avi->next; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * ++ */ ++sr_xavp_t *xavi_get_last(str *xname, sr_xavp_t **list) ++{ ++ sr_xavp_t *prev; ++ sr_xavp_t *crt; ++ ++ crt = xavi_get_internal(xname, list, 0, 0); ++ ++ prev = NULL; ++ ++ while(crt) { ++ prev = crt; ++ crt = xavi_get_next(prev); ++ } ++ ++ return prev; ++} ++ ++/** ++ * ++ */ ++int xavi_rm(sr_xavp_t *xa, sr_xavp_t **head) ++{ ++ sr_xavp_t *avi; ++ sr_xavp_t *prv=0; ++ ++ if(head!=NULL) ++ avi = *head; ++ else ++ avi=*_xavi_list_crt; ++ ++ while(avi) ++ { ++ if(avi==xa) ++ { ++ if(prv) ++ prv->next=avi->next; ++ else if(head!=NULL) ++ *head = avi->next; ++ else ++ *_xavi_list_crt = avi->next; ++ xavi_free(avi); ++ return 1; ++ } ++ prv=avi; avi=avi->next; ++ } ++ return 0; ++} ++ ++/* Remove xavis ++ * idx: <0 remove all xavis with the same name ++ * >=0 remove only the specified index xavi ++ * Returns number of xavis that were deleted ++ */ ++static int xavi_rm_internal(str *name, sr_xavp_t **head, int idx) ++{ ++ sr_xavp_t *avi; ++ sr_xavp_t *foo; ++ sr_xavp_t *prv=0; ++ unsigned int id; ++ int n=0; ++ int count=0; ++ ++ if(name==NULL || name->s==NULL) ++ return 0; ++ ++ id = get_hash1_case_raw(name->s, name->len); ++ if(head!=NULL) ++ avi = *head; ++ else ++ avi = *_xavi_list_crt; ++ while(avi) ++ { ++ foo = avi; ++ avi=avi->next; ++ if(foo->id==id && foo->name.len==name->len ++ && strncasecmp(foo->name.s, name->s, name->len)==0) ++ { ++ if(idx<0 || idx==n) ++ { ++ if(prv!=NULL) ++ prv->next=foo->next; ++ else if(head!=NULL) ++ *head = foo->next; ++ else ++ *_xavi_list_crt = foo->next; ++ xavi_free(foo); ++ if(idx>=0) ++ return 1; ++ count++; ++ } ++ n++; ++ } else { ++ prv = foo; ++ } ++ } ++ return count; ++} ++ ++/** ++ * ++ */ ++int xavi_rm_by_name(str *name, int all, sr_xavp_t **head) ++{ ++ return xavi_rm_internal(name, head, -1*all); ++} ++ ++/** ++ * ++ */ ++int xavi_rm_by_index(str *name, int idx, sr_xavp_t **head) ++{ ++ if (idx<0) ++ return 0; ++ return xavi_rm_internal(name, head, idx); ++} ++ ++/** ++ * ++ */ ++int xavi_rm_child_by_index(str *rname, str *cname, int idx) ++{ ++ sr_xavp_t *avi=NULL; ++ ++ if (idx<0) { ++ return 0; ++ } ++ avi = xavi_get(rname, NULL); ++ ++ if(avi == NULL || avi->val.type!=SR_XTYPE_XAVP) { ++ return 0; ++ } ++ return xavi_rm_internal(cname, &avi->val.v.xavp, idx); ++} ++ ++/** ++ * ++ */ ++int xavi_count(str *name, sr_xavp_t **start) ++{ ++ sr_xavp_t *avi; ++ unsigned int id; ++ int n = 0; ++ ++ if(name==NULL || name->s==NULL) ++ return -1; ++ id = get_hash1_case_raw(name->s, name->len); ++ ++ if(start) ++ avi = *start; ++ else ++ avi=*_xavi_list_crt; ++ while(avi) ++ { ++ if(avi->id==id && avi->name.len==name->len ++ && strncasecmp(avi->name.s, name->s, name->len)==0) ++ { ++ n++; ++ } ++ avi=avi->next; ++ } ++ ++ return n; ++} ++ ++/** ++ * ++ */ ++void xavi_reset_list(void) ++{ ++ assert(_xavi_list_crt!=0 ); ++ ++ if (_xavi_list_crt!=&_xavi_list_head) ++ _xavi_list_crt=&_xavi_list_head; ++ xavi_destroy_list(_xavi_list_crt); ++} ++ ++/** ++ * ++ */ ++sr_xavp_t **xavi_set_list(sr_xavp_t **head) ++{ ++ sr_xavp_t **avi; ++ ++ assert(_xavi_list_crt!=0); ++ ++ avi = _xavi_list_crt; ++ _xavi_list_crt = head; ++ return avi; ++} ++ ++/** ++ * ++ */ ++sr_xavp_t **xavi_get_crt_list(void) ++{ ++ assert(_xavi_list_crt!=0); ++ return _xavi_list_crt; ++} ++ ++/** ++ * ++ */ ++void xavi_print_list_content(sr_xavp_t **head, int level) ++{ ++ xavx_print_list_content("XAVI", head, _xavi_list_crt, level); ++} ++ ++/** ++ * ++ */ ++void xavi_print_list(sr_xavp_t **head) ++{ ++ xavi_print_list_content(head, 0); ++} ++ ++/** ++ * returns a list of str with key names. ++ * Example: ++ * If we have this structure ++ * $xavi(test=>one) = 1 ++ * $xavi(test[0]=>two) = "2" ++ * $xavi(test[0]=>three) = 3 ++ * $xavi(test[0]=>four) = $xavp(whatever) ++ * $xavi(test[0]=>two) = "other 2" ++ * ++ * xavi_get_list_keys_names(test[0]) returns ++ * {"one", "two", "three", "four"} ++ * ++ * free the struct str_list afterwards ++ * but do *NOT* free the strings inside ++ */ ++struct str_list *xavi_get_list_key_names(sr_xavp_t *xavi) ++{ ++ sr_xavp_t *avi = NULL; ++ struct str_list *result = NULL; ++ struct str_list *r = NULL; ++ struct str_list *f = NULL; ++ int total = 0; ++ ++ if(xavi==NULL){ ++ LM_ERR("xavi is NULL\n"); ++ return 0; ++ } ++ ++ if(xavi->val.type!=SR_XTYPE_XAVP){ ++ LM_ERR("%s not xavp?\n", xavi->name.s); ++ return 0; ++ } ++ ++ avi = xavi->val.v.xavp; ++ ++ if (avi) ++ { ++ result = (struct str_list*)pkg_malloc(sizeof(struct str_list)); ++ if (result==NULL) { ++ PKG_MEM_ERROR; ++ return 0; ++ } ++ r = result; ++ r->s.s = avi->name.s; ++ r->s.len = avi->name.len; ++ r->next = NULL; ++ avi = avi->next; ++ } ++ ++ while(avi) ++ { ++ f = result; ++ while(f) ++ { ++ if((avi->name.len==f->s.len)&& ++ (strncasecmp(avi->name.s, f->s.s, f->s.len)==0)) ++ { ++ break; /* name already on list */ ++ } ++ f = f->next; ++ } ++ if (f==NULL) ++ { ++ r = append_str_list(avi->name.s, avi->name.len, &r, &total); ++ if(r==NULL){ ++ while(result){ ++ r = result; ++ result = result->next; ++ pkg_free(r); ++ } ++ return 0; ++ } ++ } ++ avi = avi->next; ++ } ++ return result; ++} ++ ++sr_xavp_t *xavi_clone_level_nodata(sr_xavp_t *xold) ++{ ++ return xavi_clone_level_nodata_with_new_name(xold, &xold->name); ++} ++ ++/** ++ * clone the xavi without values that are custom data ++ * - only one list level is cloned, other sublists are ignored ++ */ ++sr_xavp_t *xavi_clone_level_nodata_with_new_name(sr_xavp_t *xold, str *dst_name) ++{ ++ sr_xavp_t *xnew = NULL; ++ sr_xavp_t *navi = NULL; ++ sr_xavp_t *oavi = NULL; ++ sr_xavp_t *pavi = NULL; ++ ++ if(xold == NULL) ++ { ++ return NULL; ++ } ++ if(xold->val.type==SR_XTYPE_DATA || xold->val.type==SR_XTYPE_SPTR) ++ { ++ LM_INFO("xavi value type is 'data' - ignoring in clone\n"); ++ return NULL; ++ } ++ xnew = xavi_new_value(dst_name, &xold->val); ++ if(xnew==NULL) ++ { ++ LM_ERR("cannot create cloned root xavi\n"); ++ return NULL; ++ } ++ LM_DBG("cloned root xavi [%.*s] >> [%.*s]\n", xold->name.len, xold->name.s, dst_name->len, dst_name->s); ++ ++ if(xold->val.type!=SR_XTYPE_XAVP) ++ { ++ return xnew; ++ } ++ ++ xnew->val.v.xavp = NULL; ++ oavi = xold->val.v.xavp; ++ ++ while(oavi) ++ { ++ if(oavi->val.type!=SR_XTYPE_DATA && oavi->val.type!=SR_XTYPE_XAVP ++ && oavi->val.type!=SR_XTYPE_SPTR) ++ { ++ navi = xavi_new_value(&oavi->name, &oavi->val); ++ if(navi==NULL) ++ { ++ LM_ERR("cannot create cloned embedded xavi\n"); ++ if(xnew->val.v.xavp != NULL) { ++ xavi_destroy_list(&xnew->val.v.xavp); ++ } ++ shm_free(xnew); ++ return NULL; ++ } ++ LM_DBG("cloned inner xavi [%.*s]\n", oavi->name.len, oavi->name.s); ++ if(xnew->val.v.xavp == NULL) ++ { ++ /* link to val in head xavi */ ++ xnew->val.v.xavp = navi; ++ } else { ++ /* link to prev xavi in the list */ ++ pavi->next = navi; ++ } ++ pavi = navi; ++ } ++ oavi = oavi->next; ++ } ++ ++ if(xnew->val.v.xavp == NULL) ++ { ++ shm_free(xnew); ++ return NULL; ++ } ++ ++ return xnew; ++} ++ ++int xavi_insert(sr_xavp_t *xavi, int idx, sr_xavp_t **list) ++{ ++ sr_xavp_t *crt = 0; ++ sr_xavp_t *lst = 0; ++ sr_xval_t val; ++ int n = 0; ++ int i = 0; ++ ++ if(xavi==NULL) { ++ return -1; ++ } ++ ++ crt = xavi_get_internal(&xavi->name, list, 0, NULL); ++ ++ if (idx == 0 && (!crt || crt->val.type != SR_XTYPE_NULL)) ++ return xavi_add(xavi, list); ++ ++ while(crt!=NULL && nval.type == SR_XTYPE_NULL) { ++ xavi->next = crt->next; ++ crt->next = xavi; ++ ++ xavi_rm(crt, list); ++ return 0; ++ } ++ ++ memset(&val, 0, sizeof(sr_xval_t)); ++ val.type = SR_XTYPE_NULL; ++ for(i=0; iname, &val); ++ if(crt==NULL) ++ return -1; ++ if (lst == NULL) { ++ xavi_add(crt, list); ++ } else { ++ crt->next = lst->next; ++ lst->next = crt; ++ } ++ lst = crt; ++ } ++ ++ if(lst==NULL) { ++ LM_ERR("cannot link the xavi\n"); ++ return -1; ++ } ++ xavi->next = lst->next; ++ lst->next = xavi; ++ ++ return 0; ++} ++ ++sr_xavp_t *xavi_extract(str *name, sr_xavp_t **list) ++{ ++ sr_xavp_t *avi = 0; ++ sr_xavp_t *foo; ++ sr_xavp_t *prv = 0; ++ unsigned int id; ++ ++ if(name==NULL || name->s==NULL) { ++ if(list!=NULL) { ++ avi = *list; ++ if(avi!=NULL) { ++ *list = avi->next; ++ avi->next = NULL; ++ } ++ } else { ++ avi = *_xavi_list_crt; ++ if(avi!=NULL) { ++ *_xavi_list_crt = avi->next; ++ avi->next = NULL; ++ } ++ } ++ ++ return avi; ++ } ++ ++ id = get_hash1_case_raw(name->s, name->len); ++ if(list!=NULL) ++ avi = *list; ++ else ++ avi = *_xavi_list_crt; ++ while(avi) ++ { ++ foo = avi; ++ avi=avi->next; ++ if(foo->id==id && foo->name.len==name->len ++ && strncasecmp(foo->name.s, name->s, name->len)==0) ++ { ++ if(prv!=NULL) ++ prv->next=foo->next; ++ else if(list!=NULL) ++ *list = foo->next; ++ else ++ *_xavi_list_crt = foo->next; ++ foo->next = NULL; ++ return foo; ++ } else { ++ prv = foo; ++ } ++ } ++ return NULL; ++} ++ ++/** ++ * return child node of an xavi ++ * - $xavi(rname=>cname) ++ */ ++sr_xavp_t* xavi_get_child(str *rname, str *cname) ++{ ++ sr_xavp_t *ravi=NULL; ++ ++ ravi = xavi_get(rname, NULL); ++ if(ravi==NULL || ravi->val.type!=SR_XTYPE_XAVP) ++ return NULL; ++ ++ return xavi_get(cname, ravi->val.v.xavp); ++} ++ ++ ++/** ++ * return child node of an xavi if it has int value ++ * - $xavi(rname=>cname) ++ */ ++sr_xavp_t* xavi_get_child_with_ival(str *rname, str *cname) ++{ ++ sr_xavp_t *vavi=NULL; ++ ++ vavi = xavi_get_child(rname, cname); ++ ++ if(vavi==NULL || vavi->val.type!=SR_XTYPE_INT) ++ return NULL; ++ ++ return vavi; ++} ++ ++ ++/** ++ * return child node of an xavi if it has string value ++ * - $xavi(rname=>cname) ++ */ ++sr_xavp_t* xavi_get_child_with_sval(str *rname, str *cname) ++{ ++ sr_xavp_t *vavi=NULL; ++ ++ vavi = xavi_get_child(rname, cname); ++ ++ if(vavi==NULL || vavi->val.type!=SR_XTYPE_STR) ++ return NULL; ++ ++ return vavi; ++} ++ ++/** ++ * Set the value of the first xavi rname with first child xavi cname ++ * - replace if it exits; add if it doesn't exist ++ * - config operations: ++ * $xavi(rxname=>cname) = xval; ++ * or: ++ * $xavi(rxname[0]=>cname[0]) = xval; ++ */ ++int xavi_set_child_xval(str *rname, str *cname, sr_xval_t *xval) ++{ ++ sr_xavp_t *ravi=NULL; ++ sr_xavp_t *cavi=NULL; ++ ++ ravi = xavi_get(rname, NULL); ++ if(ravi) { ++ if(ravi->val.type != SR_XTYPE_XAVP) { ++ /* first root xavi does not have xavi list value - remove it */ ++ xavi_rm(ravi, NULL); ++ /* add a new xavi in the root list with a child */ ++ if(xavi_add_xavi_value(rname, cname, xval, NULL)==NULL) { ++ return -1; ++ } ++ } else { ++ /* first root xavi has an xavi list value */ ++ cavi = xavi_get(cname, ravi->val.v.xavp); ++ if(cavi) { ++ /* child xavi with same name - remove it */ ++ /* todo: update in place for int or if allocated size fits */ ++ xavi_rm(cavi, &ravi->val.v.xavp); ++ } ++ if(xavi_add_value(cname, xval, &ravi->val.v.xavp)==NULL) { ++ return -1; ++ } ++ } ++ } else { ++ /* no xavi with rname in root list found */ ++ if(xavi_add_xavi_value(rname, cname, xval, NULL)==NULL) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * ++ */ ++int xavi_set_child_ival(str *rname, str *cname, int ival) ++{ ++ sr_xval_t xval; ++ ++ memset(&xval, 0, sizeof(sr_xval_t)); ++ xval.type = SR_XTYPE_INT; ++ xval.v.i = ival; ++ ++ return xavi_set_child_xval(rname, cname, &xval); ++} ++ ++/** ++ * ++ */ ++int xavi_set_child_sval(str *rname, str *cname, str *sval) ++{ ++ sr_xval_t xval; ++ ++ memset(&xval, 0, sizeof(sr_xval_t)); ++ xval.type = SR_XTYPE_STR; ++ xval.v.s = *sval; ++ ++ return xavi_set_child_xval(rname, cname, &xval); ++} ++ ++/** ++ * serialize the values in subfields of an xavi in name=value; format ++ * - rname - name of the root list xavi ++ * - obuf - buffer were to write the output ++ * - olen - the size of obuf ++ * return: 0 - not found; -1 - error; >0 - length of output ++ */ ++int xavi_serialize_fields(str *rname, char *obuf, int olen) ++{ ++ sr_xavp_t *ravi = NULL; ++ sr_xavp_t *avi = NULL; ++ str ostr; ++ int rlen; ++ ++ ravi = xavi_get(rname, NULL); ++ if(ravi==NULL || ravi->val.type!=SR_XTYPE_XAVP) { ++ /* not found or not holding subfields */ ++ return 0; ++ } ++ ++ rlen = 0; ++ ostr.s = obuf; ++ avi = ravi->val.v.xavp; ++ while(avi) { ++ switch(avi->val.type) { ++ case SR_XTYPE_INT: ++ LM_DBG(" XAVP int value: %d\n", avi->val.v.i); ++ ostr.len = snprintf(ostr.s, olen-rlen, "%.*s=%u;", ++ avi->name.len, avi->name.s, (unsigned int)avi->val.v.i); ++ if(ostr.len<=0 || ostr.len>=olen-rlen) { ++ LM_ERR("failed to serialize int value (%d/%d\n", ++ ostr.len, olen-rlen); ++ return -1; ++ } ++ break; ++ case SR_XTYPE_STR: ++ LM_DBG(" XAVP str value: %s\n", avi->val.v.s.s); ++ if(avi->val.v.s.len == 0) { ++ ostr.len = snprintf(ostr.s, olen-rlen, "%.*s;", ++ avi->name.len, avi->name.s); ++ } else { ++ ostr.len = snprintf(ostr.s, olen-rlen, "%.*s=%.*s;", ++ avi->name.len, avi->name.s, ++ avi->val.v.s.len, avi->val.v.s.s); ++ } ++ if(ostr.len<=0 || ostr.len>=olen-rlen) { ++ LM_ERR("failed to serialize int value (%d/%d\n", ++ ostr.len, olen-rlen); ++ return -1; ++ } ++ break; ++ default: ++ LM_DBG("skipping value type: %d\n", avi->val.type); ++ ostr.len = 0; ++ } ++ if(ostr.len>0) { ++ ostr.s += ostr.len; ++ rlen += ostr.len; ++ } ++ avi = avi->next; ++ } ++ return rlen; ++} +diff --git a/src/core/xavp.h b/src/core/xavp.h +index 071a421..d58f21d 100644 +--- a/src/core/xavp.h ++++ b/src/core/xavp.h +@@ -111,4 +111,47 @@ int xavp_serialize_fields(str *rname, char *obuf, int olen); + int xavp_set_child_ival(str *rname, str *cname, int ival); + int xavp_set_child_sval(str *rname, str *cname, str *sval); + ++/** xavi api */ ++int xavi_init_head(void); ++#define xavi_free xavp_free ++ ++int xavi_add(sr_xavp_t *xavp, sr_xavp_t **list); ++int xavi_add_last(sr_xavp_t *xavp, sr_xavp_t **list); ++int xavi_add_after(sr_xavp_t *nxavp, sr_xavp_t *pxavp); ++sr_xavp_t *xavi_add_value(str *name, sr_xval_t *val, sr_xavp_t **list); ++sr_xavp_t *xavi_add_value_after(str *name, sr_xval_t *val, sr_xavp_t *pxavp); ++sr_xavp_t *xavi_add_xavi_value(str *rname, str *name, sr_xval_t *val, sr_xavp_t **list); ++sr_xavp_t *xavi_set_value(str *name, int idx, sr_xval_t *val, sr_xavp_t **list); ++sr_xavp_t *xavi_get(str *name, sr_xavp_t *start); ++sr_xavp_t *xavi_get_by_index(str *name, int idx, sr_xavp_t **start); ++sr_xavp_t *xavi_get_next(sr_xavp_t *start); ++sr_xavp_t *xavi_get_last(str *xname, sr_xavp_t **list); ++int xavi_rm_by_name(str *name, int all, sr_xavp_t **head); ++int xavi_rm_by_index(str *name, int idx, sr_xavp_t **head); ++int xavi_rm(sr_xavp_t *xa, sr_xavp_t **head); ++int xavi_rm_child_by_index(str *rname, str *cname, int idx); ++int xavi_count(str *name, sr_xavp_t **start); ++#define xavi_destroy_list_unsafe xavp_destroy_list_unsafe ++#define xavi_destroy_list xavp_destroy_list ++void xavi_reset_list(void); ++sr_xavp_t **xavi_set_list(sr_xavp_t **head); ++sr_xavp_t **xavi_get_crt_list(void); ++struct str_list *xavi_get_list_key_names(sr_xavp_t *xavp); ++ ++int xavi_insert(sr_xavp_t *xavp, int idx, sr_xavp_t **list); ++sr_xavp_t *xavi_extract(str *name, sr_xavp_t **list); ++ ++void xavi_print_list(sr_xavp_t **head); ++ ++sr_xavp_t *xavi_clone_level_nodata(sr_xavp_t *xold); ++sr_xavp_t *xavi_clone_level_nodata_with_new_name(sr_xavp_t *xold, str *dst_name); ++ ++sr_xavp_t* xavi_get_child(str *rname, str *cname); ++sr_xavp_t* xavi_get_child_with_ival(str *rname, str *cname); ++sr_xavp_t* xavi_get_child_with_sval(str *rname, str *cname); ++int xavi_serialize_fields(str *rname, char *obuf, int olen); ++ ++int xavi_set_child_ival(str *rname, str *cname, int ival); ++int xavi_set_child_sval(str *rname, str *cname, str *sval); ++ + #endif diff --git a/debian/patches/upstream/pv-define-xavi-types.patch b/debian/patches/upstream/pv-define-xavi-types.patch new file mode 100644 index 000000000..f45c89033 --- /dev/null +++ b/debian/patches/upstream/pv-define-xavi-types.patch @@ -0,0 +1,23 @@ +From: Victor Seva +Date: Wed, 27 May 2020 08:59:08 +0200 +Subject: pv - define xavi types + +--- + src/core/pvar.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/pvar.h b/src/core/pvar.h +index 2a249ea..c1dd9f3 100644 +--- a/src/core/pvar.h ++++ b/src/core/pvar.h +@@ -77,8 +77,8 @@ enum _pv_type { + PVT_DSTURI, PVT_COLOR, PVT_BRANCH, + PVT_FROM, PVT_TO, PVT_OURI, + PVT_SCRIPTVAR, PVT_MSG_BODY, PVT_CONTEXT, +- PVT_XAVP, PVT_HDRC, PVT_OTHER, +- PVT_EXTRA /* keep it last */ ++ PVT_XAVP, PVT_XAVI, PVT_HDRC, ++ PVT_OTHER, PVT_EXTRA /* keep it last */ + }; + + typedef enum _pv_type pv_type_t; diff --git a/debian/patches/upstream/pv-xavi-.-config-variables-implementation.patch b/debian/patches/upstream/pv-xavi-.-config-variables-implementation.patch new file mode 100644 index 000000000..c6181aee7 --- /dev/null +++ b/debian/patches/upstream/pv-xavi-.-config-variables-implementation.patch @@ -0,0 +1,1389 @@ +From: Victor Seva +Date: Wed, 27 May 2020 09:23:46 +0200 +Subject: pv: $xavi(...) config variables implementation + +same as $xavp but case insensitive for keys +--- + src/modules/pv/pv.c | 539 ++++++++++++++++++++++++++++++++++++++++------- + src/modules/pv/pv_xavp.c | 416 ++++++++++++++++++++++++++++++++++++ + src/modules/pv/pv_xavp.h | 7 + + 3 files changed, 891 insertions(+), 71 deletions(-) + +diff --git a/src/modules/pv/pv.c b/src/modules/pv/pv.c +index 2bbc77b..a92ea5a 100644 +--- a/src/modules/pv/pv.c ++++ b/src/modules/pv/pv.c +@@ -31,6 +31,7 @@ + #include "../../core/kemi.h" + #include "../../core/rpc.h" + #include "../../core/rpc_lookup.h" ++#include "../../core/strutils.h" + + + #include "pv_branch.h" +@@ -93,6 +94,9 @@ static pv_export_t mod_pvs[] = { + { {"xavp", sizeof("xavp")-1}, /* xavp */ + PVT_XAVP, pv_get_xavp, pv_set_xavp, + pv_parse_xavp_name, 0, 0, 0 }, ++ { {"xavi", sizeof("xavi")-1}, /* xavi */ ++ PVT_XAVI, pv_get_xavi, pv_set_xavi, ++ pv_parse_xavp_name, 0, 0, 0 }, + {{"avp", (sizeof("avp")-1)}, PVT_AVP, pv_get_avp, pv_set_avp, + pv_parse_avp_name, pv_parse_index, 0, 0}, + {{"hdr", (sizeof("hdr")-1)}, PVT_HDR, pv_get_hdr, 0, pv_parse_hdr_name, +@@ -549,6 +553,13 @@ static int w_sbranch_reset(sip_msg_t *msg, char p1, char *p2); + static int w_var_to_xavp(sip_msg_t *msg, char *p1, char *p2); + static int w_xavp_to_var(sip_msg_t *msg, char *p1); + ++static int w_xavi_child_seti(sip_msg_t *msg, char *prname, char *pcname, ++ char *pval); ++static int w_xavi_child_sets(sip_msg_t *msg, char *prname, char *pcname, ++ char *pval); ++static int w_xavi_rm(sip_msg_t *msg, char *prname, char *p2); ++static int w_xavi_child_rm(sip_msg_t *msg, char *prname, char *pcname); ++ + int pv_evalx_fixup(void** param, int param_no); + int w_pv_evalx(struct sip_msg *msg, char *dst, str *fmt); + +@@ -565,6 +576,8 @@ static cmd_export_t cmds[]={ + ANY_ROUTE }, + {"pv_xavp_print", (cmd_function)pv_xavp_print, 0, 0, 0, + ANY_ROUTE }, ++ {"pv_xavi_print", (cmd_function)pv_xavi_print, 0, 0, 0, ++ ANY_ROUTE }, + {"pv_var_to_xavp", (cmd_function)w_var_to_xavp, 2, fixup_spve_spve, + fixup_free_spve_spve, ANY_ROUTE }, + {"pv_xavp_to_var", (cmd_function)w_xavp_to_var, 1, fixup_spve_null, +@@ -595,6 +608,18 @@ static cmd_export_t cmds[]={ + {"xavp_child_rm", (cmd_function)w_xavp_child_rm, + 2, fixup_spve_spve, fixup_free_spve_spve, + ANY_ROUTE}, ++ {"xavi_child_seti", (cmd_function)w_xavi_child_seti, ++ 3, fixup_xavp_child_seti, fixup_free_xavp_child_seti, ++ ANY_ROUTE}, ++ {"xavi_child_sets", (cmd_function)w_xavi_child_sets, ++ 3, fixup_spve_all, fixup_free_spve_all, ++ ANY_ROUTE}, ++ {"xavi_rm", (cmd_function)w_xavi_rm, ++ 1, fixup_spve_null, fixup_free_spve_null, ++ ANY_ROUTE}, ++ {"xavi_child_rm", (cmd_function)w_xavi_child_rm, ++ 2, fixup_spve_spve, fixup_free_spve_spve, ++ ANY_ROUTE}, + {"sbranch_set_ruri", (cmd_function)w_sbranch_set_ruri, 0, 0, 0, + ANY_ROUTE }, + {"sbranch_append", (cmd_function)w_sbranch_append, 0, 0, 0, +@@ -811,6 +836,12 @@ static int ki_xavp_print(sip_msg_t* msg) + return 1; + } + ++static int ki_xavi_print(sip_msg_t* msg) ++{ ++ xavi_print_list(NULL); ++ return 1; ++} ++ + /** + * + */ +@@ -905,7 +936,7 @@ static int w_xavp_params_implode(sip_msg_t *msg, char *pxname, char *pvname) + /** + * + */ +-static int ki_xavp_seti(sip_msg_t *msg, str *rname, int ival) ++static int ki_xav_seti(sip_msg_t *msg, str *rname, int ival, int _case) + { + sr_xavp_t *xavp = NULL; + sr_xval_t xval; +@@ -914,15 +945,28 @@ static int ki_xavp_seti(sip_msg_t *msg, str *rname, int ival) + xval.type = SR_XTYPE_INT; + xval.v.i = ival; + +- xavp = xavp_add_value(rname, &xval, NULL); +- ++ if(_case) { ++ xavp = xavi_add_value(rname, &xval, NULL); ++ } else { ++ xavp = xavp_add_value(rname, &xval, NULL); ++ } + return (xavp!=NULL)?1:-1; + } + ++static int ki_xavp_seti(sip_msg_t *msg, str *rname, int ival) ++{ ++ return ki_xav_seti(msg, rname, ival, 0); ++} ++ ++static int ki_xavi_seti(sip_msg_t *msg, str *rname, int ival) ++{ ++ return ki_xav_seti(msg, rname, ival, 1); ++} ++ + /** + * + */ +-static int ki_xavp_sets(sip_msg_t *msg, str *rname, str *sval) ++static int ki_xav_sets(sip_msg_t *msg, str *rname, str *sval, int _case) + { + sr_xavp_t *xavp = NULL; + sr_xval_t xval; +@@ -931,29 +975,56 @@ static int ki_xavp_sets(sip_msg_t *msg, str *rname, str *sval) + xval.type = SR_XTYPE_STR; + xval.v.s = *sval; + +- xavp = xavp_add_value(rname, &xval, NULL); +- ++ if(_case) { ++ xavp = xavi_add_value(rname, &xval, NULL); ++ } else { ++ xavp = xavp_add_value(rname, &xval, NULL); ++ } + return (xavp!=NULL)?1:-1; + } + ++static int ki_xavp_sets(sip_msg_t *msg, str *rname, str *sval) ++{ ++ return ki_xav_sets(msg, rname, sval, 0); ++} ++ ++static int ki_xavi_sets(sip_msg_t *msg, str *rname, str *sval) ++{ ++ return ki_xav_sets(msg, rname, sval, 1); ++} ++ + /** + * + */ +-static int ki_xavp_child_seti(sip_msg_t *msg, str *rname, str *cname, +- int ival) ++static int ki_xav_child_seti(sip_msg_t *msg, str *rname, str *cname, ++ int ival, int _case) + { + int ret; ++ if(_case) { ++ ret = xavi_set_child_ival(rname, cname, ival); ++ } else { ++ ret = xavp_set_child_ival(rname, cname, ival); ++ } ++ return (ret<0)?ret:1; ++} + +- ret = xavp_set_child_ival(rname, cname, ival); ++static int ki_xavp_child_seti(sip_msg_t *msg, str *rname, str *cname, ++ int ival) ++{ ++ return ki_xav_child_seti(msg, rname, cname, ival, 0); ++} + +- return (ret<0)?ret:1; ++static int ki_xavi_child_seti(sip_msg_t *msg, str *rname, str *cname, ++ int ival) ++{ ++ return ki_xav_child_seti(msg, rname, cname, ival, 1); + } + + /** + * + */ +-static int w_xavp_child_seti(sip_msg_t *msg, char *prname, char *pcname, +- char *pval) ++static int w_xav_child_seti(sip_msg_t *msg, char *prname, char *pcname, ++ char *pval, int _case) + { + str rname = STR_NULL; + str cname = STR_NULL; +@@ -972,27 +1043,53 @@ static int w_xavp_child_seti(sip_msg_t *msg, char *prname, char *pcname, + return -1; + } + +- return ki_xavp_child_seti(msg, &rname, &cname, ival); ++ return ki_xav_child_seti(msg, &rname, &cname, ival, _case); ++} ++ ++static int w_xavp_child_seti(sip_msg_t *msg, char *prname, char *pcname, ++ char *pval) ++{ ++ return w_xav_child_seti(msg, prname, pcname, pval, 0); ++} ++ ++static int w_xavi_child_seti(sip_msg_t *msg, char *prname, char *pcname, ++ char *pval) ++{ ++ return w_xav_child_seti(msg, prname, pcname, pval, 1); + } + + /** + * + */ +-static int ki_xavp_child_sets(sip_msg_t *msg, str *rname, str *cname, +- str *sval) ++static int ki_xav_child_sets(sip_msg_t *msg, str *rname, str *cname, ++ str *sval, int _case) + { + int ret; ++ if(_case) { ++ ret = xavi_set_child_sval(rname, cname, sval); ++ } else { ++ ret = xavp_set_child_sval(rname, cname, sval); ++ } ++ return (ret<0)?ret:1; ++} + +- ret = xavp_set_child_sval(rname, cname, sval); ++static int ki_xavp_child_sets(sip_msg_t *msg, str *rname, str *cname, ++ str *sval) ++{ ++ return ki_xav_child_sets(msg, rname, cname, sval, 0); ++} + +- return (ret<0)?ret:1; ++static int ki_xavi_child_sets(sip_msg_t *msg, str *rname, str *cname, ++ str *sval) ++{ ++ return ki_xav_child_sets(msg, rname, cname, sval, 1); + } + + /** + * + */ +-static int w_xavp_child_sets(sip_msg_t *msg, char *prname, char *pcname, +- char *pval) ++static int w_xav_child_sets(sip_msg_t *msg, char *prname, char *pcname, ++ char *pval, int _case) + { + str rname; + str cname; +@@ -1011,7 +1108,17 @@ static int w_xavp_child_sets(sip_msg_t *msg, char *prname, char *pcname, + return -1; + } + +- return ki_xavp_child_sets(msg, &rname, &cname, &sval); ++ return ki_xav_child_sets(msg, &rname, &cname, &sval, _case); ++} ++ ++static int w_xavp_child_sets(sip_msg_t *msg, char *prname, char *pcname, ++ char *pval) { ++ return w_xav_child_sets(msg, prname, pcname, pval, 0); ++} ++ ++static int w_xavi_child_sets(sip_msg_t *msg, char *prname, char *pcname, ++ char *pval) { ++ return w_xav_child_sets(msg, prname, pcname, pval, 1); + } + + /** +@@ -1042,19 +1149,32 @@ static int fixup_free_xavp_child_seti(void** param, int param_no) + /** + * + */ +-static int ki_xavp_rm(sip_msg_t *msg, str *rname) ++static int ki_xav_rm(sip_msg_t *msg, str *rname, int _case) + { + int ret; +- +- ret = xavp_rm_by_index(rname, 0, NULL); ++ if(_case) { ++ ret = xavi_rm_by_index(rname, 0, NULL); ++ } else { ++ ret = xavp_rm_by_index(rname, 0, NULL); ++ } + + return (ret==0)?1:ret; + } + ++static int ki_xavp_rm(sip_msg_t *msg, str *rname) ++{ ++ return ki_xav_rm(msg, rname, 0); ++} ++ ++static int ki_xavi_rm(sip_msg_t *msg, str *rname) ++{ ++ return ki_xav_rm(msg, rname, 1); ++} ++ + /** + * + */ +-static int w_xavp_rm(sip_msg_t *msg, char *prname, char *p2) ++static int w_xav_rm(sip_msg_t *msg, char *prname, char *p2, int _case) + { + str rname; + +@@ -1063,25 +1183,45 @@ static int w_xavp_rm(sip_msg_t *msg, char *prname, char *p2) + return -1; + } + +- return ki_xavp_rm(msg, &rname); ++ return ki_xav_rm(msg, &rname, _case); ++} ++ ++static int w_xavp_rm(sip_msg_t *msg, char *prname, char *p2) { ++ return w_xav_rm(msg, prname, p2, 0); ++} ++ ++static int w_xavi_rm(sip_msg_t *msg, char *prname, char *p2) { ++ return w_xav_rm(msg, prname, p2, 1); + } + + /** + * + */ +-static int ki_xavp_child_rm(sip_msg_t *msg, str *rname, str *cname) ++static int ki_xav_child_rm(sip_msg_t *msg, str *rname, str *cname, int _case) + { + int ret; ++ if(_case) { ++ ret = xavi_rm_child_by_index(rname, cname, 0); ++ } else { ++ ret = xavp_rm_child_by_index(rname, cname, 0); ++ } ++ return (ret==0)?1:ret; ++} + +- ret = xavp_rm_child_by_index(rname, cname, 0); ++static int ki_xavp_child_rm(sip_msg_t *msg, str *rname, str *cname) ++{ ++ return ki_xav_child_rm(msg, rname, cname, 0); ++} + +- return (ret==0)?1:ret; ++static int ki_xavi_child_rm(sip_msg_t *msg, str *rname, str *cname) ++{ ++ return ki_xav_child_rm(msg, rname, cname, 1); + } + + /** + * + */ +-static int w_xavp_child_rm(sip_msg_t *msg, char *prname, char *pcname) ++static int w_xav_child_rm(sip_msg_t *msg, char *prname, char *pcname, int _case) + { + str rname; + str cname; +@@ -1095,17 +1235,28 @@ static int w_xavp_child_rm(sip_msg_t *msg, char *prname, char *pcname) + return -1; + } + +- return ki_xavp_child_rm(msg, &rname, &cname); ++ return ki_xav_child_rm(msg, &rname, &cname, _case); ++} ++ ++static int w_xavp_child_rm(sip_msg_t *msg, char *prname, char *pcname) { ++ return w_xav_child_rm(msg, prname, pcname, 0); ++} ++ ++static int w_xavi_child_rm(sip_msg_t *msg, char *prname, char *pcname) { ++ return w_xav_child_rm(msg, prname, pcname, 1); + } + + /** + * + */ +-static int ki_xavp_is_null(sip_msg_t *msg, str *rname) ++static int ki_xav_is_null(sip_msg_t *msg, str *rname, int _case) + { + sr_xavp_t *xavp=NULL; +- +- xavp = xavp_get_by_index(rname, 0, NULL); ++ if(_case) { ++ xavp = xavi_get_by_index(rname, 0, NULL); ++ } else { ++ xavp = xavp_get_by_index(rname, 0, NULL); ++ } + if(xavp==NULL) { + return 1; + } +@@ -1115,6 +1266,13 @@ static int ki_xavp_is_null(sip_msg_t *msg, str *rname) + return -1; + } + ++static int ki_xavp_is_null(sip_msg_t *msg, str *rname) { ++ return ki_xav_is_null(msg, rname, 0); ++} ++ ++static int ki_xavi_is_null(sip_msg_t *msg, str *rname) { ++ return ki_xav_is_null(msg, rname, 1); ++} + /** + * + */ +@@ -1186,13 +1344,17 @@ static sr_kemi_xval_t* ki_xavp_get_xval(sr_xavp_t *xavp, int rmode) + /** + * + */ +-static sr_kemi_xval_t* ki_xavp_get_mode(sip_msg_t *msg, str *rname, int rmode) ++static sr_kemi_xval_t* ki_xav_get_mode(sip_msg_t *msg, str *rname, int rmode, ++ int _case) + { + sr_xavp_t *xavp=NULL; + + memset(&_sr_kemi_pv_xval, 0, sizeof(sr_kemi_xval_t)); +- +- xavp = xavp_get_by_index(rname, 0, NULL); ++ if(_case) { ++ xavp = xavi_get_by_index(rname, 0, NULL); ++ } else { ++ xavp = xavp_get_by_index(rname, 0, NULL); ++ } + if(xavp==NULL) { + sr_kemi_xval_null(&_sr_kemi_pv_xval, rmode); + return &_sr_kemi_pv_xval; +@@ -1206,7 +1368,15 @@ static sr_kemi_xval_t* ki_xavp_get_mode(sip_msg_t *msg, str *rname, int rmode) + */ + static sr_kemi_xval_t* ki_xavp_get(sip_msg_t *msg, str *rname) + { +- return ki_xavp_get_mode(msg, rname, SR_KEMI_XVAL_NULL_NONE); ++ return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_NONE, 0); ++} ++ ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xavi_get(sip_msg_t *msg, str *rname) ++{ ++ return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_NONE, 1); + } + + /** +@@ -1214,7 +1384,15 @@ static sr_kemi_xval_t* ki_xavp_get(sip_msg_t *msg, str *rname) + */ + static sr_kemi_xval_t* ki_xavp_gete(sip_msg_t *msg, str *rname) + { +- return ki_xavp_get_mode(msg, rname, SR_KEMI_XVAL_NULL_EMPTY); ++ return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_EMPTY, 0); ++} ++ ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xavi_gete(sip_msg_t *msg, str *rname) ++{ ++ return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_EMPTY, 1); + } + + /** +@@ -1222,14 +1400,22 @@ static sr_kemi_xval_t* ki_xavp_gete(sip_msg_t *msg, str *rname) + */ + static sr_kemi_xval_t* ki_xavp_getw(sip_msg_t *msg, str *rname) + { +- return ki_xavp_get_mode(msg, rname, SR_KEMI_XVAL_NULL_PRINT); ++ return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_PRINT, 0); ++} ++ ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xavi_getw(sip_msg_t *msg, str *rname) ++{ ++ return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_PRINT, 1); + } + +-sr_kemi_dict_item_t* ki_xavp_dict(sr_xavp_t *xavp); ++sr_kemi_dict_item_t* ki_xav_dict(sr_xavp_t *xavp, int _case); + /** + * SR_KEMIP_ARRAY with values of xavp=>name + */ +-sr_kemi_dict_item_t* ki_xavp_dict_name(sr_xavp_t *xavp, str *name) ++sr_kemi_dict_item_t* ki_xav_dict_name(sr_xavp_t *xavp, str *name, int _case) + { + sr_kemi_dict_item_t *ini = NULL; + sr_kemi_dict_item_t *val; +@@ -1243,11 +1429,17 @@ sr_kemi_dict_item_t* ki_xavp_dict_name(sr_xavp_t *xavp, str *name) + } + memset(ini, 0, sizeof(sr_kemi_xval_t)); + ini->vtype = SR_KEMIP_ARRAY; +- while(avp!=NULL&&!STR_EQ(avp->name,*name)) +- { +- avp = avp->next; ++ if(_case) { ++ while(avp!=NULL&&!cmpi_str(&avp->name, name)) ++ { ++ avp = avp->next; ++ } ++ } else { ++ while(avp!=NULL&&!STR_EQ(avp->name,*name)) ++ { ++ avp = avp->next; ++ } + } +- + while(avp!=NULL){ + switch(avp->val.type) { + case SR_XTYPE_XAVP: +@@ -1282,7 +1474,7 @@ sr_kemi_dict_item_t* ki_xavp_dict_name(sr_xavp_t *xavp, str *name) + LM_WARN("XAVP type:%d value not supported\n", avp->val.type); + break; + case SR_XTYPE_XAVP: +- val = ki_xavp_dict(avp->val.v.xavp); ++ val = ki_xav_dict(avp->val.v.xavp, _case); + break; + default: + val->vtype = SR_KEMIP_NULL; +@@ -1296,7 +1488,11 @@ sr_kemi_dict_item_t* ki_xavp_dict_name(sr_xavp_t *xavp, str *name) + ini->v.dict = val; + } + last = val; +- avp = xavp_get_next(avp); ++ if(_case) { ++ avp = xavi_get_next(avp); ++ } else { ++ avp = xavp_get_next(avp); ++ } + } + return ini; + error: +@@ -1311,7 +1507,7 @@ error: + /** + * SR_KEMIP_DICT of xavp + */ +-sr_kemi_dict_item_t* ki_xavp_dict(sr_xavp_t *xavp) { ++sr_kemi_dict_item_t* ki_xav_dict(sr_xavp_t *xavp, int _case) { + sr_xavp_t *avp = NULL; + struct str_list *keys; + struct str_list *k; +@@ -1324,7 +1520,12 @@ sr_kemi_dict_item_t* ki_xavp_dict(sr_xavp_t *xavp) { + return NULL; + } + avp = xavp->val.v.xavp; +- if((keys = xavp_get_list_key_names(xavp)) != NULL) { ++ if(_case) { ++ keys = xavi_get_list_key_names(xavp); ++ } else { ++ keys = xavp_get_list_key_names(xavp); ++ } ++ if( keys != NULL) { + do { + val = (sr_kemi_dict_item_t*)pkg_malloc(sizeof(sr_kemi_dict_item_t)); + if(val==NULL) { +@@ -1335,7 +1536,7 @@ sr_kemi_dict_item_t* ki_xavp_dict(sr_xavp_t *xavp) { + val->vtype = SR_KEMIP_DICT; + val->name.s = keys->s.s; + val->name.len = keys->s.len; +- val->v.dict = ki_xavp_dict_name(avp, &keys->s); ++ val->v.dict = ki_xav_dict_name(avp, &keys->s, _case); + if(last) { + last->next = val; + } else { +@@ -1366,7 +1567,7 @@ error: + * + */ + static sr_kemi_xval_t* +-ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx) ++ki_xav_getd_helper(sip_msg_t *msg, str *rname, int *_indx, int _case) + { + sr_xavp_t *xavp=NULL; + int xavp_size = 0; +@@ -1383,7 +1584,11 @@ ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx) + /* we're going to retrive all */ + _sr_kemi_pv_xval.vtype = SR_KEMIP_ARRAY; + } +- xavp_size = xavp_count(rname, NULL); ++ if(_case) { ++ xavp_size = xavi_count(rname, NULL); ++ } else { ++ xavp_size = xavp_count(rname, NULL); ++ } + if(indx<0) + { + if((indx*-1)>xavp_size) +@@ -1394,13 +1599,17 @@ ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx) + indx = xavp_size + indx; + } + +- xavp = xavp_get_by_index(rname, indx, NULL); ++ if(_case) { ++ xavp = xavi_get_by_index(rname, indx, NULL); ++ } else { ++ xavp = xavp_get_by_index(rname, indx, NULL); ++ } + if(xavp==NULL) { + sr_kemi_xval_null(&_sr_kemi_pv_xval, SR_KEMI_XVAL_NULL_NONE); + return &_sr_kemi_pv_xval; + } + do { +- val = ki_xavp_dict(xavp); ++ val = ki_xav_dict(xavp, _case); + if(last) { + last->next = val; + } else { +@@ -1411,7 +1620,11 @@ ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx) + xavp = NULL; + } else { + indx = indx + 1; +- xavp = xavp_get_by_index(rname, indx, NULL); ++ if(_case) { ++ xavp = xavi_get_by_index(rname, indx, NULL); ++ } else { ++ xavp = xavp_get_by_index(rname, indx, NULL); ++ } + } + } while(xavp!=NULL); + return &_sr_kemi_pv_xval; +@@ -1423,7 +1636,15 @@ ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx) + static sr_kemi_xval_t* + ki_xavp_getd(sip_msg_t *msg, str *rname) + { +- return ki_xavp_getd_helper(msg, rname, NULL); ++ return ki_xav_getd_helper(msg, rname, NULL, 0); ++} ++ ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xavi_getd(sip_msg_t *msg, str *rname) ++{ ++ return ki_xav_getd_helper(msg, rname, NULL, 1); + } + + /** +@@ -1432,14 +1653,23 @@ ki_xavp_getd(sip_msg_t *msg, str *rname) + static sr_kemi_xval_t* + ki_xavp_getd_p1(sip_msg_t *msg, str *rname, int indx) + { +- return ki_xavp_getd_helper(msg, rname, &indx); ++ return ki_xav_getd_helper(msg, rname, &indx, 0); + } + + /** + * + */ + static sr_kemi_xval_t* +-ki_xavp_get_keys(sip_msg_t *msg, str *rname, int indx) { ++ki_xavi_getd_p1(sip_msg_t *msg, str *rname, int indx) ++{ ++ return ki_xav_getd_helper(msg, rname, &indx, 1); ++} ++ ++/** ++ * ++ */ ++static sr_kemi_xval_t* ++ki_xav_get_keys(sip_msg_t *msg, str *rname, int indx, int _case) { + sr_xavp_t *xavp=NULL; + struct str_list *keys, *k; + sr_kemi_dict_item_t *val; +@@ -1447,12 +1677,20 @@ ki_xavp_get_keys(sip_msg_t *msg, str *rname, int indx) { + + memset(&_sr_kemi_pv_xval, 0, sizeof(sr_kemi_xval_t)); + +- xavp = xavp_get_by_index(rname, indx, NULL); ++ if(_case) { ++ xavp = xavi_get_by_index(rname, indx, NULL); ++ } else { ++ xavp = xavp_get_by_index(rname, indx, NULL); ++ } + if(xavp==NULL) { + sr_kemi_xval_null(&_sr_kemi_pv_xval, SR_KEMI_XVAL_NULL_NONE); + return &_sr_kemi_pv_xval; + } +- keys = xavp_get_list_key_names(xavp); ++ if(_case) { ++ keys = xavi_get_list_key_names(xavp); ++ } else { ++ keys = xavp_get_list_key_names(xavp); ++ } + _sr_kemi_pv_xval.vtype = SR_KEMIP_ARRAY; + while(keys!=NULL){ + k = keys; +@@ -1494,18 +1732,41 @@ error: + /** + * + */ +-static int ki_xavp_child_is_null(sip_msg_t *msg, str *rname, str *cname) ++static sr_kemi_xval_t* ki_xavp_get_keys(sip_msg_t *msg, str *rname, int indx) + { +- sr_xavp_t *xavp=NULL; ++ return ki_xav_get_keys(msg, rname, indx, 0); ++} + +- xavp = xavp_get_by_index(rname, 0, NULL); ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xavi_get_keys(sip_msg_t *msg, str *rname, int indx) ++{ ++ return ki_xav_get_keys(msg, rname, indx, 1); ++} ++ ++/** ++ * ++ */ ++static int ki_xav_child_is_null(sip_msg_t *msg, str *rname, str *cname, int _case) ++{ ++ sr_xavp_t *xavp=NULL; ++ if(_case) { ++ xavp = xavi_get_by_index(rname, 0, NULL); ++ } else { ++ xavp = xavp_get_by_index(rname, 0, NULL); ++ } + if(xavp==NULL) { + return 1; + } + if(xavp->val.type != SR_XTYPE_XAVP) { + return 1; + } +- xavp = xavp_get_by_index(cname, 0, &xavp->val.v.xavp); ++ if(_case) { ++ xavp = xavi_get_by_index(cname, 0, &xavp->val.v.xavp); ++ } else { ++ xavp = xavp_get_by_index(cname, 0, &xavp->val.v.xavp); ++ } + if(xavp==NULL) { + return 1; + } +@@ -1518,14 +1779,34 @@ static int ki_xavp_child_is_null(sip_msg_t *msg, str *rname, str *cname) + /** + * + */ +-static sr_kemi_xval_t* ki_xavp_child_get_mode(sip_msg_t *msg, str *rname, +- str *cname, int rmode) ++static int ki_xavp_child_is_null(sip_msg_t *msg, str *rname, str *cname) ++{ ++ return ki_xav_child_is_null(msg, rname, cname, 0); ++} ++ ++/** ++ * ++ */ ++static int ki_xavi_child_is_null(sip_msg_t *msg, str *rname, str *cname) ++{ ++ return ki_xav_child_is_null(msg, rname, cname, 1); ++} ++ ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xav_child_get_mode(sip_msg_t *msg, str *rname, ++ str *cname, int rmode, int _case) + { + sr_xavp_t *xavp=NULL; + + memset(&_sr_kemi_pv_xval, 0, sizeof(sr_kemi_xval_t)); + +- xavp = xavp_get_by_index(rname, 0, NULL); ++ if(_case) { ++ xavp = xavi_get_by_index(rname, 0, NULL); ++ } else { ++ xavp = xavp_get_by_index(rname, 0, NULL); ++ } + if(xavp==NULL) { + sr_kemi_xval_null(&_sr_kemi_pv_xval, rmode); + return &_sr_kemi_pv_xval; +@@ -1536,7 +1817,11 @@ static sr_kemi_xval_t* ki_xavp_child_get_mode(sip_msg_t *msg, str *rname, + return &_sr_kemi_pv_xval; + } + +- xavp = xavp_get_by_index(cname, 0, &xavp->val.v.xavp); ++ if(_case) { ++ xavp = xavi_get_by_index(cname, 0, &xavp->val.v.xavp); ++ } else { ++ xavp = xavp_get_by_index(cname, 0, &xavp->val.v.xavp); ++ } + if(xavp==NULL) { + sr_kemi_xval_null(&_sr_kemi_pv_xval, rmode); + return &_sr_kemi_pv_xval; +@@ -1550,25 +1835,47 @@ static sr_kemi_xval_t* ki_xavp_child_get_mode(sip_msg_t *msg, str *rname, + */ + static sr_kemi_xval_t* ki_xavp_child_get(sip_msg_t *msg, str *rname, str *cname) + { +- return ki_xavp_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_NONE); ++ return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_NONE, 0); + } + ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xavi_child_get(sip_msg_t *msg, str *rname, str *cname) ++{ ++ return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_NONE, 1); ++} + + /** + * + */ + static sr_kemi_xval_t* ki_xavp_child_gete(sip_msg_t *msg, str *rname, str *cname) + { +- return ki_xavp_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_EMPTY); ++ return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_EMPTY, 0); + } + ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xavi_child_gete(sip_msg_t *msg, str *rname, str *cname) ++{ ++ return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_EMPTY, 1); ++} + + /** + * + */ + static sr_kemi_xval_t* ki_xavp_child_getw(sip_msg_t *msg, str *rname, str *cname) + { +- return ki_xavp_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_PRINT); ++ return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_PRINT, 0); ++} ++ ++/** ++ * ++ */ ++static sr_kemi_xval_t* ki_xavi_child_getw(sip_msg_t *msg, str *rname, str *cname) ++{ ++ return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_PRINT, 1); + } + + /** +@@ -1927,6 +2234,11 @@ static sr_kemi_t sr_kemi_pvx_exports[] = { + { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE, + SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } + }, ++ { str_init("pvx"), str_init("pv_xavi_print"), ++ SR_KEMIP_INT, ki_xavi_print, ++ { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, + { str_init("pvx"), str_init("xavp_params_explode"), + SR_KEMIP_INT, ki_xavp_params_explode, + { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, +@@ -2022,6 +2334,91 @@ static sr_kemi_t sr_kemi_pvx_exports[] = { + { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, + SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } + }, ++ { str_init("pvx"), str_init("xavi_seti"), ++ SR_KEMIP_INT, ki_xavi_seti, ++ { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_sets"), ++ SR_KEMIP_INT, ki_xavi_sets, ++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_get"), ++ SR_KEMIP_XVAL, ki_xavi_get, ++ { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_gete"), ++ SR_KEMIP_XVAL, ki_xavi_gete, ++ { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_getw"), ++ SR_KEMIP_XVAL, ki_xavi_getw, ++ { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_getd"), ++ SR_KEMIP_XVAL, ki_xavi_getd, ++ { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_getd_p1"), ++ SR_KEMIP_XVAL, ki_xavi_getd_p1, ++ { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_get_keys"), ++ SR_KEMIP_XVAL, ki_xavi_get_keys, ++ { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_rm"), ++ SR_KEMIP_INT, ki_xavi_rm, ++ { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_is_null"), ++ SR_KEMIP_INT, ki_xavi_is_null, ++ { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_child_seti"), ++ SR_KEMIP_INT, ki_xavi_child_seti, ++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_child_sets"), ++ SR_KEMIP_INT, ki_xavi_child_sets, ++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_child_rm"), ++ SR_KEMIP_INT, ki_xavi_child_rm, ++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_child_is_null"), ++ SR_KEMIP_INT, ki_xavi_child_is_null, ++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_child_get"), ++ SR_KEMIP_XVAL, ki_xavi_child_get, ++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_child_gete"), ++ SR_KEMIP_XVAL, ki_xavi_child_gete, ++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, ++ { str_init("pvx"), str_init("xavi_child_getw"), ++ SR_KEMIP_XVAL, ki_xavi_child_getw, ++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, ++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } ++ }, + { str_init("pvx"), str_init("evalx"), + SR_KEMIP_INT, ki_pv_evalx, + { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, +diff --git a/src/modules/pv/pv_xavp.c b/src/modules/pv/pv_xavp.c +index 9dca116..8db7a1c 100644 +--- a/src/modules/pv/pv_xavp.c ++++ b/src/modules/pv/pv_xavp.c +@@ -567,6 +567,12 @@ int pv_xavp_print(sip_msg_t* msg, char* s1, char *s2) + return 1; + } + ++int pv_xavi_print(sip_msg_t* msg, char* s1, char *s2) ++{ ++ xavi_print_list(NULL); ++ return 1; ++} ++ + /** + * + */ +@@ -759,3 +765,413 @@ int pv_xavp_to_var(str *xname) { + } while(xavp); + return 1; + } ++ ++void pv_xavi_name_destroy(pv_xavp_name_t *xname) ++{ ++ return; ++} ++ ++int pv_parse_xavi_name(pv_spec_p sp, str *in) ++{ ++ pv_xavp_name_t *xname=NULL; ++ char *p; ++ str s; ++ ++ if(in->s==NULL || in->len<=0) ++ return -1; ++ ++ xname = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t)); ++ if(xname==NULL) { ++ PKG_MEM_ERROR; ++ return -1; ++ } ++ ++ memset(xname, 0, sizeof(pv_xavp_name_t)); ++ ++ s = *in; ++ ++ p = pv_xavp_fill_ni(&s, xname); ++ if(p==NULL) ++ goto error; ++ ++ if(*p!='=') ++ goto done; ++ p++; ++ if(*p!='>') ++ goto error; ++ p++; ++ ++ s.len = in->len - (int)(p - in->s); ++ s.s = p; ++ LM_DBG("xavi sublist [%.*s] - key [%.*s]\n", xname->name.len, ++ xname->name.s, s.len, s.s); ++ ++ xname->next = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t)); ++ if(xname->next==NULL) { ++ LM_ERR("not enough pkg mem\n"); ++ goto error; ++ } ++ memset(xname->next, 0, sizeof(pv_xavp_name_t)); ++ ++ p = pv_xavp_fill_ni(&s, xname->next); ++ if(p==NULL) ++ goto error; ++ ++done: ++ sp->pvp.pvn.u.dname = (void*)xname; ++ sp->pvp.pvn.type = PV_NAME_PVAR; ++ return 0; ++ ++error: ++ if(xname!=NULL) { ++ pv_xavi_name_destroy(xname); ++ pkg_free(xname); ++ } ++ return -1; ++} ++ ++int pv_get_xavi(struct sip_msg *msg, pv_param_t *param, ++ pv_value_t *res) ++{ ++ pv_xavp_name_t *xname=NULL; ++ sr_xavp_t *avi=NULL; ++ int idxf = 0; ++ int idx = 0; ++ int count; ++ char *p, *p_ini; ++ int p_size; ++ ++ if(param==NULL) ++ { ++ LM_ERR("bad parameters\n"); ++ return -1; ++ } ++ xname = (pv_xavp_name_t*)param->pvn.u.dname; ++ ++ if(xname->index.type==PVT_EXTRA) ++ { ++ /* get the index */ ++ if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0) ++ { ++ LM_ERR("invalid index\n"); ++ return -1; ++ } ++ } ++ /* fix the index */ ++ if(idx<0) ++ { ++ count = xavi_count(&xname->name, NULL); ++ idx = count + idx; ++ } ++ avi = xavi_get_by_index(&xname->name, idx, NULL); ++ if(avi==NULL) ++ return pv_get_null(msg, param, res); ++ if(xname->next==NULL) ++ return pv_xavp_get_value(msg, param, res, avi); ++ if(avi->val.type != SR_XTYPE_XAVP) ++ return pv_get_null(msg, param, res); ++ ++ idx = 0; ++ idxf = 0; ++ if(xname->next->index.type==PVT_EXTRA) ++ { ++ /* get the index */ ++ if(pv_get_spec_index(msg, &xname->next->index.pvp, &idx, &idxf)!=0) ++ { ++ LM_ERR("invalid index\n"); ++ return -1; ++ } ++ } ++ /* fix the index */ ++ if(idx<0) ++ { ++ count = xavi_count(&xname->next->name, &avi->val.v.xavp); ++ idx = count + idx; ++ } ++ avi = xavi_get_by_index(&xname->next->name, idx, &avi->val.v.xavp); ++ if(avi==NULL) ++ return pv_get_null(msg, param, res); ++ /* get all values of second key */ ++ if(idxf==PV_IDX_ALL) ++ { ++ p_ini = pv_get_buffer(); ++ p = p_ini; ++ p_size = pv_get_buffer_size(); ++ do { ++ if(p!=p_ini) ++ { ++ if(p-p_ini+PV_FIELD_DELIM_LEN+1>p_size) ++ { ++ LM_ERR("local buffer length exceeded\n"); ++ return pv_get_null(msg, param, res); ++ } ++ memcpy(p, PV_FIELD_DELIM, PV_FIELD_DELIM_LEN); ++ p += PV_FIELD_DELIM_LEN; ++ } ++ if(pv_xavp_get_value(msg, param, res, avi)<0) ++ { ++ LM_ERR("can get value\n"); ++ return pv_get_null(msg, param, res); ++ } ++ if(p-p_ini+res->rs.len+1>p_size) ++ { ++ LM_ERR("local buffer length exceeded!\n"); ++ return pv_get_null(msg, param, res); ++ } ++ memcpy(p, res->rs.s, res->rs.len); ++ p += res->rs.len; ++ } while ((avi=xavi_get_next(avi))!=0); ++ res->rs.s = p_ini; ++ res->rs.len = p - p_ini; ++ return 0; ++ } ++ return pv_xavp_get_value(msg, param, res, avi); ++} ++ ++/** ++ * $xavi(name1[idx1]=>name2[idx2]) ++ */ ++int pv_set_xavi(struct sip_msg* msg, pv_param_t *param, ++ int op, pv_value_t *val) ++{ ++ pv_xavp_name_t *xname=NULL; ++ sr_xavp_t *avi=NULL; ++ sr_xavp_t *list=NULL; ++ sr_xval_t xval; ++ int idxf = 0; ++ int idx = 0; ++ int idxf1 = 0; ++ int idx1 = 0; ++ int count; ++ ++ if(param==NULL) ++ { ++ LM_ERR("bad parameters\n"); ++ return -1; ++ } ++ xname = (pv_xavp_name_t*)param->pvn.u.dname; ++ ++ if(xname->index.type==PVT_EXTRA) ++ { ++ /* get the index */ ++ if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0) ++ { ++ LM_ERR("invalid index\n"); ++ return -1; ++ } ++ } ++ ++ if((val==NULL) || (val->flags&PV_VAL_NULL)) ++ { ++ if(xname->next==NULL) ++ { ++ if(xname->index.type==PVT_EXTRA) { ++ if(idxf==PV_IDX_ALL) { ++ xavi_rm_by_name(&xname->name, 1, NULL); ++ return 0; ++ } ++ } ++ if(idx==0) { ++ xavi_rm_by_name(&xname->name, 0, NULL); ++ return 0; ++ } ++ /* fix the index */ ++ if(idx<0) ++ { ++ count = xavi_count(&xname->name, NULL); ++ idx = count + idx + 1; ++ } ++ xavi_rm_by_index(&xname->name, idx, NULL); ++ return 0; ++ } ++ ++ if(xname->next->index.type==PVT_EXTRA) ++ { ++ /* get the index */ ++ if(pv_get_spec_index(msg,&xname->next->index.pvp,&idx1,&idxf1)!=0) ++ { ++ LM_ERR("invalid index!\n"); ++ return -1; ++ } ++ } ++ ++ if(idxf==PV_IDX_ALL) { ++ /* iterate */ ++ avi = xavi_get(&xname->name, NULL); ++ while(avi) { ++ if(avi->val.type==SR_XTYPE_XAVP) { ++ if(xname->next->index.type==PVT_EXTRA) { ++ if(idxf1==PV_IDX_ALL) { ++ xavi_rm_by_name(&xname->next->name, 1, ++ &avi->val.v.xavp); ++ } else { ++ /* fix the index */ ++ idx = idx1; ++ if(idx<0) ++ { ++ count = xavi_count(&xname->next->name, ++ &avi->val.v.xavp); ++ idx = count + idx1 + 1; ++ } ++ xavi_rm_by_index(&xname->next->name, idx, ++ &avi->val.v.xavp); ++ } ++ } else { ++ xavi_rm_by_name(&xname->next->name, 0, ++ &avi->val.v.xavp); ++ } ++ } ++ avi = xavi_get_next(avi); ++ } ++ return 0; ++ } ++ ++ if(idx==0) { ++ avi = xavi_get(&xname->name, NULL); ++ } else { ++ /* fix the index */ ++ if(idx<0) ++ { ++ count = xavi_count(&xname->name, NULL); ++ idx = count + idx + 1; ++ } ++ avi = xavi_get_by_index(&xname->name, idx, NULL); ++ } ++ if(avi) { ++ if(avi->val.type==SR_XTYPE_XAVP) { ++ if(xname->next->index.type==PVT_EXTRA) { ++ if(idxf1==PV_IDX_ALL) { ++ xavi_rm_by_name(&xname->next->name, 1, ++ &avi->val.v.xavp); ++ } else { ++ /* fix the index */ ++ idx = idx1; ++ if(idx<0) ++ { ++ count = xavi_count(&xname->next->name, ++ &avi->val.v.xavp); ++ idx = count + idx1 + 1; ++ } ++ xavi_rm_by_index(&xname->next->name, idx, ++ &avi->val.v.xavp); ++ } ++ } else { ++ xavi_rm_by_name(&xname->next->name, 0, ++ &avi->val.v.xavp); ++ } ++ } ++ } ++ return 0; ++ } /* NULL assignment */ ++ ++ /* build xavi value */ ++ memset(&xval, 0, sizeof(sr_xval_t)); ++ ++ if(val->flags&PV_TYPE_INT) ++ { ++ xval.type = SR_XTYPE_INT; ++ xval.v.i = val->ri; ++ } else { ++ xval.type = SR_XTYPE_STR; ++ xval.v.s = val->rs; ++ } ++ ++ /* where to add */ ++ if(xname->next==NULL) ++ { ++ /* xavi with single value */ ++ if(xname->index.type==PVT_EXTRA) { ++ if(idxf==PV_IDX_ALL) { ++ /* ignore: should iterate and set same value to all xavis ++ * with same name?!?! */ ++ return -1; ++ } ++ /* fix the index */ ++ if(idx<0) ++ { ++ count = xavi_count(&xname->name, NULL); ++ idx = count + idx + 1; ++ } ++ /* set the value */ ++ if(xavi_set_value(&xname->name, idx, &xval, NULL)==NULL) ++ return -1; ++ return 0; ++ } ++ /* add new value */ ++ if(xavi_add_value(&xname->name, &xval, NULL)==NULL) ++ return -1; ++ return 0; ++ } ++ ++ /* xavi with xavp list value */ ++ if(xname->next->index.type==PVT_EXTRA) ++ { ++ /* get the index */ ++ if(pv_get_spec_index(msg,&xname->next->index.pvp,&idx1,&idxf1)!=0) ++ { ++ LM_ERR("invalid index!\n"); ++ return -1; ++ } ++ } ++ ++ if(xname->index.type==PVT_EXTRA) ++ { ++ /* set the value */ ++ if(idxf==PV_IDX_ALL) { ++ /* ignore: should iterate and set same value to all xavis ++ * with same name?!?! */ ++ return 0; ++ } ++ ++ if(idx==0) { ++ avi = xavi_get(&xname->name, NULL); ++ } else { ++ /* fix the index */ ++ if(idx<0) ++ { ++ count = xavi_count(&xname->name, NULL); ++ idx = count + idx + 1; ++ } ++ avi = xavi_get_by_index(&xname->name, idx, NULL); ++ } ++ if(avi==NULL) ++ return 0; ++ ++ if(avi->val.type!=SR_XTYPE_XAVP) ++ return -1; ++ ++ if(xname->next->index.type==PVT_EXTRA) { ++ if(idxf1==PV_IDX_ALL) { ++ /* ignore: should iterate and set same value to all xavis ++ * with same name?!?! */ ++ return 0; ++ } ++ /* fix the index */ ++ idx = idx1; ++ if(idx<0) ++ { ++ count = xavi_count(&xname->next->name, ++ &avi->val.v.xavp); ++ idx = count + idx1 + 1; ++ } ++ /* set value */ ++ xavi_set_value(&xname->next->name, idx, &xval, &avi->val.v.xavp); ++ return 0; ++ } ++ /* add new value in sublist */ ++ if(xavi_add_value(&xname->next->name, &xval, &avi->val.v.xavp)==NULL) ++ return -1; ++ return 0; ++ } ++ /* add new xavi with xavp list */ ++ if(xavi_add_value(&xname->next->name, &xval, &list)==NULL) ++ return -1; ++ ++ /* build xavi value */ ++ memset(&xval, 0, sizeof(sr_xval_t)); ++ xval.type = SR_XTYPE_XAVP; ++ xval.v.xavp = list; ++ xavi_add_value(&xname->name, &xval, NULL); ++ ++ return 0; ++} +diff --git a/src/modules/pv/pv_xavp.h b/src/modules/pv/pv_xavp.h +index 35c4109..b9e7de6 100644 +--- a/src/modules/pv/pv_xavp.h ++++ b/src/modules/pv/pv_xavp.h +@@ -26,7 +26,14 @@ int pv_set_xavp(struct sip_msg* msg, pv_param_t *param, + int op, pv_value_t *val); + int pv_parse_xavp_name(pv_spec_p sp, str *in); + ++int pv_get_xavi(struct sip_msg *msg, pv_param_t *param, ++ pv_value_t *res); ++int pv_set_xavi(struct sip_msg* msg, pv_param_t *param, ++ int op, pv_value_t *val); ++int pv_parse_xavi_name(pv_spec_p sp, str *in); ++ + int pv_xavp_print(struct sip_msg* msg, char* s1, char *s2); ++int pv_xavi_print(struct sip_msg* msg, char* s1, char *s2); + + int xavp_params_explode(str *params, str *xname); + diff --git a/debian/patches/upstream/tm-process-xavi-list-in-transaction-contexts.patch b/debian/patches/upstream/tm-process-xavi-list-in-transaction-contexts.patch new file mode 100644 index 000000000..ab792f24a --- /dev/null +++ b/debian/patches/upstream/tm-process-xavi-list-in-transaction-contexts.patch @@ -0,0 +1,205 @@ +From: Victor Seva +Date: Wed, 27 May 2020 09:05:09 +0200 +Subject: tm: process xavi list in transaction contexts + +--- + src/modules/tm/h_table.c | 11 +++++++++++ + src/modules/tm/h_table.h | 3 +++ + src/modules/tm/t_hooks.c | 6 ++++++ + src/modules/tm/t_reply.c | 7 +++++++ + 4 files changed, 27 insertions(+) + +diff --git a/src/modules/tm/h_table.c b/src/modules/tm/h_table.c +index cf5201c..2d73b9a 100644 +--- a/src/modules/tm/h_table.c ++++ b/src/modules/tm/h_table.c +@@ -257,6 +257,8 @@ void free_cell_helper( + destroy_avp_list_unsafe(&dead_cell->uri_avps_to); + if(dead_cell->xavps_list) + xavp_destroy_list_unsafe(&dead_cell->xavps_list); ++ if(dead_cell->xavis_list) ++ xavi_destroy_list_unsafe(&dead_cell->xavis_list); + + memset(dead_cell, 0, sizeof(tm_cell_t)); + /* the cell's body */ +@@ -366,6 +368,10 @@ struct cell *build_cell(struct sip_msg *p_msg) + new_cell->xavps_list = *xold; + *xold = 0; + ++ xold = xavi_set_list(&new_cell->xavis_list); ++ new_cell->xavis_list = *xold; ++ *xold = 0; ++ + /* We can just store pointer to domain avps in the transaction context, + * because they are read-only */ + new_cell->domain_avps_from = +@@ -423,10 +429,12 @@ error: + destroy_avp_list(&new_cell->uri_avps_from); + destroy_avp_list(&new_cell->uri_avps_to); + xavp_destroy_list(&new_cell->xavps_list); ++ xavi_destroy_list(&new_cell->xavis_list); + shm_free(new_cell); + /* unlink transaction AVP list and link back the global AVP list (bogdan)*/ + reset_avps(); + xavp_reset_list(); ++ xavi_reset_list(); + return NULL; + } + +@@ -531,6 +539,7 @@ void tm_xdata_swap(tm_cell_t *t, tm_xlinks_t *xd, int mode) + set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, x->domain_avps_from); + set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, x->domain_avps_to); + xavp_set_list(x->xavps_list); ++ xavi_set_list(x->xavis_list); + } + } + +@@ -548,6 +557,7 @@ void tm_xdata_replace(tm_xdata_t *newxd, tm_xlinks_t *bakxd) + AVP_TRACK_FROM | AVP_CLASS_DOMAIN, bakxd->domain_avps_from); + set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, bakxd->domain_avps_to); + xavp_set_list(bakxd->xavps_list); ++ xavi_set_list(bakxd->xavis_list); + return; + } + +@@ -565,6 +575,7 @@ void tm_xdata_replace(tm_xdata_t *newxd, tm_xlinks_t *bakxd) + bakxd->domain_avps_to = set_avp_list( + AVP_TRACK_TO | AVP_CLASS_DOMAIN, &newxd->domain_avps_to); + bakxd->xavps_list = xavp_set_list(&newxd->xavps_list); ++ bakxd->xavis_list = xavi_set_list(&newxd->xavis_list); + return; + } + } +diff --git a/src/modules/tm/h_table.h b/src/modules/tm/h_table.h +index ef666e5..5c8b916 100644 +--- a/src/modules/tm/h_table.h ++++ b/src/modules/tm/h_table.h +@@ -309,6 +309,7 @@ typedef struct tm_xdata + struct usr_avp *domain_avps_from; + struct usr_avp *domain_avps_to; + sr_xavp_t *xavps_list; ++ sr_xavp_t *xavis_list; + } tm_xdata_t; + + +@@ -325,6 +326,7 @@ typedef struct tm_xlinks + struct usr_avp **domain_avps_from; + struct usr_avp **domain_avps_to; + sr_xavp_t **xavps_list; ++ sr_xavp_t **xavis_list; + } tm_xlinks_t; + + +@@ -398,6 +400,7 @@ typedef struct cell + struct usr_avp *domain_avps_from; + struct usr_avp *domain_avps_to; + sr_xavp_t *xavps_list; ++ sr_xavp_t *xavis_list; + + /* protection against concurrent reply processing */ + ser_lock_t reply_mutex; +diff --git a/src/modules/tm/t_hooks.c b/src/modules/tm/t_hooks.c +index e0d4423..2decc79 100644 +--- a/src/modules/tm/t_hooks.c ++++ b/src/modules/tm/t_hooks.c +@@ -229,6 +229,7 @@ void run_trans_callbacks_internal(struct tmcb_head_list* cb_lst, int type, + struct tm_callback *cbp; + avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to; + sr_xavp_t **backup_xavps; ++ sr_xavp_t **backup_xavis; + + backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, + &trans->uri_avps_from ); +@@ -243,6 +244,7 @@ void run_trans_callbacks_internal(struct tmcb_head_list* cb_lst, int type, + backup_dom_to = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, + &trans->domain_avps_to); + backup_xavps = xavp_set_list(&trans->xavps_list); ++ backup_xavis = xavi_set_list(&trans->xavis_list); + + cbp=(struct tm_callback*)cb_lst->first; + while(cbp){ +@@ -262,6 +264,7 @@ void run_trans_callbacks_internal(struct tmcb_head_list* cb_lst, int type, + set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, backup_uri_to ); + set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, backup_uri_from ); + xavp_set_list(backup_xavps); ++ xavi_set_list(backup_xavis); + } + + +@@ -317,6 +320,7 @@ static void run_reqin_callbacks_internal(struct tmcb_head_list* hl, + avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, + *backup_uri_from, *backup_uri_to; + sr_xavp_t **backup_xavps; ++ sr_xavp_t **backup_xavis; + + if (hl==0 || hl->first==0) return; + backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, +@@ -332,6 +336,7 @@ static void run_reqin_callbacks_internal(struct tmcb_head_list* hl, + backup_dom_to = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, + &trans->domain_avps_to); + backup_xavps = xavp_set_list(&trans->xavps_list); ++ backup_xavis = xavi_set_list(&trans->xavis_list); + for (cbp=(struct tm_callback*)hl->first; cbp; cbp=cbp->next) { + LM_DBG("trans=%p, callback type %d, id %d entered\n", + trans, cbp->types, cbp->id ); +@@ -345,6 +350,7 @@ static void run_reqin_callbacks_internal(struct tmcb_head_list* hl, + set_avp_list(AVP_CLASS_USER | AVP_TRACK_TO, backup_to ); + set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, backup_from ); + xavp_set_list(backup_xavps); ++ xavi_set_list(backup_xavis); + } + + +diff --git a/src/modules/tm/t_reply.c b/src/modules/tm/t_reply.c +index 77747d3..f26d42b 100644 +--- a/src/modules/tm/t_reply.c ++++ b/src/modules/tm/t_reply.c +@@ -691,6 +691,7 @@ typedef struct tm_faked_env { + avp_list_t* backup_uri_from; + avp_list_t* backup_uri_to; + sr_xavp_t **backup_xavps; ++ sr_xavp_t **backup_xavis; + struct socket_info* backup_si; + struct lump *backup_add_rm; + struct lump *backup_body_lumps; +@@ -780,6 +781,8 @@ int faked_env(struct cell *t, struct sip_msg *msg, int is_async_env) + &t->domain_avps_to); + _tm_faked_env[_tm_faked_env_idx].backup_xavps + = xavp_set_list(&t->xavps_list); ++ _tm_faked_env[_tm_faked_env_idx].backup_xavis ++ = xavi_set_list(&t->xavis_list); + /* set default send address to the saved value */ + _tm_faked_env[_tm_faked_env_idx].backup_si = bind_address; + bind_address = t->uac[0].request.dst.send_sock; +@@ -815,6 +818,7 @@ int faked_env(struct cell *t, struct sip_msg *msg, int is_async_env) + set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, + _tm_faked_env[_tm_faked_env_idx].backup_uri_to); + xavp_set_list(_tm_faked_env[_tm_faked_env_idx].backup_xavps); ++ xavi_set_list(_tm_faked_env[_tm_faked_env_idx].backup_xavis); + bind_address = _tm_faked_env[_tm_faked_env_idx].backup_si; + /* restore lump lists */ + t->uas.request->add_rm +@@ -2203,6 +2207,7 @@ int reply_received( struct sip_msg *p_msg ) + avp_list_t* backup_domain_from, *backup_domain_to; + avp_list_t* backup_uri_from, *backup_uri_to; + sr_xavp_t **backup_xavps; ++ sr_xavp_t **backup_xavis; + int replies_locked = 0; + #ifdef USE_DNS_FAILOVER + int branch_ret; +@@ -2392,6 +2397,7 @@ int reply_received( struct sip_msg *p_msg ) + backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, + &t->domain_avps_to ); + backup_xavps = xavp_set_list(&t->xavps_list); ++ backup_xavis = xavi_set_list(&t->xavis_list); + setbflagsval(0, uac->branch_flags); + if(msg_status>last_uac_status) { + /* current response (msg) status is higher that the last received +@@ -2436,6 +2442,7 @@ int reply_received( struct sip_msg *p_msg ) + set_avp_list( AVP_TRACK_FROM | AVP_CLASS_DOMAIN, backup_domain_from ); + set_avp_list( AVP_TRACK_TO | AVP_CLASS_DOMAIN, backup_domain_to ); + xavp_set_list(backup_xavps); ++ xavi_set_list(backup_xavis); + /* handle a possible DROP in the script, but only if this + * is not a final reply (final replies already stop the timers + * and droping them might leave a transaction living forever) */