wireshark/ui/cli/tap-rpcprogs.c

247 lines
5.8 KiB
C
Raw Normal View History

/* 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>
2023-02-06 22:46:45 +00:00
#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:
*/