Allow taps to have menu item registration routines; the menu item
[obnox/wireshark/wip.git] / tap-iostat.c
1 /* tap-iostat.c
2  * iostat   2002 Ronnie Sahlberg
3  *
4  * $Id: tap-iostat.c,v 1.5 2003/04/23 03:50:59 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <string.h>
36 #include "epan/packet_info.h"
37 #include "tap.h"
38 #include "register.h"
39
40
41 typedef struct _io_stat_t {
42         gint32 interval;        /* unit is ms */
43         guint32 num_items;
44         struct _io_stat_item_t *items;
45         char **filters;
46 } io_stat_t;    
47
48 typedef struct _io_stat_item_t {
49         io_stat_t *parent;
50         struct _io_stat_item_t *next;
51         struct _io_stat_item_t *prev;
52         gint32 time;            /* unit is ms since start of capture */
53         guint32 frames;
54         guint32 bytes;
55 } io_stat_item_t;
56
57 #ifdef REMOVED
58 /* Tethereal does not use the reset callback.
59    But if someone ports this feature to Gtk with a nice gui, this is what
60    reset should look like.
61 */
62 static void
63 iostat_reset(io_stat_item_t *mit)
64 {
65         io_stat_item_t *it;
66
67         mit->prev=mit;
68         mit->time=0;
69         mit->frames=0;
70         mit->bytes=0;
71         while(mit->next){
72                 it=mit->next;
73                 mit=mit->next->next;
74                 g_free(it);
75         }
76 }
77
78 /* function to remove and clean up an io stat. would be used by Gtk/Gtk2 version
79    io iostat when the iostat window is closed.
80 */
81 static void 
82 iostat_cleanup(io_stat_t *io)
83 {
84         int i;
85
86         for(i=0;i<io->num_items;i++){
87                 if(filters[i]){
88                         g_free(filters[i]);
89                         filters[i]=NULL;
90                 }
91                 iostat_reset(&io->items[i]);
92                 remove_tap_listener(&io->items[i]);
93         }
94         g_free(io->items);
95         g_free(io->filters);
96         g_free(io);
97 }
98
99 #endif
100
101 static int
102 iostat_packet(io_stat_item_t *mit, packet_info *pinfo, epan_dissect_t *edt _U_, void *dummy _U_)
103 {
104         io_stat_item_t *it;
105         gint32 current_time;
106
107         current_time=((pinfo->fd->rel_secs*1000)+(pinfo->fd->rel_usecs/1000));
108
109         /* the prev item before the main one is always the last interval we saw packets for */
110         it=mit->prev;
111
112         /* XXX for the time being, just ignore all frames that are in the past.
113            should be fixed in the future but hopefully it is uncommon */
114         if(current_time<it->time){
115                 return FALSE;
116         }
117
118         /* we have moved into a new interval, we need to create a new struct */
119         if(current_time>=(it->time+mit->parent->interval)){
120                 it->next=g_malloc(sizeof(io_stat_item_t));
121                 it->next->prev=it;
122                 it->next->next=NULL;
123                 it=it->next;
124                 mit->prev=it;
125
126                 it->time=(current_time / mit->parent->interval) * mit->parent->interval;
127                 it->frames=0;
128                 it->bytes=0;
129         }
130
131         /* it will now give us the current structure to use to store the data in */
132         it->frames++;
133         it->bytes+=pinfo->fd->pkt_len;
134         
135         return TRUE;
136 }
137
138 static void
139 iostat_draw(io_stat_item_t *mit)
140 {
141         io_stat_t *iot;
142         io_stat_item_t **items;
143         guint32 *frames;
144         guint32 *bytes;
145         guint32 i,more_items;
146         gint t;
147
148         iot=mit->parent;
149
150         printf("\n");
151         printf("===================================================================\n");
152         printf("IO Statistics\n");
153         printf("Interval: %d secs\n", iot->interval);
154         for(i=0;i<iot->num_items;i++){
155                 printf("Column #%d: %s\n",i,iot->filters[i]?iot->filters[i]:"");
156         }
157         printf("                ");
158         for(i=0;i<iot->num_items;i++){
159                 printf("|   Column #%-2d   ",i);
160         }
161         printf("\n");
162         printf("Time            ");
163         for(i=0;i<iot->num_items;i++){
164                 printf("|frames|  bytes  ");
165         }
166         printf("\n");
167
168         items=g_malloc(sizeof(io_stat_item_t *)*iot->num_items);
169         frames=g_malloc(sizeof(guint32)*iot->num_items);
170         bytes=g_malloc(sizeof(guint32)*iot->num_items);
171         /* preset all items at the first interval */
172         for(i=0;i<iot->num_items;i++){
173                 items[i]=&iot->items[i];
174         }
175
176         /* loop the items until we run out of them all */
177         t=0;
178         do {
179                 more_items=0;
180                 for(i=0;i<iot->num_items;i++){
181                         frames[i]=0;
182                         bytes[i]=0;
183                 }
184                 for(i=0;i<iot->num_items;i++){
185                         if(items[i] && (t>=(items[i]->time+iot->interval))){
186                                 items[i]=items[i]->next;
187                         }
188
189                         if(items[i] && (t<(items[i]->time+iot->interval)) && (t>=items[i]->time) ){
190                                 frames[i]=items[i]->frames;
191                                 bytes[i]=items[i]->bytes;
192                         }
193
194                         if(items[i]){
195                                 more_items=1;
196                         }
197                 }
198
199                 if(more_items){
200                         printf("%03d.%03d-%03d.%03d  ",
201                                 t/1000,t%1000,
202                                 (t+iot->interval)/1000,(t+iot->interval)%1000);
203                         for(i=0;i<iot->num_items;i++){
204                                 printf("%6d %9d ",frames[i],bytes[i]);
205                         }
206                         printf("\n");
207                 }
208
209                 t+=iot->interval;
210         } while(more_items);
211
212         printf("===================================================================\n");
213
214         g_free(items);
215         g_free(frames);
216         g_free(bytes);
217 }
218
219
220 static void
221 register_io_tap(io_stat_t *io, int i, char *filter)
222 {
223         io->items[i].prev=&io->items[i];
224         io->items[i].next=NULL;
225         io->items[i].parent=io;
226         io->items[i].time=0;
227         io->items[i].frames=0;
228         io->items[i].bytes=0;
229         io->filters[i]=filter;
230
231         if(register_tap_listener("frame", &io->items[i], filter, NULL, (void*)iostat_packet, i?NULL:(void*)iostat_draw)){
232                 g_free(io->items);
233                 g_free(io);
234                 fprintf(stderr,"tethereal: iostat_init() failed to attach tap\n");
235                 exit(1);
236         }
237 }
238
239 void
240 iostat_init(char *optarg)
241 {
242         float interval_float;
243         gint32 interval; 
244         int pos=0;
245         io_stat_t *io;
246         char *filter=NULL;
247
248         if(sscanf(optarg,"io,stat,%f,%n",&interval_float,&pos)==1){
249                 if(pos){
250                         filter=optarg+pos;
251                 } else {
252                         filter=NULL;
253                 }
254         } else {
255                 fprintf(stderr, "tethereal: invalid \"-z io,stat,<interval>[,<filter>]\" argument\n");
256                 exit(1);
257         }
258
259
260         /* make interval be number of ms */
261         interval=interval_float*1000;   
262         if(interval<1){
263                 fprintf(stderr, "tethereal:iostat_init()  interval must be >=0.001 seconds\n");
264                 exit(10);
265         }
266         
267         io=g_malloc(sizeof(io_stat_t));
268         io->interval=interval;
269         if((!filter)||(filter[0]==0)){
270                 io->num_items=1;
271                 io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
272                 io->filters=g_malloc(sizeof(char *)*io->num_items);
273
274                 register_io_tap(io, 0, NULL);
275         } else {
276                 char *str,*pos,*tmp;
277                 int i;
278                 /* find how many ',' separated filters we have */
279                 str=filter;
280                 io->num_items=1;
281                 while((str=strchr(str,','))){
282                         io->num_items++;
283                         str++;
284                 }
285
286                 io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
287                 io->filters=g_malloc(sizeof(char *)*io->num_items);
288
289                 /* for each filter, register a tap listener */          
290                 i=0;
291                 str=filter;
292                 do{
293                         pos=strchr(str,',');
294                         if(pos==str){
295                                 register_io_tap(io, i, NULL);
296                         } else if(pos==NULL) {
297                                 tmp=g_malloc(strlen(str)+1);
298                                 strcpy(tmp,str);
299                                 register_io_tap(io, i, tmp);
300                         } else {
301                                 tmp=g_malloc((pos-str)+1);
302                                 strncpy(tmp,str,(pos-str));
303                                 tmp[pos-str]=0;
304                                 register_io_tap(io, i, tmp);
305                         }
306                         str=pos+1;
307                         i++;                    
308                 } while(pos);
309         }                       
310 }
311
312 void
313 register_tap_listener_iostat(void)
314 {
315         register_ethereal_tap("io,stat,", iostat_init);
316 }
317