From 2d00e26d912b79da67ce44375c5d422582041693 Mon Sep 17 00:00:00 2001 From: Julien Chavanton Date: Tue, 31 Mar 2020 22:18:38 +0000 Subject: [PATCH] dialog: adding dlg.dump alternative command to output dialogs data to file, far much faster than dlg.list dialog: use core/srjson --- src/modules/dialog/dialog.c | 151 ++++++++++++++++++++++++ src/modules/dialog/doc/dialog_admin.xml | 18 +++ 2 files changed, 169 insertions(+) diff --git a/src/modules/dialog/dialog.c b/src/modules/dialog/dialog.c index 48bf0b1f44d..5dd941e7d0e 100644 --- a/src/modules/dialog/dialog.c +++ b/src/modules/dialog/dialog.c @@ -2196,6 +2196,118 @@ int mod_register(char *path, int *dlflags, void *p1, void *p2) } /**************************** RPC functions ******************************/ +/*! + * \brief Helper method that outputs a dialog in a file + * \see rpc_dump_file_dlg + * \param dlg printed dialog + * \param output file descriptor + * \return 0 on success, -1 on failure + */ +static inline void internal_rpc_dump_file_dlg(dlg_cell_t *dlg, FILE* dialogf) +{ + dlg_profile_link_t *pl; + dlg_var_t *var; + srjson_doc_t jdoc; + srjson_t * jdoc_caller = NULL; + srjson_t * jdoc_callee = NULL; + srjson_t * jdoc_profiles = NULL; + srjson_t * jdoc_variables = NULL; + + srjson_InitDoc(&jdoc, NULL); + jdoc.root = srjson_CreateObject(&jdoc); + if (!jdoc.root) { + LM_ERR("cannot create json\n"); + goto clear; + } + srjson_AddNumberToObject(&jdoc, jdoc.root, "h_entry", dlg->h_entry); + srjson_AddNumberToObject(&jdoc, jdoc.root, "h_id", dlg->h_id); + srjson_AddNumberToObject(&jdoc, jdoc.root, "ref", dlg->ref); + srjson_AddStrToObject(&jdoc, jdoc.root, "call_id", dlg->callid.s, dlg->callid.len); + srjson_AddStrToObject(&jdoc, jdoc.root, "from_uri", dlg->from_uri.s, dlg->from_uri.len); + srjson_AddStrToObject(&jdoc, jdoc.root, "to_uri", dlg->to_uri.s, dlg->to_uri.len); + srjson_AddNumberToObject(&jdoc, jdoc.root, "state", dlg->state); + srjson_AddNumberToObject(&jdoc, jdoc.root, "start_ts", dlg->start_ts); + srjson_AddNumberToObject(&jdoc, jdoc.root, "init_ts", dlg->init_ts); + srjson_AddNumberToObject(&jdoc, jdoc.root, "end_ts", dlg->end_ts); + srjson_AddNumberToObject(&jdoc, jdoc.root, "timeout", dlg->tl.timeout ? time(0) + dlg->tl.timeout - get_ticks() : 0); + srjson_AddNumberToObject(&jdoc, jdoc.root, "lifetime", dlg->lifetime); + srjson_AddNumberToObject(&jdoc, jdoc.root, "dflags", dlg->dflags); + srjson_AddNumberToObject(&jdoc, jdoc.root, "sflags", dlg->sflags); + srjson_AddNumberToObject(&jdoc, jdoc.root, "iflags", dlg->iflags); + + jdoc_caller = srjson_CreateObject(&jdoc); + if (!jdoc_caller) { + LM_ERR("cannot create json caller\n"); + goto clear; + } + srjson_AddStrToObject(&jdoc, jdoc_caller, "tag", dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLER_LEG].len); + srjson_AddStrToObject(&jdoc, jdoc_caller, "contact", dlg->contact[DLG_CALLER_LEG].s, dlg->contact[DLG_CALLER_LEG].len); + srjson_AddStrToObject(&jdoc, jdoc_caller, "cseq", dlg->cseq[DLG_CALLER_LEG].s, dlg->cseq[DLG_CALLER_LEG].len); + srjson_AddStrToObject(&jdoc, jdoc_caller, "route_set", dlg->route_set[DLG_CALLER_LEG].s, dlg->route_set[DLG_CALLER_LEG].len); + srjson_AddStrToObject(&jdoc, jdoc_caller, "socket", + dlg->bind_addr[DLG_CALLER_LEG] ? dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s : empty_str.s, + dlg->bind_addr[DLG_CALLER_LEG] ? dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len : empty_str.len); + srjson_AddItemToObject(&jdoc, jdoc.root, "caller", jdoc_caller); + + jdoc_callee = srjson_CreateObject(&jdoc); + if (!jdoc_callee) { + LM_ERR("cannot create json callee\n"); + goto clear; + } + srjson_AddStrToObject(&jdoc, jdoc_callee, "tag", dlg->tag[DLG_CALLEE_LEG].s, dlg->tag[DLG_CALLEE_LEG].len); + srjson_AddStrToObject(&jdoc, jdoc_callee, "contact", dlg->contact[DLG_CALLEE_LEG].s, dlg->contact[DLG_CALLEE_LEG].len); + srjson_AddStrToObject(&jdoc, jdoc_callee, "cseq", dlg->cseq[DLG_CALLEE_LEG].s, dlg->cseq[DLG_CALLEE_LEG].len); + srjson_AddStrToObject(&jdoc, jdoc_callee, "route_set", dlg->route_set[DLG_CALLEE_LEG].s, dlg->route_set[DLG_CALLEE_LEG].len); + srjson_AddStrToObject(&jdoc, jdoc_callee, "socket", + dlg->bind_addr[DLG_CALLEE_LEG] ? dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s : empty_str.s, + dlg->bind_addr[DLG_CALLEE_LEG] ? dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len : empty_str.len); + srjson_AddItemToObject(&jdoc, jdoc.root, "callee", jdoc_callee); + + // profiles section + jdoc_profiles = srjson_CreateObject(&jdoc); + if (!jdoc_profiles) { + LM_ERR("cannot create json profiles\n"); + goto clear; + } + for (pl = dlg->profile_links ; pl && (dlg->statenext) { + if (pl->profile->has_value) { + srjson_AddStrToObject(&jdoc, jdoc_profiles, pl->profile->name.s, pl->hash_linker.value.s, pl->hash_linker.value.len); + } else { + srjson_AddStrToObject(&jdoc, jdoc_profiles, pl->profile->name.s, empty_str.s, empty_str.len); + } + } + srjson_AddItemToObject(&jdoc, jdoc.root, "profiles", jdoc_profiles); + + // variables section + jdoc_variables = srjson_CreateObject(&jdoc); + if (!jdoc_variables) { + LM_ERR("cannot create json variables\n"); + goto clear; + } + for (var=dlg->vars ; var && (dlg->statenext) { + srjson_AddStrToObject(&jdoc, jdoc_variables, var->key.s, var->value.s, var->value.len); + } + srjson_AddItemToObject(&jdoc, jdoc.root, "variables", jdoc_variables); + + // serialize and print to file + jdoc.buf.s = srjson_PrintUnformatted(&jdoc, jdoc.root); + if (!jdoc.buf.s) { + LM_ERR("unable to serialize data\n"); + goto clear; + } + jdoc.buf.len = strlen(jdoc.buf.s); + LM_DBG("sending serialized data %.*s\n", jdoc.buf.len, jdoc.buf.s); + fprintf(dialogf,"%s\n", jdoc.buf.s); + +clear: + if (jdoc.buf.s) { + jdoc.free_fn(jdoc.buf.s); + jdoc.buf.s = NULL; + } + srjson_DestroyDoc(&jdoc); + return; +} + /*! * \brief Helper method that outputs a dialog via the RPC interface * \see rpc_print_dlg @@ -2276,6 +2388,38 @@ static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, dlg_cell_t *dlg, return; } +/*! + * \brief Helper function that outputs all dialogs via the RPC interface + * \see rpc_dump_file_dlgs + * \param rpc RPC node that should be filled + * \param c RPC void pointer + * \param with_context if 1 then the dialog context will be also printed + */ +static void internal_rpc_dump_file_dlgs(rpc_t *rpc, void *c, int with_context) +{ + dlg_cell_t *dlg; + str output_file_name; + FILE* dialogf; + unsigned int i; + if (rpc->scan(c, ".S", &output_file_name) < 1) return; + + dialogf = fopen(output_file_name.s, "a+"); + if (!dialogf) { + LM_ERR("failed to open output file: %s\n", output_file_name.s); + return; + } + + for( i=0 ; isize ; i++ ) { + dlg_lock( d_table, &(d_table->entries[i]) ); + + for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) { + internal_rpc_dump_file_dlg(dlg, dialogf); + } + dlg_unlock( d_table, &(d_table->entries[i]) ); + } + fclose(dialogf); +} + /*! * \brief Helper function that outputs all dialogs via the RPC interface * \see rpc_print_dlgs @@ -2415,6 +2559,9 @@ static int w_dlg_set_ruri(sip_msg_t *msg, char *p1, char *p2) static const char *rpc_print_dlgs_doc[2] = { "Print all dialogs", 0 }; +static const char *rpc_dump_file_dlgs_doc[2] = { + "Print all dialogs to json file", 0 +}; static const char *rpc_print_dlgs_ctx_doc[2] = { "Print all dialogs with associated context", 0 }; @@ -2459,6 +2606,9 @@ static const char *rpc_dlg_is_alive_doc[2] = { static void rpc_print_dlgs(rpc_t *rpc, void *c) { internal_rpc_print_dlgs(rpc, c, 0); } +static void rpc_dump_file_dlgs(rpc_t *rpc, void *c) { + internal_rpc_dump_file_dlgs(rpc, c, 0); +} static void rpc_print_dlgs_ctx(rpc_t *rpc, void *c) { internal_rpc_print_dlgs(rpc, c, 1); } @@ -2946,6 +3096,7 @@ static void rpc_dlg_briefing(rpc_t *rpc, void *c) static rpc_export_t rpc_methods[] = { {"dlg.briefing", rpc_dlg_briefing, rpc_dlg_briefing_doc, RET_ARRAY}, {"dlg.list", rpc_print_dlgs, rpc_print_dlgs_doc, RET_ARRAY}, + {"dlg.dump_file", rpc_dump_file_dlgs, rpc_dump_file_dlgs_doc, 0}, {"dlg.list_ctx", rpc_print_dlgs_ctx, rpc_print_dlgs_ctx_doc, RET_ARRAY}, {"dlg.list_match", rpc_dlg_list_match, rpc_dlg_list_match_doc, RET_ARRAY}, {"dlg.list_match_ctx", rpc_dlg_list_match_ctx, rpc_dlg_list_match_ctx_doc, RET_ARRAY}, diff --git a/src/modules/dialog/doc/dialog_admin.xml b/src/modules/dialog/doc/dialog_admin.xml index 975c0213850..aeae7da4548 100644 --- a/src/modules/dialog/doc/dialog_admin.xml +++ b/src/modules/dialog/doc/dialog_admin.xml @@ -2537,6 +2537,24 @@ dlg_reset_property("timeout-noreset"); +
+ dlg.dump_file + Dump all dialogs in a json file. (much faster than dlg.list) + Name: dlg.dump_file + Parameters: + + + file name output file name + + + RPC Command Format: + +... +&kamcmd; dlg.dump_file "/tmp/dlg.json" +... + +
+
dlg.dlg_list