modules/debugger: add dbg_pv_dump config function.
authorVictor Seva <linuxmaniac@torreviejawireless.org>
Sun, 7 Jul 2013 05:23:11 +0000 (07:23 +0200)
committerVictor Seva <linuxmaniac@torreviejawireless.org>
Sun, 7 Jul 2013 05:23:11 +0000 (07:23 +0200)
It dumps the content of pv_cache on json format.

modules/debugger/Makefile
modules/debugger/debugger_api.c
modules/debugger/debugger_api.h
modules/debugger/debugger_mod.c

index 579bcde..a87111c 100644 (file)
@@ -9,4 +9,6 @@ LIBS=
 
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
 include ../../Makefile.modules
index f0dbdce..d3f64e4 100644 (file)
@@ -38,6 +38,9 @@
 #include "../../locking.h"
 #include "../../lvalue.h"
 #include "../../hashes.h"
+#include "../../lib/srutils/srjson.h"
+#include "../../xavp.h"
+#include "../pv/pv_xavp.h"
 
 #include "debugger_act.h"
 #include "debugger_api.h"
@@ -1280,3 +1283,376 @@ int dbg_level_mode_fixup(void *temp_handle,
        }
        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&&i<DBG_XAVP_DUMP_SIZE)
+       {
+               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_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;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, 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;
+}
index 54d5c59..be20098 100644 (file)
@@ -39,5 +39,13 @@ void dbg_enable_mod_levels(void);
 
 int dbg_init_pvcache(void);
 void dbg_enable_log_assign(void);
+
+#define DBG_DP_NULL                    1
+#define DBG_DP_AVP                     2
+#define DBG_DP_SCRIPTVAR       4
+#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
 
index f048b0d..cef4617 100644 (file)
@@ -47,6 +47,9 @@ static int w_dbg_breakpoint(struct sip_msg* msg, char* point, char* str2);
 static int fixup_dbg_breakpoint(void** param, int param_no);
 static int dbg_mod_level_param(modparam_t type, void *val);
 
+static int fixup_dbg_pv_dump(void** param, int param_no);
+static int w_dbg_dump(struct sip_msg* msg, char* mask, char* level);
+
 /* parameters */
 extern int _dbg_cfgtrace;
 extern int _dbg_breakpoint;
@@ -62,6 +65,12 @@ static int _dbg_log_assign = 0;
 static cmd_export_t cmds[]={
        {"dbg_breakpoint", (cmd_function)w_dbg_breakpoint, 1,
                fixup_dbg_breakpoint, 0, ANY_ROUTE},
+       {"dbg_pv_dump", (cmd_function)w_dbg_dump, 0,
+               fixup_dbg_pv_dump, 0, ANY_ROUTE},
+       {"dbg_pv_dump", (cmd_function)w_dbg_dump, 1,
+               fixup_dbg_pv_dump, 0, ANY_ROUTE},
+       {"dbg_pv_dump", (cmd_function)w_dbg_dump, 2,
+               fixup_dbg_pv_dump, 0, ANY_ROUTE},
        {0, 0, 0, 0, 0, 0}
 };
 
@@ -176,6 +185,64 @@ static int w_dbg_breakpoint(struct sip_msg* msg, char* point, char* str2)
 }
 
 /**
+ * fixup for cfg dbg_pv_dump
+ */
+static int fixup_dbg_pv_dump(void** param, int param_no)
+{
+       unsigned int mask;
+       int level;
+       str s = STR_NULL;
+
+       switch(param_no)
+       {
+               case 2:
+                       switch(((char*)(*param))[2])
+                       {
+                               case 'A': level = L_ALERT; break;
+                               case 'B': level = L_BUG; break;
+                               case 'C': level = L_CRIT2; break;
+                               case 'E': level = L_ERR; break;
+                               case 'W': level = L_WARN; break;
+                               case 'N': level = L_NOTICE; break;
+                               case 'I': level = L_INFO; break;
+                               case 'D': level = L_DBG; break;
+                               default:
+                                       LM_ERR("unknown log level\n");
+                                       return E_UNSPEC;
+                       }
+                       *param = (void*)(long)level;
+               break;
+               case 1:
+                       s.s = *param;
+                       s.len = strlen(s.s);
+                       if(str2int(&s, &mask) == 0) {
+                               *param = (void*)(long)mask;
+                       }
+                       else return E_UNSPEC;
+               break;
+       }
+
+    return 0;
+}
+
+/**
+ * dump pv_cache contents as json
+ */
+static int w_dbg_dump(struct sip_msg* msg, char* mask, char* level)
+{
+       unsigned int umask = DBG_DP_ALL;
+       int ilevel = L_DBG;
+       if(level!=NULL){
+               ilevel = (int)(long)level;
+       }
+       if(mask!=NULL){
+               umask = (unsigned int)(unsigned long)mask;
+       }
+       dbg_dump_json(msg, umask, ilevel);
+       return 1;
+}
+
+/**
  * get the pointer to action structure
  */
 static struct action *dbg_fixup_get_action(void **param, int param_no)