6650491075f12c0120c38cb4edb029fbb6a3b1b1
[metze/wireshark/wip.git] / ui / cli / tap-rpcprogs.c
1 /* tap-rpcprogs.c
2  * rpcstat   2002 Ronnie Sahlberg
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0+*/
9
10 /* This module provides rpc call/reply SRT statistics to tshark.
11  * It is only used by tshark and not wireshark
12  */
13
14 #include "config.h"
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <glib.h>
21
22 #include <epan/packet_info.h>
23 #include <epan/tap.h>
24 #include <epan/stat_tap_ui.h>
25 #include <epan/dissectors/packet-rpc.h>
26
27 #define MICROSECS_PER_SEC   1000000
28 #define NANOSECS_PER_SEC    1000000000
29
30 void register_tap_listener_rpcprogs(void);
31
32 /* used to keep track of statistics for a specific program/version */
33 typedef struct _rpc_program_t {
34         struct _rpc_program_t *next;
35         guint32 program;
36         guint32 version;
37         int num;
38         nstime_t min;
39         nstime_t max;
40         nstime_t tot;
41 } rpc_program_t;
42
43 static rpc_program_t *prog_list = NULL;
44 static int already_enabled = 0;
45
46 static int
47 rpcprogs_packet(void *dummy1 _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
48 {
49         const rpc_call_info_value *ri = (const rpc_call_info_value *)pri;
50         nstime_t delta;
51         rpc_program_t *rp = NULL;
52
53         if (!prog_list) {
54                 /* the list was empty */
55                 rp = g_new(rpc_program_t, 1);
56                 rp->next      = NULL;
57                 rp->program   = ri->prog;
58                 rp->version   = ri->vers;
59                 rp->num       = 0;
60                 rp->min.secs  = 0;
61                 rp->min.nsecs = 0;
62                 rp->max.secs  = 0;
63                 rp->max.nsecs = 0;
64                 rp->tot.secs  = 0;
65                 rp->tot.nsecs = 0;
66                 prog_list = rp;
67         } else if ((ri->prog == prog_list->program)
68                 && (ri->vers == prog_list->version)) {
69                 rp = prog_list;
70         } else if ( (ri->prog < prog_list->program)
71                 || ((ri->prog == prog_list->program) && (ri->vers < prog_list->version))) {
72                 /* we should be first entry in list */
73                 rp = g_new(rpc_program_t, 1);
74                 rp->next      = prog_list;
75                 rp->program   = ri->prog;
76                 rp->version   = ri->vers;
77                 rp->num       = 0;
78                 rp->min.secs  = 0;
79                 rp->min.nsecs = 0;
80                 rp->max.secs  = 0;
81                 rp->max.nsecs = 0;
82                 rp->tot.secs  = 0;
83                 rp->tot.nsecs = 0;
84                 prog_list = rp;
85         } else {
86                 /* we go somewhere else in the list */
87                 for (rp=prog_list; rp; rp=rp->next) {
88                         if ((rp->next)
89                          && (rp->next->program == ri->prog)
90                          && (rp->next->version == ri->vers)) {
91                                 rp = rp->next;
92                                 break;
93                         }
94                         if ((!rp->next)
95                          || (rp->next->program > ri->prog)
96                          || (   (rp->next->program == ri->prog)
97                              && (rp->next->version > ri->vers))) {
98                                 rpc_program_t *trp;
99                                 trp = g_new(rpc_program_t, 1);
100                                 trp->next      = rp->next;
101                                 trp->program   = ri->prog;
102                                 trp->version   = ri->vers;
103                                 trp->num       = 0;
104                                 trp->min.secs  = 0;
105                                 trp->min.nsecs = 0;
106                                 trp->max.secs  = 0;
107                                 trp->max.nsecs = 0;
108                                 trp->tot.secs  = 0;
109                                 trp->tot.nsecs = 0;
110                                 rp->next       = trp;
111                                 rp = trp;
112                                 break;
113                         }
114                 }
115         }
116
117
118         /* we are only interested in reply packets */
119         if (ri->request || !rp) {
120                 return 0;
121         }
122
123         /* calculate time delta between request and reply */
124         nstime_delta(&delta, &pinfo->abs_ts, &ri->req_time);
125
126         if ((rp->max.secs == 0)
127          && (rp->max.nsecs == 0) ) {
128                 rp->max.secs  = delta.secs;
129                 rp->max.nsecs = delta.nsecs;
130         }
131
132         if ((rp->min.secs == 0)
133          && (rp->min.nsecs == 0) ) {
134                 rp->min.secs  = delta.secs;
135                 rp->min.nsecs = delta.nsecs;
136         }
137
138         if ( (delta.secs < rp->min.secs)
139         || ( (delta.secs == rp->min.secs)
140           && (delta.nsecs < rp->min.nsecs) ) ) {
141                 rp->min.secs  = delta.secs;
142                 rp->min.nsecs = delta.nsecs;
143         }
144
145         if ( (delta.secs > rp->max.secs)
146         || ( (delta.secs == rp->max.secs)
147           && (delta.nsecs > rp->max.nsecs) ) ) {
148                 rp->max.secs  = delta.secs;
149                 rp->max.nsecs = delta.nsecs;
150         }
151
152         rp->tot.secs  += delta.secs;
153         rp->tot.nsecs += delta.nsecs;
154         if (rp->tot.nsecs > NANOSECS_PER_SEC) {
155                 rp->tot.nsecs -= NANOSECS_PER_SEC;
156                 rp->tot.secs++;
157         }
158         rp->num++;
159
160         return 1;
161 }
162
163
164 static void
165 rpcprogs_draw(void *dummy _U_)
166 {
167         guint64 td;
168         rpc_program_t *rp;
169         char str[64];
170
171         printf("\n");
172         printf("==========================================================\n");
173         printf("ONC-RPC Program Statistics:\n");
174         printf("Program    Version  Calls    Min SRT    Max SRT    Avg SRT\n");
175         for (rp = prog_list;rp;rp = rp->next) {
176                 /* Only display procs with non-zero calls */
177                 if (rp->num == 0) {
178                         continue;
179                 }
180                 /* Scale the average SRT in units of 1us and round to the nearest us. */
181                 td = ((guint64)(rp->tot.secs)) * NANOSECS_PER_SEC + rp->tot.nsecs;
182                 td = ((td / rp->num) + 500) / 1000;
183
184                 g_snprintf(str, sizeof(str), "%s(%d)", rpc_prog_name(rp->program), rp->program);
185                 printf("%-15s %2u %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
186                        str,
187                        rp->version,
188                        rp->num,
189                        (int)(rp->min.secs), (rp->min.nsecs+500)/1000,
190                        (int)(rp->max.secs), (rp->max.nsecs+500)/1000,
191                        td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
192                 );
193         }
194         printf("===================================================================\n");
195 }
196
197
198 static void
199 rpcprogs_init(const char *opt_arg _U_, void *userdata _U_)
200 {
201         GString *error_string;
202
203         if (already_enabled) {
204                 return;
205         }
206         already_enabled = 1;
207
208         error_string = register_tap_listener("rpc", NULL, NULL, 0, NULL, rpcprogs_packet, rpcprogs_draw);
209         if (error_string) {
210                 fprintf(stderr, "tshark: Couldn't register rpc,programs tap: %s\n",
211                         error_string->str);
212                 g_string_free(error_string, TRUE);
213                 exit(1);
214         }
215 }
216
217 static stat_tap_ui rpcprogs_ui = {
218         REGISTER_STAT_GROUP_GENERIC,
219         NULL,
220         "rpc,programs",
221         rpcprogs_init,
222         0,
223         NULL
224 };
225
226 void
227 register_tap_listener_rpcprogs(void)
228 {
229         register_stat_tap_ui(&rpcprogs_ui, NULL);
230 }
231
232 /*
233  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
234  *
235  * Local variables:
236  * c-basic-offset: 8
237  * tab-width: 8
238  * indent-tabs-mode: t
239  * End:
240  *
241  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
242  * :indentSize=8:tabSize=8:noTabs=false:
243  */