diff options
Diffstat (limited to '')
-rw-r--r-- | ui/cli/tap-rpcprogs.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/ui/cli/tap-rpcprogs.c b/ui/cli/tap-rpcprogs.c new file mode 100644 index 0000000..e64c93b --- /dev/null +++ b/ui/cli/tap-rpcprogs.c @@ -0,0 +1,246 @@ +/* tap-rpcprogs.c + * rpcstat 2002 Ronnie Sahlberg + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* This module provides rpc call/reply SRT statistics to tshark. + * It is only used by tshark and not wireshark + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> + +#include <epan/packet_info.h> +#include <epan/tap.h> +#include <epan/stat_tap_ui.h> +#include <epan/dissectors/packet-rpc.h> + +#include <wsutil/cmdarg_err.h> + +#define MICROSECS_PER_SEC 1000000 +#define NANOSECS_PER_SEC 1000000000 + +void register_tap_listener_rpcprogs(void); + +/* used to keep track of statistics for a specific program/version */ +typedef struct _rpc_program_t { + struct _rpc_program_t *next; + guint32 program; + guint32 version; + int num; + nstime_t min; + nstime_t max; + nstime_t tot; +} rpc_program_t; + +static rpc_program_t *prog_list = NULL; +static int already_enabled = 0; + +static tap_packet_status +rpcprogs_packet(void *dummy1 _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri, tap_flags_t flags _U_) +{ + const rpc_call_info_value *ri = (const rpc_call_info_value *)pri; + nstime_t delta; + rpc_program_t *rp = NULL; + + if (!prog_list) { + /* the list was empty */ + rp = g_new(rpc_program_t, 1); + rp->next = NULL; + rp->program = ri->prog; + rp->version = ri->vers; + rp->num = 0; + rp->min.secs = 0; + rp->min.nsecs = 0; + rp->max.secs = 0; + rp->max.nsecs = 0; + rp->tot.secs = 0; + rp->tot.nsecs = 0; + prog_list = rp; + } else if ((ri->prog == prog_list->program) + && (ri->vers == prog_list->version)) { + rp = prog_list; + } else if ( (ri->prog < prog_list->program) + || ((ri->prog == prog_list->program) && (ri->vers < prog_list->version))) { + /* we should be first entry in list */ + rp = g_new(rpc_program_t, 1); + rp->next = prog_list; + rp->program = ri->prog; + rp->version = ri->vers; + rp->num = 0; + rp->min.secs = 0; + rp->min.nsecs = 0; + rp->max.secs = 0; + rp->max.nsecs = 0; + rp->tot.secs = 0; + rp->tot.nsecs = 0; + prog_list = rp; + } else { + /* we go somewhere else in the list */ + for (rp=prog_list; rp; rp=rp->next) { + if ((rp->next) + && (rp->next->program == ri->prog) + && (rp->next->version == ri->vers)) { + rp = rp->next; + break; + } + if ((!rp->next) + || (rp->next->program > ri->prog) + || ( (rp->next->program == ri->prog) + && (rp->next->version > ri->vers))) { + rpc_program_t *trp; + trp = g_new(rpc_program_t, 1); + trp->next = rp->next; + trp->program = ri->prog; + trp->version = ri->vers; + trp->num = 0; + trp->min.secs = 0; + trp->min.nsecs = 0; + trp->max.secs = 0; + trp->max.nsecs = 0; + trp->tot.secs = 0; + trp->tot.nsecs = 0; + rp->next = trp; + rp = trp; + break; + } + } + } + + + /* we are only interested in reply packets */ + if (ri->request || !rp) { + return TAP_PACKET_DONT_REDRAW; + } + + /* calculate time delta between request and reply */ + nstime_delta(&delta, &pinfo->abs_ts, &ri->req_time); + + if ((rp->max.secs == 0) + && (rp->max.nsecs == 0) ) { + rp->max.secs = delta.secs; + rp->max.nsecs = delta.nsecs; + } + + if ((rp->min.secs == 0) + && (rp->min.nsecs == 0) ) { + rp->min.secs = delta.secs; + rp->min.nsecs = delta.nsecs; + } + + if ( (delta.secs < rp->min.secs) + || ( (delta.secs == rp->min.secs) + && (delta.nsecs < rp->min.nsecs) ) ) { + rp->min.secs = delta.secs; + rp->min.nsecs = delta.nsecs; + } + + if ( (delta.secs > rp->max.secs) + || ( (delta.secs == rp->max.secs) + && (delta.nsecs > rp->max.nsecs) ) ) { + rp->max.secs = delta.secs; + rp->max.nsecs = delta.nsecs; + } + + rp->tot.secs += delta.secs; + rp->tot.nsecs += delta.nsecs; + if (rp->tot.nsecs > NANOSECS_PER_SEC) { + rp->tot.nsecs -= NANOSECS_PER_SEC; + rp->tot.secs++; + } + rp->num++; + + return TAP_PACKET_REDRAW; +} + + +static void +rpcprogs_draw(void *dummy _U_) +{ + guint64 td; + rpc_program_t *rp; + char str[64]; + + printf("\n"); + printf("==========================================================\n"); + printf("ONC-RPC Program Statistics:\n"); + printf("Program Version Calls Min SRT Max SRT Avg SRT\n"); + for (rp = prog_list;rp;rp = rp->next) { + /* Only display procs with non-zero calls */ + if (rp->num == 0) { + continue; + } + /* Scale the average SRT in units of 1us and round to the nearest us. */ + td = ((guint64)(rp->tot.secs)) * NANOSECS_PER_SEC + rp->tot.nsecs; + td = ((td / rp->num) + 500) / 1000; + + snprintf(str, sizeof(str), "%s(%d)", rpc_prog_name(rp->program), rp->program); + printf("%-15s %2u %6d %3d.%06d %3d.%06d %3" PRIu64 ".%06" PRIu64 "\n", + str, + rp->version, + rp->num, + (int)(rp->min.secs), (rp->min.nsecs+500)/1000, + (int)(rp->max.secs), (rp->max.nsecs+500)/1000, + td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC + ); + } + printf("===================================================================\n"); +} + + +static void +rpcprogs_init(const char *opt_arg _U_, void *userdata _U_) +{ + GString *error_string; + + if (already_enabled) { + return; + } + already_enabled = 1; + + error_string = register_tap_listener("rpc", NULL, NULL, 0, NULL, rpcprogs_packet, rpcprogs_draw, NULL); + if (error_string) { + cmdarg_err("Couldn't register rpc,programs tap: %s", + error_string->str); + g_string_free(error_string, TRUE); + exit(1); + } +} + +static stat_tap_ui rpcprogs_ui = { + REGISTER_STAT_GROUP_GENERIC, + NULL, + "rpc,programs", + rpcprogs_init, + 0, + NULL +}; + +void +register_tap_listener_rpcprogs(void) +{ + register_stat_tap_ui(&rpcprogs_ui, NULL); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ |