ee2c9e7b776dcb26925014da7342f84361f6e78f
[jlayton/wireshark.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  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /* This module provides rpc call/reply SRT statistics to tshark.
24  * It is only used by tshark and not wireshark
25  */
26
27 #include "config.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <glib.h>
34
35 #include <epan/packet_info.h>
36 #include <epan/tap.h>
37 #include <epan/stat_tap_ui.h>
38 #include <epan/dissectors/packet-rpc.h>
39
40 #define MICROSECS_PER_SEC   1000000
41 #define NANOSECS_PER_SEC    1000000000
42
43 void register_tap_listener_rpcprogs(void);
44
45 /* used to keep track of statistics for a specific program/version */
46 typedef struct _rpc_program_t {
47         struct _rpc_program_t *next;
48         guint32 program;
49         guint32 version;
50         int num;
51         nstime_t min;
52         nstime_t max;
53         nstime_t tot;
54 } rpc_program_t;
55
56 static rpc_program_t *prog_list = NULL;
57 static int already_enabled = 0;
58
59 static int
60 rpcprogs_packet(void *dummy1 _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
61 {
62         const rpc_call_info_value *ri = (const rpc_call_info_value *)pri;
63         nstime_t delta;
64         rpc_program_t *rp = NULL;
65
66         if (!prog_list) {
67                 /* the list was empty */
68                 rp = g_new(rpc_program_t, 1);
69                 rp->next      = NULL;
70                 rp->program   = ri->prog;
71                 rp->version   = ri->vers;
72                 rp->num       = 0;
73                 rp->min.secs  = 0;
74                 rp->min.nsecs = 0;
75                 rp->max.secs  = 0;
76                 rp->max.nsecs = 0;
77                 rp->tot.secs  = 0;
78                 rp->tot.nsecs = 0;
79                 prog_list = rp;
80         } else if ((ri->prog == prog_list->program)
81                 && (ri->vers == prog_list->version)) {
82                 rp = prog_list;
83         } else if ( (ri->prog < prog_list->program)
84                 || ((ri->prog == prog_list->program) && (ri->vers < prog_list->version))) {
85                 /* we should be first entry in list */
86                 rp = g_new(rpc_program_t, 1);
87                 rp->next      = prog_list;
88                 rp->program   = ri->prog;
89                 rp->version   = ri->vers;
90                 rp->num       = 0;
91                 rp->min.secs  = 0;
92                 rp->min.nsecs = 0;
93                 rp->max.secs  = 0;
94                 rp->max.nsecs = 0;
95                 rp->tot.secs  = 0;
96                 rp->tot.nsecs = 0;
97                 prog_list = rp;
98         } else {
99                 /* we go somewhere else in the list */
100                 for (rp=prog_list; rp; rp=rp->next) {
101                         if ((rp->next)
102                          && (rp->next->program == ri->prog)
103                          && (rp->next->version == ri->vers)) {
104                                 rp = rp->next;
105                                 break;
106                         }
107                         if ((!rp->next)
108                          || (rp->next->program > ri->prog)
109                          || (   (rp->next->program == ri->prog)
110                              && (rp->next->version > ri->vers))) {
111                                 rpc_program_t *trp;
112                                 trp = g_new(rpc_program_t, 1);
113                                 trp->next      = rp->next;
114                                 trp->program   = ri->prog;
115                                 trp->version   = ri->vers;
116                                 trp->num       = 0;
117                                 trp->min.secs  = 0;
118                                 trp->min.nsecs = 0;
119                                 trp->max.secs  = 0;
120                                 trp->max.nsecs = 0;
121                                 trp->tot.secs  = 0;
122                                 trp->tot.nsecs = 0;
123                                 rp->next       = trp;
124                                 rp = trp;
125                                 break;
126                         }
127                 }
128         }
129
130
131         /* we are only interested in reply packets */
132         if (ri->request || !rp) {
133                 return 0;
134         }
135
136         /* calculate time delta between request and reply */
137         nstime_delta(&delta, &pinfo->abs_ts, &ri->req_time);
138
139         if ((rp->max.secs == 0)
140          && (rp->max.nsecs == 0) ) {
141                 rp->max.secs  = delta.secs;
142                 rp->max.nsecs = delta.nsecs;
143         }
144
145         if ((rp->min.secs == 0)
146          && (rp->min.nsecs == 0) ) {
147                 rp->min.secs  = delta.secs;
148                 rp->min.nsecs = delta.nsecs;
149         }
150
151         if ( (delta.secs < rp->min.secs)
152         || ( (delta.secs == rp->min.secs)
153           && (delta.nsecs < rp->min.nsecs) ) ) {
154                 rp->min.secs  = delta.secs;
155                 rp->min.nsecs = delta.nsecs;
156         }
157
158         if ( (delta.secs > rp->max.secs)
159         || ( (delta.secs == rp->max.secs)
160           && (delta.nsecs > rp->max.nsecs) ) ) {
161                 rp->max.secs  = delta.secs;
162                 rp->max.nsecs = delta.nsecs;
163         }
164
165         rp->tot.secs  += delta.secs;
166         rp->tot.nsecs += delta.nsecs;
167         if (rp->tot.nsecs > NANOSECS_PER_SEC) {
168                 rp->tot.nsecs -= NANOSECS_PER_SEC;
169                 rp->tot.secs++;
170         }
171         rp->num++;
172
173         return 1;
174 }
175
176
177 static void
178 rpcprogs_draw(void *dummy _U_)
179 {
180         guint64 td;
181         rpc_program_t *rp;
182         char str[64];
183
184         printf("\n");
185         printf("==========================================================\n");
186         printf("ONC-RPC Program Statistics:\n");
187         printf("Program    Version  Calls    Min SRT    Max SRT    Avg SRT\n");
188         for (rp = prog_list;rp;rp = rp->next) {
189                 /* Only display procs with non-zero calls */
190                 if (rp->num == 0) {
191                         continue;
192                 }
193                 /* Scale the average SRT in units of 1us and round to the nearest us. */
194                 td = ((guint64)(rp->tot.secs)) * NANOSECS_PER_SEC + rp->tot.nsecs;
195                 td = ((td / rp->num) + 500) / 1000;
196
197                 g_snprintf(str, sizeof(str), "%s(%d)", rpc_prog_name(rp->program), rp->program);
198                 printf("%-15s %2u %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
199                        str,
200                        rp->version,
201                        rp->num,
202                        (int)(rp->min.secs), (rp->min.nsecs+500)/1000,
203                        (int)(rp->max.secs), (rp->max.nsecs+500)/1000,
204                        td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
205                 );
206         }
207         printf("===================================================================\n");
208 }
209
210
211 static void
212 rpcprogs_init(const char *opt_arg _U_, void *userdata _U_)
213 {
214         gchar *error_string;
215
216         if (already_enabled) {
217                 return;
218         }
219         already_enabled = 1;
220
221         error_string = register_tap_listener("rpc", NULL, NULL, 0, NULL, rpcprogs_packet, rpcprogs_draw);
222         if (error_string) {
223                 fprintf(stderr, "tshark: Couldn't register rpc,programs tap: %s\n",
224                         error_string);
225                 wmem_free(NULL, error_string);
226                 exit(1);
227         }
228 }
229
230 static stat_tap_ui rpcprogs_ui = {
231         REGISTER_STAT_GROUP_GENERIC,
232         NULL,
233         "rpc,programs",
234         rpcprogs_init,
235         0,
236         NULL
237 };
238
239 void
240 register_tap_listener_rpcprogs(void)
241 {
242         register_stat_tap_ui(&rpcprogs_ui, NULL);
243 }
244
245 /*
246  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
247  *
248  * Local variables:
249  * c-basic-offset: 8
250  * tab-width: 8
251  * indent-tabs-mode: t
252  * End:
253  *
254  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
255  * :indentSize=8:tabSize=8:noTabs=false:
256  */