Gtk1 version of io-stat
[obnox/wireshark/wip.git] / tap-iostat.c
1 /* tap-iostat.c
2  * iostat   2002 Ronnie Sahlberg
3  *
4  * $Id: tap-iostat.c,v 1.3 2002/11/15 10:55:15 sahlberg 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;
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;
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
106         /* the prev item before the main one is always the last interval we saw packets for */
107         it=mit->prev;
108
109         /* XXX for the time being, just ignore all frames that are in the past.
110            should be fixed in the future but hopefully it is uncommon */
111         if(pinfo->fd->rel_secs<it->time){
112                 return FALSE;
113         }
114
115         /* we have moved into a new interval, we need to create a new struct */
116         if(pinfo->fd->rel_secs>=(it->time+mit->parent->interval)){
117                 it->next=g_malloc(sizeof(io_stat_item_t));
118                 it->next->prev=it;
119                 it->next->next=NULL;
120                 it=it->next;
121                 mit->prev=it;
122
123                 it->time=(pinfo->fd->rel_secs / mit->parent->interval) * mit->parent->interval;
124                 it->frames=0;
125                 it->bytes=0;
126         }
127
128         /* it will now give us the current structure to use to store the data in */
129         it->frames++;
130         it->bytes+=pinfo->fd->pkt_len;
131         
132         return TRUE;
133 }
134
135 static void
136 iostat_draw(io_stat_item_t *mit)
137 {
138         io_stat_t *iot;
139         io_stat_item_t **items;
140         guint32 *frames;
141         guint32 *bytes;
142         guint32 i,more_items;
143         gint t;
144
145         iot=mit->parent;
146
147         printf("\n");
148         printf("===================================================================\n");
149         printf("IO Statistics\n");
150         printf("Interval: %d secs\n", iot->interval);
151         for(i=0;i<iot->num_items;i++){
152                 printf("Column #%d: %s\n",i,iot->filters[i]?iot->filters[i]:"");
153         }
154         printf("            ");
155         for(i=0;i<iot->num_items;i++){
156                 printf("|   Column #%-2d   ",i);
157         }
158         printf("\n");
159         printf("Time        ");
160         for(i=0;i<iot->num_items;i++){
161                 printf("|frames|  bytes  ");
162         }
163         printf("\n");
164
165         items=g_malloc(sizeof(io_stat_item_t *)*iot->num_items);
166         frames=g_malloc(sizeof(guint32)*iot->num_items);
167         bytes=g_malloc(sizeof(guint32)*iot->num_items);
168         /* preset all items at the first interval */
169         for(i=0;i<iot->num_items;i++){
170                 items[i]=&iot->items[i];
171         }
172
173         /* loop the items until we run out of them all */
174         t=0;
175         do {
176                 more_items=0;
177                 for(i=0;i<iot->num_items;i++){
178                         frames[i]=0;
179                         bytes[i]=0;
180                 }
181                 for(i=0;i<iot->num_items;i++){
182                         if(items[i] && (t>=(items[i]->time+iot->interval))){
183                                 items[i]=items[i]->next;
184                         }
185
186                         if(items[i] && (t<(items[i]->time+iot->interval)) && (t>=items[i]->time) ){
187                                 frames[i]=items[i]->frames;
188                                 bytes[i]=items[i]->bytes;
189                         }
190
191                         if(items[i]){
192                                 more_items=1;
193                         }
194                 }
195
196                 if(more_items){
197                         printf("%5d-%5d  ",t,t+iot->interval);
198                         for(i=0;i<iot->num_items;i++){
199                                 printf("%6d %9d ",frames[i],bytes[i]);
200                         }
201                         printf("\n");
202                 }
203
204                 t+=iot->interval;
205         } while(more_items);
206
207         printf("===================================================================\n");
208
209         g_free(items);
210         g_free(frames);
211         g_free(bytes);
212 }
213
214
215 static void
216 register_io_tap(io_stat_t *io, int i, char *filter)
217 {
218         io->items[i].prev=&io->items[i];
219         io->items[i].next=NULL;
220         io->items[i].parent=io;
221         io->items[i].time=0;
222         io->items[i].frames=0;
223         io->items[i].bytes=0;
224         io->filters[i]=filter;
225
226         if(register_tap_listener("frame", &io->items[i], filter, NULL, (void*)iostat_packet, i?NULL:(void*)iostat_draw)){
227                 g_free(io->items);
228                 g_free(io);
229                 fprintf(stderr,"tethereal: iostat_init() failed to attach tap\n");
230                 exit(1);
231         }
232 }
233
234 void
235 iostat_init(char *optarg)
236 {
237         int interval, pos=0;
238         io_stat_t *io;
239         char *filter=NULL;
240
241         if(sscanf(optarg,"io,stat,%d,%n",&interval,&pos)==1){
242                 if(pos){
243                         filter=optarg+pos;
244                 } else {
245                         filter=NULL;
246                 }
247         } else {
248                 fprintf(stderr, "tethereal: invalid \"-z io,stat,<interval>[,<filter>]\" argument\n");
249                 exit(1);
250         }
251
252         if(interval<1){
253                 fprintf(stderr, "tethereal:iostat_init()  interval must be >0 seconds\n");
254                 exit(10);
255         }
256         
257         io=g_malloc(sizeof(io_stat_t));
258         io->interval=interval;
259         if((!filter)||(filter[0]==0)){
260                 io->num_items=1;
261                 io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
262                 io->filters=g_malloc(sizeof(char *)*io->num_items);
263
264                 register_io_tap(io, 0, NULL);
265         } else {
266                 char *str,*pos,*tmp;
267                 int i;
268                 /* find how many ',' separated filters we have */
269                 str=filter;
270                 io->num_items=1;
271                 while((str=strchr(str,','))){
272                         io->num_items++;
273                         str++;
274                 }
275
276                 io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
277                 io->filters=g_malloc(sizeof(char *)*io->num_items);
278
279                 /* for each filter, register a tap listener */          
280                 i=0;
281                 str=filter;
282                 do{
283                         pos=strchr(str,',');
284                         if(pos==str){
285                                 register_io_tap(io, i, NULL);
286                         } else if(pos==NULL) {
287                                 tmp=g_malloc(strlen(str)+1);
288                                 strcpy(tmp,str);
289                                 register_io_tap(io, i, tmp);
290                         } else {
291                                 tmp=g_malloc((pos-str)+1);
292                                 strncpy(tmp,str,(pos-str));
293                                 tmp[pos-str]=0;
294                                 register_io_tap(io, i, tmp);
295                         }
296                         str=pos+1;
297                         i++;                    
298                 } while(pos);
299         }                       
300 }
301
302 void
303 register_tap_listener_iostat(void)
304 {
305         register_ethereal_tap("io,stat,", iostat_init, NULL, NULL);
306 }
307