You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules/debugger/debugger_json.c

424 lines
9.5 KiB

/**
*
* 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 <stdio.h>
#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(i<DBG_XAVP_DUMP_SIZE && _dbg_xavp_dump[i]!=NULL)
{
if(_dbg_xavp_dump[i]->len==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, "<<xavp:%p>>", avp->val.v.xavp);
break;
case SR_XTYPE_DATA:
result = snprintf(_pv_xavp_buf, 128, "<<data:%p>>", 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;i<PV_CACHE_SIZE;i++)
{
el = _pv_cache[i];
while(el)
{
if(!(el->spec.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;
}