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