From 696dbabcfcee45d4b6739b5fe9250216b0b118c9 Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Fri, 26 Jun 2015 14:21:59 +0200 Subject: [PATCH] MT#6565 mod_cfgt Change-Id: I1ceb9ee84d0f8f851118f873815303809af86555 --- debian/patches/series | 7 +- ...-move-json-related-from-debugger_api.patch | 902 +++++++++ ...s-cfgt-trace-config-and-save-to-file.patch | 1718 +++++++++++++++++ debian/patches/sipwise/debug/mod_cfgt.patch | 11 + ...ous-routename-in-order-to-get-the-co.patch | 40 + 5 files changed, 2677 insertions(+), 1 deletion(-) create mode 100644 debian/patches/sipwise/debug/0000-modules-debugger-move-json-related-from-debugger_api.patch create mode 100644 debian/patches/sipwise/debug/0001-modules-cfgt-trace-config-and-save-to-file.patch create mode 100644 debian/patches/sipwise/debug/mod_cfgt.patch create mode 100644 debian/patches/upstream/0001-core-clean-previous-routename-in-order-to-get-the-co.patch diff --git a/debian/patches/series b/debian/patches/series index 66446cc13..a009bf2ae 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,5 +1,10 @@ # kamailio-config-test -upstream/debug/0001-modules-debugger-trace-msg-out.patch +# fix needed from upstream +upstream/0001-core-clean-previous-routename-in-order-to-get-the-co.patch +# +sipwise/debug/0000-modules-debugger-move-json-related-from-debugger_api.patch +sipwise/debug/0001-modules-cfgt-trace-config-and-save-to-file.patch +sipwise/debug/mod_cfgt.patch # no_lib64_on_64_bits.patch no_INSTALL_file.patch diff --git a/debian/patches/sipwise/debug/0000-modules-debugger-move-json-related-from-debugger_api.patch b/debian/patches/sipwise/debug/0000-modules-debugger-move-json-related-from-debugger_api.patch new file mode 100644 index 000000000..44b43ab8e --- /dev/null +++ b/debian/patches/sipwise/debug/0000-modules-debugger-move-json-related-from-debugger_api.patch @@ -0,0 +1,902 @@ +From dead28aa11df089e1110a531297d67a4dd583972 Mon Sep 17 00:00:00 2001 +From: Victor Seva +Date: Sat, 20 Jun 2015 13:37:04 +0200 +Subject: [PATCH] modules/debugger: move json related from debugger_api.c to + debugger_json.c|h + +--- + modules/debugger/debugger_api.c | 389 +---------------------------------- + modules/debugger/debugger_api.h | 2 +- + modules/debugger/debugger_json.c | 423 +++++++++++++++++++++++++++++++++++++++ + modules/debugger/debugger_json.h | 32 +++ + modules/debugger/debugger_mod.c | 1 + + 5 files changed, 462 insertions(+), 385 deletions(-) + create mode 100644 modules/debugger/debugger_json.c + create mode 100644 modules/debugger/debugger_json.h + +--- a/modules/debugger/debugger_api.c ++++ b/modules/debugger/debugger_api.c +@@ -27,20 +27,14 @@ + #include + + #include "../../dprint.h" +-#include "../../ut.h" +-#include "../../pt.h" + #include "../../events.h" +-#include "../../pvar.h" +-#include "../../rpc.h" +-#include "../../rpc_lookup.h" +-#include "../../route_struct.h" +-#include "../../mem/shm_mem.h" + #include "../../locking.h" + #include "../../lvalue.h" +-#include "../../hashes.h" +-#include "../../lib/srutils/srjson.h" +-#include "../../xavp.h" +-#include "../pv/pv_xavp.h" ++#include "../../pt.h" ++#include "../../route_struct.h" ++#include "../../rpc.h" ++#include "../../rpc_lookup.h" ++#include "../../ut.h" + + #include "debugger_act.h" + #include "debugger_api.h" +@@ -1432,376 +1426,3 @@ + } + return 0; + } +- +-int _dbg_get_array_avp_vals(struct sip_msg *msg, +- pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobj, +- str *item_name) +-{ +- struct usr_avp *avp; +- unsigned short name_type; +- int_str avp_name; +- int_str avp_value; +- struct search_state state; +- srjson_t *jobjt; +- memset(&state, 0, sizeof(struct search_state)); +- +- if(pv_get_avp_name(msg, param, &avp_name, &name_type)!=0) +- { +- LM_ERR("invalid name\n"); +- return -1; +- } +- *jobj = srjson_CreateArray(jdoc); +- if(*jobj==NULL) +- { +- LM_ERR("cannot create json object\n"); +- return -1; +- } +- if ((avp=search_first_avp(name_type, avp_name, &avp_value, &state))==0) +- { +- goto ok; +- } +- do +- { +- if(avp->flags & AVP_VAL_STR) +- { +- jobjt = srjson_CreateStr(jdoc, avp_value.s.s, avp_value.s.len); +- if(jobjt==NULL) +- { +- LM_ERR("cannot create json object\n"); +- return -1; +- } +- } else { +- jobjt = srjson_CreateNumber(jdoc, avp_value.n); +- if(jobjt==NULL) +- { +- LM_ERR("cannot create json object\n"); +- return -1; +- } +- } +- srjson_AddItemToArray(jdoc, *jobj, jobjt); +- } while ((avp=search_next_avp(&state, &avp_value))!=0); +-ok: +- item_name->s = avp_name.s.s; +- item_name->len = avp_name.s.len; +- return 0; +-} +-#define DBG_XAVP_DUMP_SIZE 32 +-static str* _dbg_xavp_dump[DBG_XAVP_DUMP_SIZE]; +-int _dbg_xavp_dump_lookup(pv_param_t *param) +-{ +- unsigned int i = 0; +- pv_xavp_name_t *xname; +- +- if(param==NULL) +- return -1; +- +- xname = (pv_xavp_name_t*)param->pvn.u.dname; +- +- while(_dbg_xavp_dump[i]!=NULL&&ilen==xname->name.len) +- { +- if(strncmp(_dbg_xavp_dump[i]->s, xname->name.s, xname->name.len)==0) +- return 1; /* already dump before */ +- } +- i++; +- } +- if(i==DBG_XAVP_DUMP_SIZE) +- { +- LM_WARN("full _dbg_xavp_dump cache array\n"); +- return 0; /* end cache names */ +- } +- _dbg_xavp_dump[i] = &xname->name; +- return 0; +-} +- +-void _dbg_get_obj_xavp_val(sr_xavp_t *avp, srjson_doc_t *jdoc, srjson_t **jobj) +-{ +- static char _pv_xavp_buf[128]; +- int result = 0; +- +- switch(avp->val.type) { +- case SR_XTYPE_NULL: +- *jobj = srjson_CreateNull(jdoc); +- break; +- case SR_XTYPE_INT: +- *jobj = srjson_CreateNumber(jdoc, avp->val.v.i); +- break; +- case SR_XTYPE_STR: +- *jobj = srjson_CreateStr(jdoc, avp->val.v.s.s, avp->val.v.s.len); +- break; +- case SR_XTYPE_TIME: +- result = snprintf(_pv_xavp_buf, 128, "%lu", (long unsigned)avp->val.v.t); +- break; +- case SR_XTYPE_LONG: +- result = snprintf(_pv_xavp_buf, 128, "%ld", (long unsigned)avp->val.v.l); +- break; +- case SR_XTYPE_LLONG: +- result = snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll); +- break; +- case SR_XTYPE_XAVP: +- result = snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.xavp); +- break; +- case SR_XTYPE_DATA: +- result = snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.data); +- break; +- default: +- LM_WARN("unknown data type\n"); +- *jobj = srjson_CreateNull(jdoc); +- } +- if(result<0) +- { +- LM_ERR("cannot convert to str\n"); +- *jobj = srjson_CreateNull(jdoc); +- } +- else if(*jobj==NULL) +- { +- *jobj = srjson_CreateStr(jdoc, _pv_xavp_buf, 128); +- } +-} +- +-int _dbg_get_obj_avp_vals(str name, sr_xavp_t *xavp, srjson_doc_t *jdoc, srjson_t **jobj) +-{ +- sr_xavp_t *avp = NULL; +- srjson_t *jobjt = NULL; +- +- *jobj = srjson_CreateArray(jdoc); +- if(*jobj==NULL) +- { +- LM_ERR("cannot create json object\n"); +- return -1; +- } +- avp = xavp; +- while(avp!=NULL&&!STR_EQ(avp->name,name)) +- { +- avp = avp->next; +- } +- while(avp!=NULL) +- { +- _dbg_get_obj_xavp_val(avp, jdoc, &jobjt); +- srjson_AddItemToArray(jdoc, *jobj, jobjt); +- jobjt = NULL; +- avp = xavp_get_next(avp); +- } +- +- return 0; +-} +- +-int _dbg_get_obj_xavp_vals(struct sip_msg *msg, +- pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobjr, +- str *item_name) +-{ +- pv_xavp_name_t *xname = (pv_xavp_name_t*)param->pvn.u.dname; +- sr_xavp_t *xavp = NULL; +- sr_xavp_t *avp = NULL; +- srjson_t *jobj = NULL; +- srjson_t *jobjt = NULL; +- struct str_list *keys; +- struct str_list *k; +- +- *jobjr = srjson_CreateArray(jdoc); +- if(*jobjr==NULL) +- { +- LM_ERR("cannot create json object\n"); +- return -1; +- } +- +- item_name->s = xname->name.s; +- item_name->len = xname->name.len; +- xavp = xavp_get_by_index(&xname->name, 0, NULL); +- if(xavp==NULL) +- { +- return 0; /* empty */ +- } +- +- do +- { +- if(xavp->val.type==SR_XTYPE_XAVP) +- { +- avp = xavp->val.v.xavp; +- jobj = srjson_CreateObject(jdoc); +- if(jobj==NULL) +- { +- LM_ERR("cannot create json object\n"); +- return -1; +- } +- keys = xavp_get_list_key_names(xavp); +- if(keys!=NULL) +- { +- do +- { +- _dbg_get_obj_avp_vals(keys->s, avp, jdoc, &jobjt); +- srjson_AddStrItemToObject(jdoc, jobj, keys->s.s, +- keys->s.len, jobjt); +- k = keys; +- keys = keys->next; +- pkg_free(k); +- jobjt = NULL; +- }while(keys!=NULL); +- } +- } +- if(jobj!=NULL) +- { +- srjson_AddItemToArray(jdoc, *jobjr, jobj); +- jobj = NULL; +- } +- }while((xavp = xavp_get_next(xavp))!=0); +- +- return 0; +-} +- +-int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level) +-{ +- int i; +- pv_value_t value; +- pv_cache_t **_pv_cache = pv_cache_get_table(); +- pv_cache_t *el = NULL; +- srjson_doc_t jdoc; +- srjson_t *jobj = NULL; +- char *output = NULL; +- str item_name = STR_NULL; +- static char iname[128]; +- int result = -1; +- +- if(_pv_cache==NULL) +- { +- LM_ERR("cannot access pv_cache\n"); +- return -1; +- } +- +- memset(_dbg_xavp_dump, 0, sizeof(str*)*DBG_XAVP_DUMP_SIZE); +- srjson_InitDoc(&jdoc, NULL); +- if(jdoc.root==NULL) +- { +- jdoc.root = srjson_CreateObject(&jdoc); +- if(jdoc.root==NULL) +- { +- LM_ERR("cannot create json root\n"); +- goto error; +- } +- } +- for(i=0;ispec.type==PVT_AVP|| +- el->spec.type==PVT_SCRIPTVAR|| +- el->spec.type==PVT_XAVP|| +- el->spec.type==PVT_OTHER)|| +- !((el->spec.type==PVT_AVP&&mask&DBG_DP_AVP)|| +- (el->spec.type==PVT_XAVP&&mask&DBG_DP_XAVP)|| +- (el->spec.type==PVT_SCRIPTVAR&&mask&DBG_DP_SCRIPTVAR)|| +- (el->spec.type==PVT_OTHER&&mask&DBG_DP_OTHER))|| +- (el->spec.trans!=NULL)) +- { +- el = el->next; +- continue; +- } +- jobj = NULL; +- item_name.len = 0; +- item_name.s = 0; +- iname[0] = '\0'; +- if(el->spec.type==PVT_AVP) +- { +- if(el->spec.pvp.pvi.type==PV_IDX_ALL|| +- (el->spec.pvp.pvi.type==PV_IDX_INT&&el->spec.pvp.pvi.u.ival!=0)) +- { +- el = el->next; +- continue; +- } +- else +- { +- if(_dbg_get_array_avp_vals(msg, &el->spec.pvp, &jdoc, &jobj, &item_name)!=0) +- { +- LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); +- el = el->next; +- continue; +- } +- if(srjson_GetArraySize(&jdoc, jobj)==0 && !(mask&DBG_DP_NULL)) +- { +- el = el->next; +- continue; +- } +- snprintf(iname, 128, "$avp(%.*s)", item_name.len, item_name.s); +- } +- } +- else if(el->spec.type==PVT_XAVP) +- { +- if(_dbg_xavp_dump_lookup(&el->spec.pvp)!=0) +- { +- el = el->next; +- continue; +- } +- if(_dbg_get_obj_xavp_vals(msg, &el->spec.pvp, &jdoc, &jobj, &item_name)!=0) +- { +- LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); +- el = el->next; +- continue; +- } +- if(srjson_GetArraySize(&jdoc, jobj)==0 && !(mask&DBG_DP_NULL)) +- { +- el = el->next; +- continue; +- } +- snprintf(iname, 128, "$xavp(%.*s)", item_name.len, item_name.s); +- } +- else +- { +- if(pv_get_spec_value(msg, &el->spec, &value)!=0) +- { +- LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); +- el = el->next; +- continue; +- } +- if(value.flags&(PV_VAL_NULL|PV_VAL_EMPTY|PV_VAL_NONE)) +- { +- if(mask&DBG_DP_NULL) +- { +- jobj = srjson_CreateNull(&jdoc); +- } +- else +- { +- el = el->next; +- continue; +- } +- }else if(value.flags&(PV_VAL_INT)){ +- jobj = srjson_CreateNumber(&jdoc, value.ri); +- }else if(value.flags&(PV_VAL_STR)){ +- jobj = srjson_CreateStr(&jdoc, value.rs.s, value.rs.len); +- }else { +- LM_WARN("el->pvname[%.*s] value[%d] unhandled\n", el->pvname.len, el->pvname.s, +- value.flags); +- el = el->next; +- continue; +- } +- if(jobj==NULL) +- { +- LM_ERR("el->pvname[%.*s] empty json object\n", el->pvname.len, +- el->pvname.s); +- goto error; +- } +- snprintf(iname, 128, "%.*s", el->pvname.len, el->pvname.s); +- } +- if(jobj!=NULL) +- { +- srjson_AddItemToObject(&jdoc, jdoc.root, iname, jobj); +- } +- el = el->next; +- } +- } +- output = srjson_PrintUnformatted(&jdoc, jdoc.root); +- if(output==NULL) +- { +- LM_ERR("cannot print json doc\n"); +- goto error; +- } +- LOG(level, "%s\n", output); +- result = 0; +- +-error: +- if(output!=NULL) jdoc.free_fn(output); +- srjson_DestroyDoc(&jdoc); +- +- return result; +-} +--- a/modules/debugger/debugger_api.h ++++ b/modules/debugger/debugger_api.h +@@ -56,6 +56,6 @@ + #define DBG_DP_XAVP 8 + #define DBG_DP_OTHER 16 + #define DBG_DP_ALL 31 +-int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level); ++ + #endif + +--- /dev/null ++++ b/modules/debugger/debugger_json.c +@@ -0,0 +1,423 @@ ++/** ++ * ++ * Copyright (C) 2013-2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++#include ++ ++#include "../../pvar.h" ++#include "../../mem/shm_mem.h" ++#include "../../xavp.h" ++#include "../pv/pv_xavp.h" ++ ++#include "debugger_api.h" ++#include "debugger_json.h" ++ ++int _dbg_get_array_avp_vals(struct sip_msg *msg, ++ pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobj, ++ str *item_name) ++{ ++ struct usr_avp *avp; ++ unsigned short name_type; ++ int_str avp_name; ++ int_str avp_value; ++ struct search_state state; ++ srjson_t *jobjt; ++ memset(&state, 0, sizeof(struct search_state)); ++ ++ if(pv_get_avp_name(msg, param, &avp_name, &name_type)!=0) ++ { ++ LM_ERR("invalid name\n"); ++ return -1; ++ } ++ *jobj = srjson_CreateArray(jdoc); ++ if(*jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ if ((avp=search_first_avp(name_type, avp_name, &avp_value, &state))==0) ++ { ++ goto ok; ++ } ++ do ++ { ++ if(avp->flags & AVP_VAL_STR) ++ { ++ jobjt = srjson_CreateStr(jdoc, avp_value.s.s, avp_value.s.len); ++ if(jobjt==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ } else { ++ jobjt = srjson_CreateNumber(jdoc, avp_value.n); ++ if(jobjt==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ } ++ srjson_AddItemToArray(jdoc, *jobj, jobjt); ++ } while ((avp=search_next_avp(&state, &avp_value))!=0); ++ok: ++ item_name->s = avp_name.s.s; ++ item_name->len = avp_name.s.len; ++ return 0; ++} ++#define DBG_XAVP_DUMP_SIZE 32 ++static str* _dbg_xavp_dump[DBG_XAVP_DUMP_SIZE]; ++int _dbg_xavp_dump_lookup(pv_param_t *param) ++{ ++ unsigned int i = 0; ++ pv_xavp_name_t *xname; ++ ++ if(param==NULL) ++ return -1; ++ ++ xname = (pv_xavp_name_t*)param->pvn.u.dname; ++ ++ while(_dbg_xavp_dump[i]!=NULL&&ilen==xname->name.len) ++ { ++ if(strncmp(_dbg_xavp_dump[i]->s, xname->name.s, xname->name.len)==0) ++ return 1; /* already dump before */ ++ } ++ i++; ++ } ++ if(i==DBG_XAVP_DUMP_SIZE) ++ { ++ LM_WARN("full _dbg_xavp_dump cache array\n"); ++ return 0; /* end cache names */ ++ } ++ _dbg_xavp_dump[i] = &xname->name; ++ return 0; ++} ++ ++void _dbg_get_obj_xavp_val(sr_xavp_t *avp, srjson_doc_t *jdoc, srjson_t **jobj) ++{ ++ static char _pv_xavp_buf[128]; ++ int result = 0; ++ ++ switch(avp->val.type) { ++ case SR_XTYPE_NULL: ++ *jobj = srjson_CreateNull(jdoc); ++ break; ++ case SR_XTYPE_INT: ++ *jobj = srjson_CreateNumber(jdoc, avp->val.v.i); ++ break; ++ case SR_XTYPE_STR: ++ *jobj = srjson_CreateStr(jdoc, avp->val.v.s.s, avp->val.v.s.len); ++ break; ++ case SR_XTYPE_TIME: ++ result = snprintf(_pv_xavp_buf, 128, "%lu", (long unsigned)avp->val.v.t); ++ break; ++ case SR_XTYPE_LONG: ++ result = snprintf(_pv_xavp_buf, 128, "%ld", (long unsigned)avp->val.v.l); ++ break; ++ case SR_XTYPE_LLONG: ++ result = snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll); ++ break; ++ case SR_XTYPE_XAVP: ++ result = snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.xavp); ++ break; ++ case SR_XTYPE_DATA: ++ result = snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.data); ++ break; ++ default: ++ LM_WARN("unknown data type\n"); ++ *jobj = srjson_CreateNull(jdoc); ++ } ++ if(result<0) ++ { ++ LM_ERR("cannot convert to str\n"); ++ *jobj = srjson_CreateNull(jdoc); ++ } ++ else if(*jobj==NULL) ++ { ++ *jobj = srjson_CreateStr(jdoc, _pv_xavp_buf, 128); ++ } ++} ++ ++int _dbg_get_obj_avp_vals(str name, sr_xavp_t *xavp, srjson_doc_t *jdoc, srjson_t **jobj) ++{ ++ sr_xavp_t *avp = NULL; ++ srjson_t *jobjt = NULL; ++ ++ *jobj = srjson_CreateArray(jdoc); ++ if(*jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ avp = xavp; ++ while(avp!=NULL&&!STR_EQ(avp->name,name)) ++ { ++ avp = avp->next; ++ } ++ while(avp!=NULL) ++ { ++ _dbg_get_obj_xavp_val(avp, jdoc, &jobjt); ++ srjson_AddItemToArray(jdoc, *jobj, jobjt); ++ jobjt = NULL; ++ avp = xavp_get_next(avp); ++ } ++ ++ return 0; ++} ++ ++int _dbg_get_obj_xavp_vals(struct sip_msg *msg, ++ pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobjr, ++ str *item_name) ++{ ++ pv_xavp_name_t *xname = (pv_xavp_name_t*)param->pvn.u.dname; ++ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *avp = NULL; ++ srjson_t *jobj = NULL; ++ srjson_t *jobjt = NULL; ++ struct str_list *keys; ++ struct str_list *k; ++ ++ *jobjr = srjson_CreateArray(jdoc); ++ if(*jobjr==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ ++ item_name->s = xname->name.s; ++ item_name->len = xname->name.len; ++ xavp = xavp_get_by_index(&xname->name, 0, NULL); ++ if(xavp==NULL) ++ { ++ return 0; /* empty */ ++ } ++ ++ do ++ { ++ if(xavp->val.type==SR_XTYPE_XAVP) ++ { ++ avp = xavp->val.v.xavp; ++ jobj = srjson_CreateObject(jdoc); ++ if(jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ keys = xavp_get_list_key_names(xavp); ++ if(keys!=NULL) ++ { ++ do ++ { ++ _dbg_get_obj_avp_vals(keys->s, avp, jdoc, &jobjt); ++ srjson_AddStrItemToObject(jdoc, jobj, keys->s.s, ++ keys->s.len, jobjt); ++ k = keys; ++ keys = keys->next; ++ pkg_free(k); ++ jobjt = NULL; ++ }while(keys!=NULL); ++ } ++ } ++ if(jobj!=NULL) ++ { ++ srjson_AddItemToArray(jdoc, *jobjr, jobj); ++ jobj = NULL; ++ } ++ }while((xavp = xavp_get_next(xavp))!=0); ++ ++ return 0; ++} ++ ++int dbg_get_json(struct sip_msg* msg, unsigned int mask, srjson_doc_t *jdoc, ++ srjson_t *head) ++{ ++ int i; ++ pv_value_t value; ++ pv_cache_t **_pv_cache = pv_cache_get_table(); ++ pv_cache_t *el = NULL; ++ srjson_t *jobj = NULL; ++ str item_name = STR_NULL; ++ static char iname[128]; ++ ++ if(_pv_cache==NULL) ++ { ++ LM_ERR("cannot access pv_cache\n"); ++ return -1; ++ } ++ if(jdoc==NULL){ ++ LM_ERR("jdoc is null\n"); ++ return -1; ++ } ++ if(head==NULL){ ++ LM_ERR("head is null\n"); ++ return -1; ++ } ++ ++ memset(_dbg_xavp_dump, 0, sizeof(str*)*DBG_XAVP_DUMP_SIZE); ++ for(i=0;ispec.type==PVT_AVP|| ++ el->spec.type==PVT_SCRIPTVAR|| ++ el->spec.type==PVT_XAVP|| ++ el->spec.type==PVT_OTHER)|| ++ !((el->spec.type==PVT_AVP&&mask&DBG_DP_AVP)|| ++ (el->spec.type==PVT_XAVP&&mask&DBG_DP_XAVP)|| ++ (el->spec.type==PVT_SCRIPTVAR&&mask&DBG_DP_SCRIPTVAR)|| ++ (el->spec.type==PVT_OTHER&&mask&DBG_DP_OTHER))|| ++ (el->spec.trans!=NULL)) ++ { ++ el = el->next; ++ continue; ++ } ++ jobj = NULL; ++ item_name.len = 0; ++ item_name.s = 0; ++ iname[0] = '\0'; ++ if(el->spec.type==PVT_AVP) ++ { ++ if(el->spec.pvp.pvi.type==PV_IDX_ALL|| ++ (el->spec.pvp.pvi.type==PV_IDX_INT&&el->spec.pvp.pvi.u.ival!=0)) ++ { ++ el = el->next; ++ continue; ++ } ++ else ++ { ++ if(_dbg_get_array_avp_vals(msg, &el->spec.pvp, jdoc, &jobj, &item_name)!=0) ++ { ++ LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); ++ el = el->next; ++ continue; ++ } ++ if(srjson_GetArraySize(jdoc, jobj)==0 && !(mask&DBG_DP_NULL)) ++ { ++ el = el->next; ++ continue; ++ } ++ snprintf(iname, 128, "$avp(%.*s)", item_name.len, item_name.s); ++ } ++ } ++ else if(el->spec.type==PVT_XAVP) ++ { ++ if(_dbg_xavp_dump_lookup(&el->spec.pvp)!=0) ++ { ++ el = el->next; ++ continue; ++ } ++ if(_dbg_get_obj_xavp_vals(msg, &el->spec.pvp, jdoc, &jobj, &item_name)!=0) ++ { ++ LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); ++ el = el->next; ++ continue; ++ } ++ if(srjson_GetArraySize(jdoc, jobj)==0 && !(mask&DBG_DP_NULL)) ++ { ++ el = el->next; ++ continue; ++ } ++ snprintf(iname, 128, "$xavp(%.*s)", item_name.len, item_name.s); ++ } ++ else ++ { ++ if(pv_get_spec_value(msg, &el->spec, &value)!=0) ++ { ++ LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); ++ el = el->next; ++ continue; ++ } ++ if(value.flags&(PV_VAL_NULL|PV_VAL_EMPTY|PV_VAL_NONE)) ++ { ++ if(mask&DBG_DP_NULL) ++ { ++ jobj = srjson_CreateNull(jdoc); ++ } ++ else ++ { ++ el = el->next; ++ continue; ++ } ++ }else if(value.flags&(PV_VAL_INT)){ ++ jobj = srjson_CreateNumber(jdoc, value.ri); ++ }else if(value.flags&(PV_VAL_STR)){ ++ jobj = srjson_CreateStr(jdoc, value.rs.s, value.rs.len); ++ }else { ++ LM_WARN("el->pvname[%.*s] value[%d] unhandled\n", el->pvname.len, el->pvname.s, ++ value.flags); ++ el = el->next; ++ continue; ++ } ++ if(jobj==NULL) ++ { ++ LM_ERR("el->pvname[%.*s] empty json object\n", el->pvname.len, ++ el->pvname.s); ++ goto error; ++ } ++ snprintf(iname, 128, "%.*s", el->pvname.len, el->pvname.s); ++ } ++ if(jobj!=NULL) ++ { ++ srjson_AddItemToObject(jdoc, head, iname, jobj); ++ } ++ el = el->next; ++ } ++ } ++ return 0; ++ ++error: ++ srjson_Delete(jdoc, head); ++ return -1; ++} ++ ++int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level) ++{ ++ char *output = NULL; ++ srjson_doc_t jdoc; ++ ++ srjson_InitDoc(&jdoc, NULL); ++ if(jdoc.root==NULL) ++ { ++ jdoc.root = srjson_CreateObject(&jdoc); ++ if(jdoc.root==NULL) ++ { ++ LM_ERR("cannot create json root\n"); ++ goto error; ++ } ++ } ++ ++ if(dbg_get_json(msg, mask, &jdoc, jdoc.root)<0) goto error; ++ output = srjson_PrintUnformatted(&jdoc, jdoc.root); ++ if(output==NULL) ++ { ++ LM_ERR("cannot print json doc\n"); ++ srjson_DestroyDoc(&jdoc); ++ } ++ LOG(level, "%s\n", output); ++ jdoc.free_fn(output); ++ srjson_DestroyDoc(&jdoc); ++ return 0; ++ ++error: ++ srjson_DestroyDoc(&jdoc); ++ return -1; ++} +--- /dev/null ++++ b/modules/debugger/debugger_json.h +@@ -0,0 +1,32 @@ ++/** ++ * ++ * Copyright (C) 2013-2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#ifndef _DEBUGGER_JSON_H ++#define _DEBUGGER_JSON_H ++ ++#include "../../lib/srutils/srjson.h" ++#include "../../route_struct.h" ++ ++int dbg_get_json(struct sip_msg* msg, unsigned int mask, srjson_doc_t *jdoc, ++ srjson_t *head); ++int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level); ++#endif +--- a/modules/debugger/debugger_mod.c ++++ b/modules/debugger/debugger_mod.c +@@ -37,6 +37,7 @@ + + #include "debugger_api.h" + #include "debugger_config.h" ++#include "debugger_json.h" + + MODULE_VERSION + diff --git a/debian/patches/sipwise/debug/0001-modules-cfgt-trace-config-and-save-to-file.patch b/debian/patches/sipwise/debug/0001-modules-cfgt-trace-config-and-save-to-file.patch new file mode 100644 index 000000000..a355035f7 --- /dev/null +++ b/debian/patches/sipwise/debug/0001-modules-cfgt-trace-config-and-save-to-file.patch @@ -0,0 +1,1718 @@ +From 95948013a291286ebd332bb71cdffb09a0618606 Mon Sep 17 00:00:00 2001 +From: Victor Seva +Date: Wed, 24 Jun 2015 22:19:24 +0200 +Subject: [PATCH] modules/cfgt: trace config and save to file + +--- + modules/cfgt/Makefile | 17 + + modules/cfgt/cfgt.c | 45 +++ + modules/cfgt/cfgt.h | 40 ++ + modules/cfgt/cfgt_int.c | 797 ++++++++++++++++++++++++++++++++++++++++ + modules/cfgt/cfgt_int.h | 67 ++++ + modules/cfgt/cfgt_json.c | 389 ++++++++++++++++++++ + modules/cfgt/cfgt_json.h | 38 ++ + modules/cfgt/cfgt_mod.c | 112 ++++++ + modules/cfgt/cfgt_mod.h | 29 ++ + modules/debugger/debugger_api.c | 19 + + modules/debugger/debugger_mod.c | 21 ++ + 11 files changed, 1574 insertions(+) + create mode 100644 modules/cfgt/Makefile + create mode 100644 modules/cfgt/cfgt.c + create mode 100644 modules/cfgt/cfgt.h + create mode 100644 modules/cfgt/cfgt_int.c + create mode 100644 modules/cfgt/cfgt_int.h + create mode 100644 modules/cfgt/cfgt_json.c + create mode 100644 modules/cfgt/cfgt_json.h + create mode 100644 modules/cfgt/cfgt_mod.c + create mode 100644 modules/cfgt/cfgt_mod.h + +--- /dev/null ++++ b/modules/cfgt/Makefile +@@ -0,0 +1,17 @@ ++# ++# cfgt module makefile ++# ++# WARNING: do not run this directly, it should be run by the master Makefile ++ ++include ../../Makefile.defs ++auto_gen= ++NAME=cfgt.so ++LIBS= ++ ++DEFS+=-DKAMAILIO_MOD_INTERFACE ++ ++SERLIBPATH=../../lib ++SER_LIBS+=$(SERLIBPATH)/kcore/kcore ++SER_LIBS+=$(SERLIBPATH)/srutils/srutils ++ ++include ../../Makefile.modules +--- /dev/null ++++ b/modules/cfgt/cfgt.c +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * Kamailio is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * Kamailio is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * ++ */ ++#include "cfgt_mod.h" ++#include "cfgt.h" ++#include "cfgt_int.h" ++ ++/*! ++ * \brief cfgt module API export bind function ++ * \param api cfgt API ++ * \return 0 on success, -1 on failure ++ */ ++int bind_cfgt(cfgt_api_t* api) ++{ ++ if (!api) { ++ LM_ERR("invalid parameter value\n"); ++ return -1; ++ } ++ if (init_flag==0) { ++ LM_ERR("configuration error - trying to bind to cfgt module" ++ " before being initialized\n"); ++ return -1; ++ } ++ ++ api->cfgt_process_route = cfgt_process_route; ++ return 0; ++} +--- /dev/null ++++ b/modules/cfgt/cfgt.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * Kamailio is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * Kamailio is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * ++ */ ++ ++#ifndef _CFGT_BIND_H ++#define _CFGT_BIND_H ++ ++#include "../../sr_module.h" ++ ++/* export not usable from scripts */ ++#define NO_SCRIPT -1 ++ ++typedef int (*cfgt_process_route_f)(struct sip_msg *msg, struct action *a); ++ ++typedef struct cfgt_api { ++ cfgt_process_route_f cfgt_process_route; ++} cfgt_api_t; ++ ++/*! cfgt API export bind function */ ++typedef int (*bind_cfgt_t)(cfgt_api_t* api); ++ ++#endif +--- /dev/null ++++ b/modules/cfgt/cfgt_int.c +@@ -0,0 +1,797 @@ ++/** ++ * ++ * Copyright (C) 2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++#include ++#include ++ ++#include "../../events.h" ++#include "../../lib/kcore/cmpapi.h" ++#include "../../pvar.h" ++#include "../../rpc.h" ++#include "../../rpc_lookup.h" ++ ++#include "cfgt_int.h" ++#include "cfgt_json.h" ++ ++static str _cfgt_route_prefix[] = { ++ str_init("start|"), ++ str_init("exit|"), ++ str_init("drop|"), ++ str_init("return|"), ++ {0, 0} ++}; ++cfgt_node_p _cfgt_node = NULL; ++cfgt_hash_p _cfgt_uuid = NULL; ++str cfgt_hdr_prefix = {"NGCP%", 5}; ++str cfgt_basedir = {"/tmp", 4}; ++int cfgt_mask = CFGT_DP_ALL; ++ ++static int shm_str_hash_alloc(struct str_hash_table *ht, int size) ++{ ++ ht->table = shm_malloc(sizeof(struct str_hash_head) * size); ++ ++ if (!ht->table) ++ return -1; ++ ++ ht->size = size; ++ return 0; ++} ++ ++static int _cfgt_init_hashtable(struct str_hash_table *ht) ++{ ++ if (shm_str_hash_alloc(ht, CFGT_HASH_SIZE) != 0) ++ { ++ LM_ERR("Error allocating shared memory hashtable\n"); ++ return -1; ++ } ++ ++ str_hash_init(ht); ++ ++ return 0; ++} ++ ++int _cfgt_pv_parse(str *param, pv_elem_p *elem) ++{ ++ if (param->s && param->len > 0) ++ { ++ if (pv_parse_format(param, elem)<0) ++ { ++ LM_ERR("malformed or non AVP %.*s AVP definition\n", ++ param->len, param->s); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++void _cfgt_remove_uuid(const str *uuid) ++{ ++ struct str_hash_head *head; ++ struct str_hash_entry *entry, *back; ++ int i; ++ ++ if(_cfgt_uuid==NULL) return; ++ if(uuid) ++ { ++ lock_get(&_cfgt_uuid->lock); ++ entry = str_hash_get(&_cfgt_uuid->hash, uuid->s, uuid->len); ++ if(entry) ++ { ++ str_hash_del(entry); ++ shm_free(entry->key.s); ++ shm_free(entry); ++ LM_DBG("uuid[%.*s] removed from hash\n", uuid->len, uuid->s); ++ } ++ else LM_DBG("uuid[%.*s] not found in hash\n", uuid->len, uuid->s); ++ lock_release(&_cfgt_uuid->lock); ++ } ++ else ++ { ++ lock_get(&_cfgt_uuid->lock); ++ for(i=0; ihash.table+i; ++ clist_foreach_safe(head, entry, back, next) ++ { ++ LM_DBG("uuid[%.*s] removed from hash\n", ++ entry->key.len, entry->key.s); ++ str_hash_del(entry); ++ shm_free(entry->key.s); ++ shm_free(entry); ++ } ++ lock_release(&_cfgt_uuid->lock); ++ } ++ LM_DBG("remove all uuids. done\n"); ++ } ++} ++ ++int _cfgt_get_uuid_id(cfgt_node_p node) ++{ ++ struct str_hash_entry *entry; ++ ++ if(_cfgt_uuid==NULL || node==NULL || node->uuid.len == 0) return -1; ++ lock_get(&_cfgt_uuid->lock); ++ entry = str_hash_get(&_cfgt_uuid->hash, node->uuid.s, node->uuid.len); ++ if(entry) ++ { ++ entry->u.n = entry->u.n + 1; ++ node->msgid = entry->u.n; ++ } ++ else ++ { ++ entry = shm_malloc(sizeof(struct str_hash_entry)); ++ if(entry==NULL) ++ { ++ lock_release(&_cfgt_uuid->lock); ++ LM_ERR("No shared memory left\n"); ++ return -1; ++ } ++ if (shm_str_dup(&entry->key, &node->uuid) != 0) ++ { ++ lock_release(&_cfgt_uuid->lock); ++ shm_free(entry); ++ LM_ERR("No shared memory left\n"); ++ return -1; ++ } ++ entry->u.n = 1; ++ node->msgid = 1; ++ LM_DBG("Add new entry[%.*s]\n", node->uuid.len, node->uuid.s); ++ str_hash_add(&_cfgt_uuid->hash, entry); ++ } ++ lock_release(&_cfgt_uuid->lock); ++ LM_DBG("msgid:[%d]\n", node->msgid); ++ return 1; ++} ++ ++int _cfgt_get_hdr_helper(struct sip_msg *msg, str *res, int mode) ++{ ++ struct hdr_field *hf; ++ char *delimiter, *end; ++ str tmp = STR_NULL; ++ ++ if(msg==NULL || (mode==0 && res==NULL)) ++ return -1; ++ ++ /* we need to be sure we have parsed all headers */ ++ if(parse_headers(msg, HDR_EOH_F, 0)<0) ++ { ++ LM_ERR("error parsing headers\n"); ++ return -1; ++ } ++ ++ hf = msg->callid; ++ if(!hf) return 1; ++ ++ if(strncmp(hf->body.s, cfgt_hdr_prefix.s, cfgt_hdr_prefix.len)==0) ++ { ++ tmp.s = hf->body.s+cfgt_hdr_prefix.len; ++ delimiter = tmp.s-1; ++ LM_DBG("Prefix detected. delimiter[%c]\n", *delimiter); ++ if(mode==0) ++ { ++ end = strchr(tmp.s, *delimiter); ++ if(end) ++ { ++ tmp.len = end-tmp.s; ++ if(pkg_str_dup(res, &tmp)<0) ++ { ++ LM_ERR("error copying header\n"); ++ return -1; ++ } ++ LM_DBG("cfgtest uuid:[%.*s]\n", res->len, res->s); ++ return 0; ++ } ++ } ++ else ++ { ++ tmp.len = res->len; ++ LM_DBG("tmp[%.*s] res[%.*s]\n", tmp.len, tmp.s, res->len, res->s); ++ return STR_EQ(tmp, *res); ++ } ++ } ++ return 1; /* not found */ ++} ++ ++int _cfgt_get_hdr(struct sip_msg *msg, str *res) ++{ ++ return _cfgt_get_hdr_helper(msg, res, 0); ++} ++ ++int _cfgt_cmp_hdr(struct sip_msg *msg, str *res) ++{ ++ return _cfgt_get_hdr_helper(msg, res, 1); ++} ++ ++cfgt_node_p cfgt_create_node(struct sip_msg *msg) ++{ ++ cfgt_node_p node; ++ ++ node = (cfgt_node_p) pkg_malloc(sizeof(cfgt_node_t)); ++ if(node==NULL) ++ { ++ LM_ERR("cannot allocate cfgtest msgnode\n"); ++ return node; ++ } ++ memset(node, 0, sizeof(cfgt_node_t)); ++ srjson_InitDoc(&node->jdoc, NULL); ++ if (msg) ++ { ++ node->msgid = msg->id; ++ LM_DBG("msgid:%d\n", node->msgid); ++ if(_cfgt_get_hdr(msg, &node->uuid)!=0 || &node->uuid.len==0) ++ { ++ LM_ERR("cannot get value of cfgtest uuid header!!\n"); ++ goto error; ++ } ++ } ++ node->jdoc.root = srjson_CreateObject(&node->jdoc); ++ if(node->jdoc.root==NULL) ++ { ++ LM_ERR("cannot create json root\n"); ++ goto error; ++ } ++ node->flow = srjson_CreateArray(&node->jdoc); ++ if(node->flow==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ goto error; ++ } ++ srjson_AddItemToObject(&node->jdoc, node->jdoc.root, "flow\0", node->flow); ++ node->in = srjson_CreateArray(&node->jdoc); ++ if(node->in==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ goto error; ++ } ++ srjson_AddItemToObject(&node->jdoc, node->jdoc.root, "sip_in\0", node->in); ++ node->out = srjson_CreateArray(&node->jdoc); ++ if(node->out==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ goto error; ++ } ++ srjson_AddItemToObject(&node->jdoc, node->jdoc.root, "sip_out\0", node->out); ++ LM_DBG("node created\n"); ++ return node; ++ ++error: ++ srjson_DestroyDoc(&node->jdoc); ++ pkg_free(node); ++ return NULL; ++} ++ ++void _cfgt_remove_node(cfgt_node_p node) ++{ ++ if(!node) return; ++ srjson_DestroyDoc(&node->jdoc); ++ if(node->uuid.s) pkg_free(node->uuid.s); ++ while(node->flow_head) ++ { ++ node->route = node->flow_head; ++ node->flow_head = node->route->next; ++ pkg_free(node->route); ++ node->route = NULL; ++ } ++ pkg_free(node); ++} ++ ++int _cfgt_get_filename(int msgid, str uuid, str *dest, int *dir) ++{ ++ int i, lid; ++ char buff_id[INT2STR_MAX_LEN]; ++ char *sid; ++ if(dest==NULL || uuid.len == 0) return -1; ++ ++ dest->len = cfgt_basedir.len + uuid.len; ++ if(cfgt_basedir.s[cfgt_basedir.len-1]!='/') ++ dest->len = dest->len + 1; ++ sid = sint2strbuf(msgid, buff_id, INT2STR_MAX_LEN, &lid); ++ dest->len += lid + 6; ++ dest->s = (char *) pkg_malloc((dest->len*sizeof(char)+1)); ++ if(dest->s==NULL) ++ { ++ LM_ERR("no more memory.\n"); ++ return -1; ++ } ++ strncpy(dest->s, cfgt_basedir.s, cfgt_basedir.len); ++ i = cfgt_basedir.len; ++ if(cfgt_basedir.s[cfgt_basedir.len-1]!='/') ++ { ++ strncpy(dest->s+i, "/", 1); ++ i = i + 1; ++ } ++ strncpy(dest->s+i, uuid.s, uuid.len); ++ i = i + uuid.len; (*dir) = i; ++ strncpy(dest->s+i, "\0", 1); ++ i = i + 1; ++ strncpy(dest->s+i, sid, lid); ++ i = i + lid; ++ strncpy(dest->s+i, ".json\0", 6); ++ return 0; ++} ++ ++int _cfgt_node2json(cfgt_node_p node) ++{ ++ srjson_t *jobj; ++ ++ if(!node) return -1; ++ jobj = srjson_CreateStr(&node->jdoc, node->uuid.s, node->uuid.len); ++ if(jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ srjson_AddItemToObject(&node->jdoc, node->jdoc.root, "uuid\0", jobj); ++ ++ jobj = srjson_CreateNumber(&node->jdoc, (double)node->msgid); ++ if(jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ srjson_AddItemToObject(&node->jdoc, node->jdoc.root, "msgid\0", jobj); ++ return 0; ++} ++ ++void cfgt_save_node(cfgt_node_p node) ++{ ++ FILE *fp; ++ str dest = STR_NULL; ++ int dir = 0; ++ if(_cfgt_get_filename(node->msgid, node->uuid, &dest, &dir)<0) ++ { ++ LM_ERR("can't build filename\n"); ++ return; ++ } ++ LM_DBG("dir [%s]\n", dest.s); ++ mkdir(dest.s, S_IRWXO|S_IXGRP|S_IRWXU); ++ dest.s[dir] = '/'; ++ fp = fopen(dest.s, "w"); ++ LM_DBG("file [%s]\n", dest.s); ++ if(fp) { ++ pkg_free(dest.s); ++ dest.s = srjson_Print(&node->jdoc, node->jdoc.root); ++ if(dest.s==NULL) ++ { ++ LM_ERR("Cannot get the json string\n"); ++ fclose(fp); ++ return; ++ } ++ if(fputs(dest.s, fp)<0){ ++ LM_ERR("failed writing to file\n"); ++ } ++ fclose(fp); ++ node->jdoc.free_fn(dest.s); ++ } ++ else { ++ LM_ERR("Can't open file [%s] to write\n", dest.s); ++ pkg_free(dest.s); ++ } ++} ++ ++void _cfgt_print_node(cfgt_node_p node, int json) ++{ ++ char *buf = NULL; ++ cfgt_str_list_p route; ++ ++ if(!node) return; ++ if(node->flow_head) ++ { ++ route = node->flow_head; ++ while(route) ++ { ++ if(route == node->route) ++ LM_DBG("[--[%.*s][%d]--]\n", ++ route->s.len, route->s.s, route->type); ++ else LM_DBG("[%.*s][%d]\n", ++ route->s.len, route->s.s, route->type); ++ route = route->next; ++ } ++ } ++ else LM_DBG("flow:empty\n"); ++ if(json) { ++ buf = srjson_PrintUnformatted(&node->jdoc, node->jdoc.root); ++ if(buf==NULL) ++ { ++ LM_ERR("Cannot get the json string\n"); ++ return; ++ } ++ LM_DBG("node[%p]: id:[%d] uuid:[%.*s] info:[%s]\n", ++ node, node->msgid, node->uuid.len, node->uuid.s, buf); ++ node->jdoc.free_fn(buf); ++ } ++} ++ ++int _cfgt_set_dump(struct sip_msg *msg, cfgt_node_p node, str *flow) ++{ ++ srjson_t *f, *vars; ++ ++ if(node==NULL || flow == NULL) return -1; ++ vars = srjson_CreateObject(&node->jdoc); ++ if(vars==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ if(cfgt_get_json(msg, 30, &node->jdoc, vars)<0) ++ { ++ LM_ERR("cannot get var info\n"); ++ return -1; ++ } ++ f = srjson_CreateObject(&node->jdoc); ++ if(f==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ srjson_Delete(&node->jdoc, vars); ++ return -1; ++ } ++ srjson_AddStrItemToObject(&node->jdoc, f, ++ flow->s, flow->len, vars); ++ srjson_AddItemToArray(&node->jdoc, node->flow, f); ++ LM_DBG("node[%.*s] flow created\n", flow->len, flow->s); ++ return 0; ++} ++ ++void _cfgt_set_type(cfgt_str_list_p route, struct action *a) ++{ ++ switch(a->type) ++ { ++ case DROP_T: ++ if(a->val[1].u.number&DROP_R_F) { ++ route->type = CFGT_DROP_D; ++ LM_DBG("set[%.*s]->CFGT_DROP_D\n", route->s.len, route->s.s); ++ } ++ if(a->val[1].u.number&RETURN_R_F){ ++ route->type = CFGT_DROP_R; ++ LM_DBG("set[%.*s]->CFGT_DROP_R\n", route->s.len, route->s.s); ++ } ++ else { ++ route->type = CFGT_DROP_E; ++ LM_DBG("set[%.*s]->CFGT_DROP_E\n", route->s.len, route->s.s); ++ } ++ break; ++ case ROUTE_T: ++ route->type = CFGT_ROUTE; ++ LM_DBG("set[%.*s]->CFGT_ROUTE\n", route->s.len, route->s.s); ++ break; ++ default: ++ if(route->type!=CFGT_DROP_E) ++ { ++ route->type = CFGT_DROP_R; ++ LM_DBG("[%.*s] no relevant action: CFGT_DROP_R[%d]\n", ++ route->s.len, route->s.s, a->type); ++ } ++ else ++ { ++ LM_DBG("[%.*s] already set to CFGT_DROP_E[%d]\n", ++ route->s.len, route->s.s, a->type); ++ } ++ break; ++ } ++} ++ ++int _cfgt_add_routename(cfgt_node_p node, struct action *a, ++ str *routename) ++{ ++ cfgt_str_list_p route; ++ int ret = 0; ++ ++ if(!node->route) /* initial */ ++ { ++ node->route = pkg_malloc(sizeof(cfgt_str_list_t)); ++ if(!node->route) ++ { ++ LM_ERR("No more pkg mem\n"); ++ return -1; ++ } ++ memset(node->route, 0, sizeof(cfgt_str_list_t)); ++ node->flow_head = node->route; ++ node->route->type = CFGT_ROUTE; ++ ret = 1; ++ } ++ else ++ { ++ LM_DBG("actual routename:[%.*s][%d]\n", node->route->s.len, ++ node->route->s.s, node->route->type); ++ if(node->route->prev) ++ LM_DBG("prev routename:[%.*s][%d]\n", node->route->prev->s.len, ++ node->route->prev->s.s, node->route->prev->type); ++ if(node->route->next) ++ LM_DBG("next routename:[%.*s][%d]\n", node->route->next->s.len, ++ node->route->next->s.s, node->route->next->type); ++ if(STR_EQ(*routename, node->route->s)) ++ { ++ LM_DBG("same route\n"); ++ _cfgt_set_type(node->route, a); ++ return 2; ++ } ++ else if(node->route->prev && ++ STR_EQ(*routename, node->route->prev->s)) ++ { ++ LM_DBG("back to route[%.*s]\n", node->route->prev->s.len, ++ node->route->prev->s.s); ++ _cfgt_set_type(node->route->prev, a); ++ return 3; ++ } ++ route = pkg_malloc(sizeof(cfgt_str_list_t)); ++ if(!route) ++ { ++ LM_ERR("No more pkg mem\n"); ++ return -1; ++ } ++ memset(route, 0, sizeof(cfgt_str_list_t)); ++ route->prev = node->route; ++ node->route->next = route; ++ node->route = route; ++ _cfgt_set_type(node->route, a); ++ } ++ node->route->s.s = routename->s; ++ node->route->s.len = routename->len; ++ LM_DBG("add[%d] route:[%.*s]\n", ret, node->route->s.len, node->route->s.s); ++ _cfgt_print_node(node, 0); ++ return ret; ++} ++ ++void _cfgt_del_routename(cfgt_node_p node) ++{ ++ if(node->route->next!=NULL) { ++ LM_ERR("wtf!! route->next[%p] not null!!\n", node->route->next); ++ _cfgt_print_node(node, 0); ++ } ++ LM_DBG("del route[%.*s]\n", node->route->s.len, node->route->s.s); ++ node->route = node->route->prev; ++ pkg_free(node->route->next); ++ node->route->next = NULL; ++} ++/* dest has to be freed */ ++int _cfgt_node_get_flowname(cfgt_str_list_p route, int *indx, str *dest) ++{ ++ int i; ++ if(route==NULL) return -1; ++ LM_DBG("routename:[%.*s][%d]\n", route->s.len, route->s.s, ++ route->type); ++ if(indx) i = *indx; ++ else i = route->type-1; ++ if(str_append(&_cfgt_route_prefix[i], ++ &route->s, dest)<0) ++ { ++ LM_ERR("Cannot create route name\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++int cfgt_process_route(struct sip_msg *msg, struct action *a) ++{ ++ str routename; ++ int ret = -1; ++ int indx = 0; ++ str flowname = STR_NULL; ++ if(!_cfgt_node) { ++ LM_ERR("node empty\n"); ++ return -1; ++ } ++ if (a->rname==NULL) { ++ LM_DBG("no routename. type:%d\n", a->type); ++ return 0; ++ } ++ LM_DBG("route from action:[%s]\n", a->rname); ++ routename.s = a->rname; routename.len = strlen(a->rname); ++ switch(_cfgt_add_routename(_cfgt_node, a, &routename)) ++ { ++ case 2: /* same name */ ++ return 0; ++ case 1: /* initial */ ++ LM_DBG("Initial route[%.*s]. dump vars\n", ++ _cfgt_node->route->s.len, _cfgt_node->route->s.s); ++ if(_cfgt_node_get_flowname(_cfgt_node->route, &indx, &flowname)<0) ++ { ++ LM_ERR("cannot create flowname\n"); ++ return -1; ++ } ++ ret = _cfgt_set_dump(msg, _cfgt_node, &flowname); ++ break; ++ case 0: /* new */ ++ LM_DBG("Change from[%.*s] route to route[%.*s]. dump vars\n", ++ _cfgt_node->route->prev->s.len, _cfgt_node->route->prev->s.s, ++ _cfgt_node->route->s.len, _cfgt_node->route->s.s); ++ if(_cfgt_node_get_flowname(_cfgt_node->route, &indx, &flowname)<0) ++ { ++ LM_ERR("cannot create flowname\n"); ++ return -1; ++ } ++ ret = _cfgt_set_dump(msg, _cfgt_node, &flowname); ++ break; ++ case 3: /* back to previous */ ++ if(_cfgt_node_get_flowname(_cfgt_node->route, 0, &flowname)<0) ++ { ++ LM_ERR("cannot create flowname\n"); ++ return -1; ++ } ++ ret = _cfgt_set_dump(msg, _cfgt_node, &flowname); ++ _cfgt_del_routename(_cfgt_node); ++ break; ++ default: ++ return -1; ++ } ++ if(flowname.s) pkg_free(flowname.s); ++ return ret; ++} ++ ++/* ++TODO: ++- parse first line, check if is SIP ++- parse for header cfgtest ++*/ ++int cfgt_msgin(void *data) ++{ ++ srjson_t *jobj; ++ str *buf = (str *) data; ++ if(buf==NULL) return 0; ++ if(_cfgt_node) { ++ cfgt_save_node(_cfgt_node); ++ _cfgt_remove_node(_cfgt_node); ++ LM_DBG("node removed\n"); ++ _cfgt_node = NULL; ++ } ++ LM_DBG("msg in:{%.*s}\n", buf->len, buf->s); ++ _cfgt_node = cfgt_create_node(NULL); ++ if(_cfgt_node) ++ { ++ jobj = srjson_CreateStr(&_cfgt_node->jdoc, buf->s, buf->len); ++ if(jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ srjson_AddItemToArray(&_cfgt_node->jdoc, _cfgt_node->in, jobj); ++ return 0; ++ } ++ LM_ERR("_cfgt_node empty\n"); ++ return -1; ++} ++ ++int cfgt_pre(struct sip_msg *msg, unsigned int flags, void *bar) { ++ str unknown = {"unknown", 7}; ++ ++ if(_cfgt_node) ++ { ++ if (_cfgt_node->msgid == 0) ++ { ++ LM_DBG("new node\n"); ++ if(_cfgt_get_hdr(msg, &_cfgt_node->uuid)!=0 || ++ _cfgt_node->uuid.len==0) ++ { ++ LM_ERR("cannot get value of cfgtest uuid header." ++ " Using unknown\n"); ++ pkg_str_dup(&_cfgt_node->uuid, &unknown); ++ } ++ return _cfgt_get_uuid_id(_cfgt_node); ++ } ++ else ++ { ++ LM_DBG("_cfgt_node->uuid:[%.*s]\n", _cfgt_node->uuid.len, ++ _cfgt_node->uuid.s); ++ if(_cfgt_cmp_hdr(msg, &_cfgt_node->uuid)) ++ { ++ LM_DBG("same uuid\n"); ++ return 1; ++ } ++ else { ++ LM_DBG("different uuid\n"); ++ } ++ } ++ } ++ else { LM_ERR("node empty??\n"); } ++ _cfgt_node = cfgt_create_node(msg); ++ if(_cfgt_node) { ++ LM_DBG("node created\n"); ++ return 1; ++ } ++ return -1; ++} ++int cfgt_post(struct sip_msg *msg, unsigned int flags, void *bar) { ++ str flowname = STR_NULL; ++ ++ if(_cfgt_node) { ++ LM_DBG("dump last flow\n"); ++ if(_cfgt_node_get_flowname(_cfgt_node->route, 0, &flowname)<0) ++ LM_ERR("cannot create flowname\n"); ++ else _cfgt_set_dump(msg, _cfgt_node, &flowname); ++ if(flowname.s) pkg_free(flowname.s); ++ cfgt_save_node(_cfgt_node); ++ } ++ return 1; ++} ++ ++int cfgt_msgout(void *data) ++{ ++ srjson_t *jobj; ++ str *buf = (str *) data; ++ if(buf==NULL) return 0; ++ LM_DBG("msg out:{%.*s}\n", buf->len, buf->s); ++ ++ if(_cfgt_node) ++ { ++ jobj = srjson_CreateStr(&_cfgt_node->jdoc, buf->s, buf->len); ++ if(jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ srjson_AddItemToArray(&_cfgt_node->jdoc, _cfgt_node->out, jobj); ++ return 0; ++ } ++ LM_ERR("node empty\n"); ++ return -1; ++} ++ ++/** ++ * ++ */ ++static const char* cfgt_rpc_mask_doc[2] = { ++ "Specify module mask", ++ 0 ++}; ++ ++static void cfgt_rpc_mask(rpc_t* rpc, void* ctx){ ++ int mask = CFGT_DP_ALL; ++ ++ if (rpc->scan(ctx, "*d", &mask) != 1) ++ { ++ rpc->fault(ctx, 500, "invalid parameters"); ++ return; ++ } ++ cfgt_mask = mask; ++ rpc->add(ctx, "s", "200 ok"); ++} ++ ++rpc_export_t cfgt_rpc[] = { ++ {"dbg.mask", cfgt_rpc_mask, cfgt_rpc_mask_doc, 0}, ++ {0, 0, 0, 0} ++}; ++ ++int cfgt_init(void) ++{ ++ if (rpc_register_array(cfgt_rpc)!=0) ++ { ++ LM_ERR("failed to register RPC commands\n"); ++ return -1; ++ } ++ _cfgt_uuid = shm_malloc(sizeof(cfgt_hash_t)); ++ if(_cfgt_uuid==NULL) ++ { ++ LM_ERR("Cannot allocate shared memory\n"); ++ return -1; ++ } ++ if(!lock_init(&_cfgt_uuid->lock)) ++ { ++ LM_ERR("cannot init the lock\n"); ++ shm_free(_cfgt_uuid); ++ _cfgt_uuid = NULL; ++ return -1; ++ } ++ if(_cfgt_init_hashtable(&_cfgt_uuid->hash)<0) ++ return -1; ++ sr_event_register_cb(SREV_NET_DATA_IN, cfgt_msgin); ++ sr_event_register_cb(SREV_NET_DATA_OUT, cfgt_msgout); ++ return 0; ++} +--- /dev/null ++++ b/modules/cfgt/cfgt_int.h +@@ -0,0 +1,67 @@ ++/** ++ * ++ * Copyright (C) 2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++#ifndef _CFGT_INT_H_ ++#define _CFGT_INT_H_ ++ ++#include "../../lib/srutils/srjson.h" ++#include "../../locking.h" ++#include "../../route_struct.h" ++#include "../../str_hash.h" ++ ++#define CFGT_HASH_SIZE 32 ++ ++enum _cfgt_action_type { ++ CFGT_ROUTE=1, ++ CFGT_DROP_E, CFGT_DROP_D, CFGT_DROP_R ++}; ++ ++typedef struct _cfgt_hash ++{ ++ gen_lock_t lock; ++ struct str_hash_table hash; ++ str save_uuid; /* uuid to be save */ ++} cfgt_hash_t, *cfgt_hash_p; ++ ++typedef struct _cfgt_str_list ++{ ++ str s; ++ enum _cfgt_action_type type; ++ struct _cfgt_str_list *next, *prev; ++} cfgt_str_list_t, *cfgt_str_list_p; ++ ++typedef struct _cfgt_node ++{ ++ srjson_doc_t jdoc; ++ str uuid; ++ int msgid; ++ cfgt_str_list_p flow_head; ++ cfgt_str_list_p route; ++ srjson_t *in, *out, *flow; ++ struct _cfgt_node *next, *prev; ++} cfgt_node_t, *cfgt_node_p; ++ ++int cfgt_init(void); ++cfgt_node_p cfgt_create_node(struct sip_msg *msg); ++int cfgt_process_route(struct sip_msg *msg, struct action *a); ++int cfgt_pre(struct sip_msg *msg, unsigned int flags, void *bar); ++int cfgt_post(struct sip_msg *msg, unsigned int flags, void *bar); ++#endif +--- /dev/null ++++ b/modules/cfgt/cfgt_json.c +@@ -0,0 +1,389 @@ ++/** ++ * ++ * Copyright (C) 2013-2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++#include ++ ++#include "../../pvar.h" ++#include "../../mem/shm_mem.h" ++#include "../../xavp.h" ++#include "../pv/pv_xavp.h" ++ ++#include "cfgt_json.h" ++ ++int _cfgt_get_array_avp_vals(struct sip_msg *msg, ++ pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobj, ++ str *item_name) ++{ ++ struct usr_avp *avp; ++ unsigned short name_type; ++ int_str avp_name; ++ int_str avp_value; ++ struct search_state state; ++ srjson_t *jobjt; ++ memset(&state, 0, sizeof(struct search_state)); ++ ++ if(pv_get_avp_name(msg, param, &avp_name, &name_type)!=0) ++ { ++ LM_ERR("invalid name\n"); ++ return -1; ++ } ++ *jobj = srjson_CreateArray(jdoc); ++ if(*jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ if ((avp=search_first_avp(name_type, avp_name, &avp_value, &state))==0) ++ { ++ goto ok; ++ } ++ do ++ { ++ if(avp->flags & AVP_VAL_STR) ++ { ++ jobjt = srjson_CreateStr(jdoc, avp_value.s.s, avp_value.s.len); ++ if(jobjt==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ } else { ++ jobjt = srjson_CreateNumber(jdoc, avp_value.n); ++ if(jobjt==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ } ++ srjson_AddItemToArray(jdoc, *jobj, jobjt); ++ } while ((avp=search_next_avp(&state, &avp_value))!=0); ++ok: ++ item_name->s = avp_name.s.s; ++ item_name->len = avp_name.s.len; ++ return 0; ++} ++#define CFGT_XAVP_DUMP_SIZE 32 ++static str* _cfgt_xavp_dump[CFGT_XAVP_DUMP_SIZE]; ++int _cfgt_xavp_dump_lookup(pv_param_t *param) ++{ ++ unsigned int i = 0; ++ pv_xavp_name_t *xname; ++ ++ if(param==NULL) ++ return -1; ++ ++ xname = (pv_xavp_name_t*)param->pvn.u.dname; ++ ++ while(_cfgt_xavp_dump[i]!=NULL&&ilen==xname->name.len) ++ { ++ if(strncmp(_cfgt_xavp_dump[i]->s, xname->name.s, xname->name.len)==0) ++ return 1; /* already dump before */ ++ } ++ i++; ++ } ++ if(i==CFGT_XAVP_DUMP_SIZE) ++ { ++ LM_WARN("full _cfgt_xavp_dump cache array\n"); ++ return 0; /* end cache names */ ++ } ++ _cfgt_xavp_dump[i] = &xname->name; ++ return 0; ++} ++ ++void _cfgt_get_obj_xavp_val(sr_xavp_t *avp, srjson_doc_t *jdoc, srjson_t **jobj) ++{ ++ static char _pv_xavp_buf[128]; ++ int result = 0; ++ ++ switch(avp->val.type) { ++ case SR_XTYPE_NULL: ++ *jobj = srjson_CreateNull(jdoc); ++ break; ++ case SR_XTYPE_INT: ++ *jobj = srjson_CreateNumber(jdoc, avp->val.v.i); ++ break; ++ case SR_XTYPE_STR: ++ *jobj = srjson_CreateStr(jdoc, avp->val.v.s.s, avp->val.v.s.len); ++ break; ++ case SR_XTYPE_TIME: ++ result = snprintf(_pv_xavp_buf, 128, "%lu", (long unsigned)avp->val.v.t); ++ break; ++ case SR_XTYPE_LONG: ++ result = snprintf(_pv_xavp_buf, 128, "%ld", (long unsigned)avp->val.v.l); ++ break; ++ case SR_XTYPE_LLONG: ++ result = snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll); ++ break; ++ case SR_XTYPE_XAVP: ++ result = snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.xavp); ++ break; ++ case SR_XTYPE_DATA: ++ result = snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.data); ++ break; ++ default: ++ LM_WARN("unknown data type\n"); ++ *jobj = srjson_CreateNull(jdoc); ++ } ++ if(result<0) ++ { ++ LM_ERR("cannot convert to str\n"); ++ *jobj = srjson_CreateNull(jdoc); ++ } ++ else if(*jobj==NULL) ++ { ++ *jobj = srjson_CreateStr(jdoc, _pv_xavp_buf, 128); ++ } ++} ++ ++int _cfgt_get_obj_avp_vals(str name, sr_xavp_t *xavp, srjson_doc_t *jdoc, srjson_t **jobj) ++{ ++ sr_xavp_t *avp = NULL; ++ srjson_t *jobjt = NULL; ++ ++ *jobj = srjson_CreateArray(jdoc); ++ if(*jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ avp = xavp; ++ while(avp!=NULL&&!STR_EQ(avp->name,name)) ++ { ++ avp = avp->next; ++ } ++ while(avp!=NULL) ++ { ++ _cfgt_get_obj_xavp_val(avp, jdoc, &jobjt); ++ srjson_AddItemToArray(jdoc, *jobj, jobjt); ++ jobjt = NULL; ++ avp = xavp_get_next(avp); ++ } ++ ++ return 0; ++} ++ ++int _cfgt_get_obj_xavp_vals(struct sip_msg *msg, ++ pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobjr, ++ str *item_name) ++{ ++ pv_xavp_name_t *xname = (pv_xavp_name_t*)param->pvn.u.dname; ++ sr_xavp_t *xavp = NULL; ++ sr_xavp_t *avp = NULL; ++ srjson_t *jobj = NULL; ++ srjson_t *jobjt = NULL; ++ struct str_list *keys; ++ struct str_list *k; ++ ++ *jobjr = srjson_CreateArray(jdoc); ++ if(*jobjr==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ ++ item_name->s = xname->name.s; ++ item_name->len = xname->name.len; ++ xavp = xavp_get_by_index(&xname->name, 0, NULL); ++ if(xavp==NULL) ++ { ++ return 0; /* empty */ ++ } ++ ++ do ++ { ++ if(xavp->val.type==SR_XTYPE_XAVP) ++ { ++ avp = xavp->val.v.xavp; ++ jobj = srjson_CreateObject(jdoc); ++ if(jobj==NULL) ++ { ++ LM_ERR("cannot create json object\n"); ++ return -1; ++ } ++ keys = xavp_get_list_key_names(xavp); ++ if(keys!=NULL) ++ { ++ do ++ { ++ _cfgt_get_obj_avp_vals(keys->s, avp, jdoc, &jobjt); ++ srjson_AddStrItemToObject(jdoc, jobj, keys->s.s, ++ keys->s.len, jobjt); ++ k = keys; ++ keys = keys->next; ++ pkg_free(k); ++ jobjt = NULL; ++ }while(keys!=NULL); ++ } ++ } ++ if(jobj!=NULL) ++ { ++ srjson_AddItemToArray(jdoc, *jobjr, jobj); ++ jobj = NULL; ++ } ++ }while((xavp = xavp_get_next(xavp))!=0); ++ ++ return 0; ++} ++ ++int cfgt_get_json(struct sip_msg* msg, unsigned int mask, srjson_doc_t *jdoc, ++ srjson_t *head) ++{ ++ int i; ++ pv_value_t value; ++ pv_cache_t **_pv_cache = pv_cache_get_table(); ++ pv_cache_t *el = NULL; ++ srjson_t *jobj = NULL; ++ str item_name = STR_NULL; ++ static char iname[128]; ++ ++ if(_pv_cache==NULL) ++ { ++ LM_ERR("cannot access pv_cache\n"); ++ return -1; ++ } ++ if(jdoc==NULL){ ++ LM_ERR("jdoc is null\n"); ++ return -1; ++ } ++ if(head==NULL){ ++ LM_ERR("head is null\n"); ++ return -1; ++ } ++ ++ memset(_cfgt_xavp_dump, 0, sizeof(str*)*CFGT_XAVP_DUMP_SIZE); ++ for(i=0;ispec.type==PVT_AVP|| ++ el->spec.type==PVT_SCRIPTVAR|| ++ el->spec.type==PVT_XAVP|| ++ el->spec.type==PVT_OTHER)|| ++ !((el->spec.type==PVT_AVP&&mask&CFGT_DP_AVP)|| ++ (el->spec.type==PVT_XAVP&&mask&CFGT_DP_XAVP)|| ++ (el->spec.type==PVT_SCRIPTVAR&&mask&CFGT_DP_SCRIPTVAR)|| ++ (el->spec.type==PVT_OTHER&&mask&CFGT_DP_OTHER))|| ++ (el->spec.trans!=NULL)) ++ { ++ el = el->next; ++ continue; ++ } ++ jobj = NULL; ++ item_name.len = 0; ++ item_name.s = 0; ++ iname[0] = '\0'; ++ if(el->spec.type==PVT_AVP) ++ { ++ if(el->spec.pvp.pvi.type==PV_IDX_ALL|| ++ (el->spec.pvp.pvi.type==PV_IDX_INT&&el->spec.pvp.pvi.u.ival!=0)) ++ { ++ el = el->next; ++ continue; ++ } ++ else ++ { ++ if(_cfgt_get_array_avp_vals(msg, &el->spec.pvp, jdoc, &jobj, &item_name)!=0) ++ { ++ LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); ++ el = el->next; ++ continue; ++ } ++ if(srjson_GetArraySize(jdoc, jobj)==0 && !(mask&CFGT_DP_NULL)) ++ { ++ el = el->next; ++ continue; ++ } ++ snprintf(iname, 128, "$avp(%.*s)", item_name.len, item_name.s); ++ } ++ } ++ else if(el->spec.type==PVT_XAVP) ++ { ++ if(_cfgt_xavp_dump_lookup(&el->spec.pvp)!=0) ++ { ++ el = el->next; ++ continue; ++ } ++ if(_cfgt_get_obj_xavp_vals(msg, &el->spec.pvp, jdoc, &jobj, &item_name)!=0) ++ { ++ LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); ++ el = el->next; ++ continue; ++ } ++ if(srjson_GetArraySize(jdoc, jobj)==0 && !(mask&CFGT_DP_NULL)) ++ { ++ el = el->next; ++ continue; ++ } ++ snprintf(iname, 128, "$xavp(%.*s)", item_name.len, item_name.s); ++ } ++ else ++ { ++ if(pv_get_spec_value(msg, &el->spec, &value)!=0) ++ { ++ LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); ++ el = el->next; ++ continue; ++ } ++ if(value.flags&(PV_VAL_NULL|PV_VAL_EMPTY|PV_VAL_NONE)) ++ { ++ if(mask&CFGT_DP_NULL) ++ { ++ jobj = srjson_CreateNull(jdoc); ++ } ++ else ++ { ++ el = el->next; ++ continue; ++ } ++ }else if(value.flags&(PV_VAL_INT)){ ++ jobj = srjson_CreateNumber(jdoc, value.ri); ++ }else if(value.flags&(PV_VAL_STR)){ ++ jobj = srjson_CreateStr(jdoc, value.rs.s, value.rs.len); ++ }else { ++ LM_WARN("el->pvname[%.*s] value[%d] unhandled\n", el->pvname.len, el->pvname.s, ++ value.flags); ++ el = el->next; ++ continue; ++ } ++ if(jobj==NULL) ++ { ++ LM_ERR("el->pvname[%.*s] empty json object\n", el->pvname.len, ++ el->pvname.s); ++ goto error; ++ } ++ snprintf(iname, 128, "%.*s", el->pvname.len, el->pvname.s); ++ } ++ if(jobj!=NULL) ++ { ++ srjson_AddItemToObject(jdoc, head, iname, jobj); ++ } ++ el = el->next; ++ } ++ } ++ return 0; ++ ++error: ++ srjson_Delete(jdoc, head); ++ return -1; ++} +\ No newline at end of file +--- /dev/null ++++ b/modules/cfgt/cfgt_json.h +@@ -0,0 +1,38 @@ ++/** ++ * ++ * Copyright (C) 2013-2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++#ifndef _CFGT_JSON_H ++#define _CFGT_JSON_H ++ ++#include "../../lib/srutils/srjson.h" ++#include "../../route_struct.h" ++ ++#define CFGT_DP_NULL 1 ++#define CFGT_DP_AVP 2 ++#define CFGT_DP_SCRIPTVAR 4 ++#define CFGT_DP_XAVP 8 ++#define CFGT_DP_OTHER 16 ++#define CFGT_DP_ALL 31 ++ ++int cfgt_get_json(struct sip_msg* msg, unsigned int mask, srjson_doc_t *jdoc, ++ srjson_t *head); ++#endif +--- /dev/null ++++ b/modules/cfgt/cfgt_mod.c +@@ -0,0 +1,112 @@ ++/* ++ * Copyright (C) 2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * Kamailio is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * Kamailio is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * ++ */ ++ ++#include "../../events.h" ++#include "../../script_cb.h" ++#include "../../sr_module.h" ++ ++#include "cfgt_mod.h" ++#include "cfgt_int.h" ++#include "cfgt_json.h" ++#include "cfgt.h" ++ ++MODULE_VERSION ++ ++static int mod_init(void); /*!< Module initialization function */ ++static void destroy(void); /*!< Module destroy function */ ++static int child_init(int rank); /*!< Per-child init function */ ++ ++extern int bind_cfgt(cfgt_api_t* api); ++ ++/*! flag to protect against wrong initialization */ ++unsigned int init_flag = 0; ++extern int cfgt_mask; ++extern str cfgt_basedir; ++extern str cfgt_hdr_prefix; ++ ++/*! \brief ++ * Exported functions ++ */ ++static cmd_export_t cmds[] = { ++ {"cfgt_bind_cfgt", (cmd_function)bind_cfgt, 1, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0} ++}; ++ ++/*! \brief ++ * Exported parameters ++ */ ++static param_export_t params[] = { ++ {"basedir", PARAM_STR, &cfgt_basedir}, ++ {"mask", INT_PARAM, &cfgt_mask }, ++ {"callid_prefix", PARAM_STR, &cfgt_hdr_prefix }, ++ {0, 0, 0} ++}; ++ ++struct module_exports exports = { ++ "cfgt", ++ DEFAULT_DLFLAGS, /*!< dlopen flags */ ++ cmds, /*!< Exported functions */ ++ params, /*!< Export parameters */ ++ 0, /*!< exported statistics */ ++ 0, /*!< exported MI functions */ ++ 0, /*!< exported pseudo-variables */ ++ 0, /*!< extra processes */ ++ mod_init, /*!< Module initialization function */ ++ 0, /*!< Response function */ ++ destroy, /*!< Destroy function */ ++ child_init /*!< Child initialization function */ ++}; ++ ++/*! \brief ++ * Module initialization function ++ */ ++static int mod_init(void) ++{ ++ unsigned int ALL = REQUEST_CB+FAILURE_CB+ONREPLY_CB ++ +BRANCH_CB+ONSEND_CB+ERROR_CB+LOCAL_CB+EVENT_CB+BRANCH_FAILURE_CB; ++ if(cfgt_init()<0) return -1; ++ if (register_script_cb(cfgt_pre, PRE_SCRIPT_CB|ALL, 0) != 0) ++ { ++ LM_ERR("could not insert PRE_SCRIPT callback"); ++ return -1; ++ } ++ if (register_script_cb(cfgt_post, POST_SCRIPT_CB|ALL, 0) != 0) ++ { ++ LM_ERR("could not insert POST_SCRIPT callback"); ++ return -1; ++ } ++ ++ init_flag = 1; ++ return 0; ++} ++ ++static int child_init(int _rank) ++{ ++ return 0; ++} ++ ++/*! \brief ++ * Module destroy function ++ */ ++static void destroy(void) ++{ ++} +--- /dev/null ++++ b/modules/cfgt/cfgt_mod.h +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2015 Victor Seva (sipwise.com) ++ * ++ * This file is part of Kamailio, a free SIP server. ++ * ++ * Kamailio is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * Kamailio is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * ++ */ ++ ++#ifndef _CFGT_MOD_H ++#define _CFGT_MOD_H ++ ++/*! flag to protect against wrong initialization */ ++extern unsigned int init_flag; ++ ++#endif +--- a/modules/debugger/debugger_api.c ++++ b/modules/debugger/debugger_api.c +@@ -26,6 +26,7 @@ + #include + #include + ++#include "../cfgt/cfgt.h" + #include "../../dprint.h" + #include "../../events.h" + #include "../../locking.h" +@@ -70,6 +71,7 @@ + #define DBG_CFGTRACE_ON (1<<0) + #define DBG_ABKPOINT_ON (1<<1) + #define DBG_LBKPOINT_ON (1<<2) ++#define DBG_CFGTEST_ON (1<<3) + + static str _dbg_status_list[] = { + str_init("cfgtrace-on"), +@@ -78,6 +80,8 @@ + str_init("abkpoint-off"), + str_init("lbkpoint-on"), + str_init("lbkpoint-off"), ++ str_init("cfgtest-on"), ++ str_init("cfgtest-off"), + {0, 0} + }; + +@@ -89,6 +93,8 @@ + return &_dbg_status_list[2]; + if(t&DBG_LBKPOINT_ON) + return &_dbg_status_list[4]; ++ if(t&DBG_CFGTEST_ON) ++ return &_dbg_status_list[6]; + + return &_dbg_state_list[0]; + } +@@ -189,6 +195,12 @@ + int _dbg_reset_msgid = 0; + + /** ++ * disabled by default ++ */ ++int _dbg_cfgtest = 0; ++cfgt_api_t _dbg_cfgt; ++ ++/** + * + */ + typedef struct _dbg_cmd +@@ -356,6 +368,11 @@ + ); + } + } ++ if(_dbg_pid_list[process_no].set&DBG_CFGTEST_ON) ++ { ++ if(_dbg_cfgt.cfgt_process_route(msg, a)<0) ++ LM_ERR("Error processing route\n"); ++ } + if(!(_dbg_pid_list[process_no].set&DBG_ABKPOINT_ON)) + { + /* no breakpoints to be considered */ +@@ -590,6 +607,8 @@ + _dbg_pid_list[process_no].set |= DBG_ABKPOINT_ON; + if(_dbg_cfgtrace==1) + _dbg_pid_list[process_no].set |= DBG_CFGTRACE_ON; ++ if(_dbg_cfgtest==1) ++ _dbg_pid_list[process_no].set |= DBG_CFGTEST_ON; + if(_dbg_reset_msgid==1) + { + LM_DBG("[%d] create locks\n", process_no); +--- a/modules/debugger/debugger_mod.c ++++ b/modules/debugger/debugger_mod.c +@@ -27,6 +27,7 @@ + #include + #include + ++#include "../cfgt/cfgt.h" + #include "../../sr_module.h" + #include "../../dprint.h" + #include "../../ut.h" +@@ -63,6 +64,10 @@ + extern int _dbg_step_usleep; + extern int _dbg_step_loops; + extern int _dbg_reset_msgid; ++extern int _dbg_cfgtest; ++ ++/* cfgt api */ ++extern cfgt_api_t _dbg_cfgt; + + static char * _dbg_cfgtrace_facility_str = 0; + static int _dbg_log_assign = 0; +@@ -94,6 +99,7 @@ + {"mod_level", PARAM_STRING|USE_FUNC_PARAM, (void*)dbg_mod_level_param}, + {"reset_msgid", INT_PARAM, &_dbg_reset_msgid}, + {"cfgpkgcheck", INT_PARAM, &_dbg_cfgpkgcheck}, ++ {"cfgtest", INT_PARAM, &_dbg_cfgtest}, + {0, 0, 0} + }; + +@@ -119,6 +125,8 @@ + static int mod_init(void) + { + int fl; ++ bind_cfgt_t bind_cfgt; ++ + if (_dbg_cfgtrace_facility_str!=NULL) + { + fl = str2facility(_dbg_cfgtrace_facility_str); +@@ -169,6 +177,19 @@ + return -1; + } + } ++ if(_dbg_cfgtest==1) ++ { ++ bind_cfgt = (bind_cfgt_t)find_export("cfgt_bind_cfgt", 1, 0); ++ if (!bind_cfgt) { ++ LM_ERR("can't find cfgt module\n"); ++ return -1; ++ } ++ ++ if (bind_cfgt(&_dbg_cfgt) < 0) { ++ return -1; ++ } ++ LM_INFO("bind to cfgt module\n"); ++ } + return dbg_init_bp_list(); + } + diff --git a/debian/patches/sipwise/debug/mod_cfgt.patch b/debian/patches/sipwise/debug/mod_cfgt.patch new file mode 100644 index 000000000..511bf6146 --- /dev/null +++ b/debian/patches/sipwise/debug/mod_cfgt.patch @@ -0,0 +1,11 @@ +--- a/Makefile.groups ++++ b/Makefile.groups +@@ -20,7 +20,7 @@ + # - extra used modules, with no extra dependency + mod_list_extra=avp auth_diameter call_control dmq domainpolicy msrp pdb \ + qos sca seas sms sst timer tmrec uac_redirect xhttp \ +- xhttp_rpc xprint jsonrpc-s nosip usrloc_dmq statsd rtjson ++ xhttp_rpc xprint jsonrpc-s nosip usrloc_dmq statsd rtjson cfgt + + # - common modules depending on database + mod_list_db=acc alias_db auth_db avpops cfg_db db_text db_flatstore \ diff --git a/debian/patches/upstream/0001-core-clean-previous-routename-in-order-to-get-the-co.patch b/debian/patches/upstream/0001-core-clean-previous-routename-in-order-to-get-the-co.patch new file mode 100644 index 000000000..b19b036d7 --- /dev/null +++ b/debian/patches/upstream/0001-core-clean-previous-routename-in-order-to-get-the-co.patch @@ -0,0 +1,40 @@ +From 11bcc8066ce856cabfc95949b65712d891976194 Mon Sep 17 00:00:00 2001 +From: Victor Seva +Date: Mon, 29 Jun 2015 10:23:12 +0200 +Subject: [PATCH] core: clean previous routename in order to get the correct + default_routename + +fix c44685cbcefb8f6ecfa6f11369699906db832c39 +--- + cfg.y | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/cfg.y b/cfg.y +index 85e69a6..154cb44 100644 +--- a/cfg.y ++++ b/cfg.y +@@ -1778,8 +1778,8 @@ route_name: NUMBER { + ; + + +-route_main: ROUTE { ; } +- | ROUTE_REQUEST { ; } ++route_main: ROUTE { routename=NULL; } ++ | ROUTE_REQUEST { routename=NULL; } + ; + + route_stm: +@@ -1845,8 +1845,8 @@ failure_route_stm: + ; + + +-route_reply_main: ROUTE_ONREPLY { ; } +- | ROUTE_REPLY { ; } ++route_reply_main: ROUTE_ONREPLY { routename=NULL; } ++ | ROUTE_REPLY { routename=NULL; } + ; + + +-- +2.1.4 +