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