469b8cbf2bd20a788d58dcfae00cc5eccb56ba70
[obnox/wireshark/wip.git] / tap-iostat.c
1 /* tap-iostat.c
2  * iostat   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., 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/epan_dissect.h"
37 #include "epan/packet_info.h"
38 #include <epan/tap.h>
39 #include <epan/stat_cmd_args.h>
40 #include <epan/strutil.h>
41
42
43 typedef struct _io_stat_t {
44         gint64 interval;        /* unit is us */
45         guint32 num_items;
46         struct _io_stat_item_t *items;
47         const char **filters;
48 } io_stat_t;
49
50 #define CALC_TYPE_FRAMES 0
51 #define CALC_TYPE_BYTES  1
52 #define CALC_TYPE_FRAMES_AND_BYTES       2
53 #define CALC_TYPE_COUNT  3
54 #define CALC_TYPE_SUM    4
55 #define CALC_TYPE_MIN    5
56 #define CALC_TYPE_MAX    6
57 #define CALC_TYPE_AVG    7
58
59 typedef struct _io_stat_item_t {
60         io_stat_t *parent;
61         struct _io_stat_item_t *next;
62         struct _io_stat_item_t *prev;
63         gint64 time;            /* unit is us since start of capture */
64         int calc_type;
65         int hf_index;
66         guint64 frames;
67         guint64 num;
68         guint64 counter;
69 } io_stat_item_t;
70
71 #define NANOSECS_PER_SEC 1000000000
72
73 static int
74 iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
75 {
76         io_stat_item_t *mit = arg;
77         io_stat_item_t *it;
78         gint64 current_time;
79         GPtrArray *gp;
80         guint i;
81
82         current_time = (gint64)(pinfo->fd->rel_ts.secs*1000000) + (pinfo->fd->rel_ts.nsecs+500)/1000;
83
84         /* the prev item before the main one is always the last interval we saw packets for */
85         it=mit->prev;
86
87         /* XXX for the time being, just ignore all frames that are in the past.
88            should be fixed in the future but hopefully it is uncommon */
89         if(current_time<it->time){
90                 return FALSE;
91         }
92
93         /* we have moved into a new interval, we need to create a new struct */
94         if(current_time>=(it->time+mit->parent->interval)){
95                 it->next=g_malloc(sizeof(io_stat_item_t));
96                 it->next->prev=it;
97                 it->next->next=NULL;
98                 it=it->next;
99                 mit->prev=it;
100
101                 it->time=(current_time / mit->parent->interval) * mit->parent->interval;
102                 it->frames=0;
103                 it->counter=0;
104                 it->num=0;
105                 it->calc_type=it->prev->calc_type;
106                 it->hf_index=it->prev->hf_index;
107         }
108
109         /* it will now give us the current structure to use to store the data in */
110         it->frames++;
111
112         switch(it->calc_type){
113         case CALC_TYPE_BYTES:
114         case CALC_TYPE_FRAMES: 
115         case CALC_TYPE_FRAMES_AND_BYTES:
116                 it->counter+=pinfo->fd->pkt_len;
117                 break;
118         case CALC_TYPE_COUNT:
119                 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
120                 if(gp){
121                         it->counter+=gp->len;
122                 }
123                 break;
124         case CALC_TYPE_SUM:
125                 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
126                 if(gp){
127                         guint64 val;
128                         nstime_t *new_time;
129
130                         for(i=0;i<gp->len;i++){
131                                 switch(proto_registrar_get_ftype(it->hf_index)){
132                                 case FT_UINT8:
133                                 case FT_UINT16:
134                                 case FT_UINT24:
135                                 case FT_UINT32:
136                                         it->counter+=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
137                                         break;
138                                 case FT_UINT64:
139                                         it->counter+=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
140                                         break;
141                                 case FT_INT8:
142                                 case FT_INT16:
143                                 case FT_INT24:
144                                 case FT_INT32:
145                                         it->counter+=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
146                                         break;
147                                 case FT_INT64:
148                                         it->counter+=(gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
149                                         break;
150                                 case FT_RELATIVE_TIME:
151                                         new_time = fvalue_get(&((field_info *)gp->pdata[i])->value);
152                                         val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
153                                         it->counter += val;
154                                         break;
155                                 }
156                         }
157                 }
158                 break;
159         case CALC_TYPE_MIN:
160                 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
161                 if(gp){
162                         int type;
163                         guint64 val;
164                         nstime_t *new_time;
165
166                         type=proto_registrar_get_ftype(it->hf_index);
167                         for(i=0;i<gp->len;i++){
168                                 switch(type){
169                                 case FT_UINT8:
170                                 case FT_UINT16:
171                                 case FT_UINT24:
172                                 case FT_UINT32:
173                                         val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
174                                         if((it->frames==1)&&(i==0)){
175                                                 it->counter=val;
176                                         } else if(val<it->counter){
177                                                 it->counter=val;
178                                         }
179                                         break;
180                                 case FT_UINT64:
181                                         val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
182                                         if((it->frames==1)&&(i==0)){
183                                                 it->counter=val;
184                                         } else if(val<it->counter){
185                                                 it->counter=val;
186                                         }
187                                         break;
188                                 case FT_INT8:
189                                 case FT_INT16:
190                                 case FT_INT24:
191                                 case FT_INT32:
192                                         val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
193                                         if((it->frames==1)&&(i==0)){
194                                                 it->counter=val;
195                                         } else if((gint32)val<(gint32)(it->counter)){
196                                                 it->counter=val;
197                                         }
198                                         break;
199                                 case FT_INT64:
200                                         val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
201                                         if((it->frames==1)&&(i==0)){
202                                                 it->counter=val;
203                                         } else if((gint64)val<(gint64)(it->counter)){
204                                                 it->counter=val;
205                                         }
206                                         break;
207                                 case FT_RELATIVE_TIME:
208                                         new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
209                                         val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
210                                         if((it->frames==1)&&(i==0)){
211                                                 it->counter=val;
212                                         } else if(val<it->counter){
213                                                 it->counter=val;
214                                         }
215                                         break;
216                                 }
217                         }
218                 }
219                 break;
220         case CALC_TYPE_MAX:
221                 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
222                 if(gp){
223                         int type;
224                         guint64 val;
225                         nstime_t *new_time;
226
227                         type=proto_registrar_get_ftype(it->hf_index);
228                         for(i=0;i<gp->len;i++){
229                                 switch(type){
230                                 case FT_UINT8:
231                                 case FT_UINT16:
232                                 case FT_UINT24:
233                                 case FT_UINT32:
234                                         val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
235                                         if((it->frames==1)&&(i==0)){
236                                                 it->counter=val;
237                                         } else if(val>it->counter){
238                                                 it->counter=val;
239                                         }
240                                         break;
241                                 case FT_UINT64:
242                                         val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
243                                         if((it->frames==1)&&(i==0)){
244                                                 it->counter=val;
245                                         } else if(val>it->counter){
246                                                 it->counter=val;
247                                         }
248                                         break;
249                                 case FT_INT8:
250                                 case FT_INT16:
251                                 case FT_INT24:
252                                 case FT_INT32:
253                                         val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
254                                         if((it->frames==1)&&(i==0)){
255                                                 it->counter=val;
256                                         } else if((gint32)val>(gint32)(it->counter)){
257                                                 it->counter=val;
258                                         }
259                                         break;
260                                 case FT_INT64:
261                                         val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
262                                         if((it->frames==1)&&(i==0)){
263                                                 it->counter=val;
264                                         } else if((gint64)val>(gint64)(it->counter)){
265                                                 it->counter=val;
266                                         }
267                                         break;
268                                 case FT_RELATIVE_TIME:
269                                         new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
270                                         val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
271                                         if((it->frames==1)&&(i==0)){
272                                                 it->counter=val;
273                                         } else if(val>it->counter){
274                                                 it->counter=val;
275                                         }
276                                         break;
277                                 }
278                         }
279                 }
280                 break;
281         case CALC_TYPE_AVG:
282                 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
283                 if(gp){
284                         int type;
285                         guint64 val;
286                         nstime_t *new_time;
287
288                         type=proto_registrar_get_ftype(it->hf_index);
289                         for(i=0;i<gp->len;i++){
290                                 it->num++;
291                                 switch(type){
292                                 case FT_UINT8:
293                                 case FT_UINT16:
294                                 case FT_UINT24:
295                                 case FT_UINT32:
296                                         val=fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
297                                         it->counter+=val;
298                                         break;
299                                 case FT_UINT64:
300                                 case FT_INT64:
301                                         val=fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
302                                         it->counter+=val;
303                                         break;
304                                 case FT_INT8:
305                                 case FT_INT16:
306                                 case FT_INT24:
307                                 case FT_INT32:
308                                         val=fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
309                                         it->counter+=val;
310                                         break;
311                                 case FT_RELATIVE_TIME:
312                                         new_time=fvalue_get(&((field_info *)gp->pdata[i])->value);
313                                         val=(guint64)(new_time->secs) * NANOSECS_PER_SEC + new_time->nsecs;
314                                         it->counter+=val;
315                                         break;
316                                 }
317                         }
318                 }
319                 break;
320         }
321
322         return TRUE;
323 }
324
325 static void
326 iostat_draw(void *arg)
327 {
328         io_stat_item_t *mit = arg;
329         io_stat_t *iot;
330         io_stat_item_t **items;
331         guint64 *frames;
332         guint64 *counters;
333         guint64 *num;
334         guint32 i;
335         guint32 borderLen=68;
336         gboolean more_items;
337         gint64 t;
338
339         iot=mit->parent;
340
341         printf("\n");
342         
343         /* Display the table border */
344         for(i=0;i<iot->num_items;i++){
345                 if(iot->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES)
346                         borderLen+=17;
347         }
348         if(iot->interval!=G_MAXINT32)
349                 borderLen+=8;
350         if(iot->num_items>3)
351                 borderLen+=(iot->num_items-3)*17;
352         for(i=0;i<borderLen;i++){
353                 printf("=");
354         }
355         printf("\n");
356         
357         
358         printf("IO Statistics\n");
359         if(iot->interval!=G_MAXINT32)
360                 printf("Interval: %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u secs\n", 
361                                 iot->interval/1000000, iot->interval%1000000);                                          
362
363         for(i=0;i<iot->num_items;i++){
364                 printf("Column #%u: %s\n",i,iot->filters[i]?iot->filters[i]:"");
365         }
366         if(iot->interval==G_MAXINT32){
367                 printf("                |");
368         } else {
369                 printf("                        |");
370         }
371         for(i=0;i<iot->num_items;i++){
372                 if(iot->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES){
373                         printf("            Column #%-2u           |",i);
374                 } else {        
375                         printf("    Column #%-2u  |",i);
376                 }
377         }
378         printf("\n");
379
380         if(iot->interval==G_MAXINT32) {
381                 printf("Time            |");
382         } else {
383                 printf("Time                    |");
384         }
385         for(i=0;i<iot->num_items;i++){
386                 switch(iot->items[i].calc_type){
387                 case CALC_TYPE_FRAMES:
388                         printf("     FRAMES     |");
389                         break;
390                 case CALC_TYPE_BYTES:
391                         printf("     BYTES      |");
392                         break;
393                 case CALC_TYPE_FRAMES_AND_BYTES:
394                         printf("     Frames     |      Bytes     |");
395                         break;
396                 case CALC_TYPE_COUNT:
397                         printf("      COUNT     |");
398                         break;
399                 case CALC_TYPE_SUM:
400                         printf("       SUM      |");
401                         break;
402                 case CALC_TYPE_MIN:
403                         printf("       MIN      |");
404                         break;
405                 case CALC_TYPE_MAX:
406                         printf("       MAX      |");
407                         break;
408                 case CALC_TYPE_AVG:
409                         printf("       AVG      |");
410                         break;
411                 }
412         }
413         printf("\n");
414
415         items=g_malloc(sizeof(io_stat_item_t *)*iot->num_items);
416         frames=g_malloc(sizeof(guint64)*iot->num_items);
417         counters=g_malloc(sizeof(guint64)*iot->num_items);
418         num=g_malloc(sizeof(guint64)*iot->num_items);
419         /* preset all items at the first interval */
420         for(i=0;i<iot->num_items;i++){
421                 items[i]=&iot->items[i];
422         }
423
424         /* loop the items until we run out of them all */
425         t=0;
426         do {
427                 more_items=FALSE;
428                 for(i=0;i<iot->num_items;i++){
429                         frames[i]=0;
430                         counters[i]=0;
431                         num[i]=0;
432                 }
433                 for(i=0;i<iot->num_items;i++){
434                         if(items[i] && (t>=(items[i]->time+iot->interval))){
435                                 items[i]=items[i]->next;
436                         }
437
438                         if(items[i] && (t<(items[i]->time+iot->interval)) && (t>=items[i]->time) ){
439                                 frames[i]=items[i]->frames;
440                                 counters[i]=items[i]->counter;
441                                 num[i]=items[i]->num;
442                         }
443
444                         if(items[i]){
445                                 more_items=TRUE;
446                         }
447                 }
448
449                 if(more_items){
450                         if(iot->interval==G_MAXINT32) {
451                                 printf("000.000-         ");
452                         } else {
453                                 printf("%04u.%06u-%04u.%06u  ",
454                                                 (int)(t/1000000),(int)(t%1000000),
455                                                 (int)((t+iot->interval)/1000000),
456                                                 (int)((t+iot->interval)%1000000));
457                         }
458                         for(i=0;i<iot->num_items;i++){
459                                 switch(iot->items[i].calc_type){
460                                 case CALC_TYPE_FRAMES:
461                                         printf(" %15" G_GINT64_MODIFIER "u ", frames[i]);
462                                         break;
463                                 case CALC_TYPE_BYTES:
464                                         printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
465                                         break;
466                                 case CALC_TYPE_FRAMES_AND_BYTES:
467                                         printf(" %15" G_GINT64_MODIFIER "u  %15" G_GINT64_MODIFIER "u ", frames[i], counters[i]);
468                                         break;
469                                 case CALC_TYPE_COUNT:
470                                         printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
471                                         break;
472                                 case CALC_TYPE_SUM:
473                                         switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
474                                         case FT_RELATIVE_TIME:
475                                                 counters[i] = (counters[i]+500)/1000;
476                                                 printf(" %8u.%06u ",
477                                                                 (int)(counters[i]/1000000), (int)(counters[i]%1000000));
478                                                 break;
479                                         default:
480                                                 printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
481                                                 break;
482                                         }
483                                         break;
484                                 case CALC_TYPE_MIN:
485                                         switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
486                                         case FT_UINT8:
487                                         case FT_UINT16:
488                                         case FT_UINT24:
489                                         case FT_UINT32:
490                                         case FT_UINT64:
491                                                 printf(" %15" G_GINT64_MODIFIER "u ", counters[i]);
492                                                 break;
493                                         case FT_INT8:
494                                         case FT_INT16:
495                                         case FT_INT24:
496                                         case FT_INT32:
497                                         case FT_INT64:
498                                                 printf(" %15" G_GINT64_MODIFIER "d ", counters[i]);
499                                                 break;
500                                         case FT_RELATIVE_TIME:
501                                                 counters[i]=(counters[i]+500)/1000;
502                                                 printf(" %8u.%06u ",
503                                                                 (int)(counters[i]/1000000), (int)(counters[i]%1000000));
504                                                 break;
505                                         }
506                                         break;
507                                 case CALC_TYPE_MAX:
508                                         switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
509                                         case FT_UINT8:
510                                         case FT_UINT16:
511                                         case FT_UINT24:
512                                         case FT_UINT32:
513                                         case FT_UINT64:
514                                                 printf(" %15u ", (int)(counters[i]));
515                                                 break;
516                                         case FT_INT8:
517                                         case FT_INT16:
518                                         case FT_INT24:
519                                         case FT_INT32:
520                                         case FT_INT64:
521                                                 printf(" %15" G_GINT64_MODIFIER "d ", counters[i]);
522                                                 break;
523                                         case FT_RELATIVE_TIME:
524                                                 counters[i]=(counters[i]+500)/1000;
525                                                 printf(" %8u.%06u ",
526                                                                 (int)(counters[i]/1000000), (int)(counters[i]%1000000));
527                                                 break;
528                                         }
529                                         break;
530                                 case CALC_TYPE_AVG:
531                                         if(num[i]==0){
532                                                 num[i]=1;
533                                         }
534                                         switch(proto_registrar_get_ftype(iot->items[i].hf_index)){
535                                         case FT_UINT8:
536                                         case FT_UINT16:
537                                         case FT_UINT24:
538                                         case FT_UINT32:
539                                         case FT_UINT64:
540                                                 printf(" %15" G_GINT64_MODIFIER "u ", counters[i]/num[i]);
541                                                 break;
542                                         case FT_INT8:
543                                         case FT_INT16:
544                                         case FT_INT24:
545                                         case FT_INT32:
546                                         case FT_INT64:
547                                                 printf(" %15" G_GINT64_MODIFIER "d ", counters[i]/num[i]);
548                                                 break;
549                                         case FT_RELATIVE_TIME:
550                                                 counters[i]=((counters[i]/num[i])+500)/1000;
551                                                 printf(" %8u.%06u ",
552                                                                 (int)(counters[i]/1000000), (int)(counters[i]%1000000));
553                                                 break;
554                                         }
555                                         break;
556
557                                 }
558                         }
559                         printf("\n");
560                 }
561
562                 t+=iot->interval;
563         } while(more_items);
564
565         for(i=0;i<borderLen;i++){
566                 printf("=");
567         }
568         printf("\n");
569
570         g_free(items);
571         g_free(frames);
572         g_free(counters);
573         g_free(num);
574 }
575
576
577 typedef struct {
578         const char *func_name;
579         int calc_type;
580 } calc_type_ent_t;
581
582 static calc_type_ent_t calc_type_table[] = {
583         { "FRAMES", CALC_TYPE_FRAMES },
584         { "BYTES", CALC_TYPE_BYTES },
585         { "COUNT", CALC_TYPE_COUNT },
586         { "SUM", CALC_TYPE_SUM },
587         { "MIN", CALC_TYPE_MIN },
588         { "MAX", CALC_TYPE_MAX },
589         { "AVG", CALC_TYPE_AVG },
590         { NULL, 0 }
591 };
592
593 static void
594 register_io_tap(io_stat_t *io, int i, const char *filter)
595 {
596         GString *error_string;
597         const char *flt;
598         int j;
599         size_t namelen;
600         const char *p, *parenp;
601         char *field;
602         header_field_info *hfi;
603
604         io->items[i].prev=&io->items[i];
605         io->items[i].next=NULL;
606         io->items[i].parent=io;
607         io->items[i].time=0;
608         io->items[i].calc_type=CALC_TYPE_FRAMES_AND_BYTES;
609         io->items[i].frames=0;
610         io->items[i].counter=0;
611         io->items[i].num=0;
612         io->filters[i]=filter;
613         flt=filter;
614
615         field=NULL;
616         hfi=NULL;
617         for(j=0; calc_type_table[j].func_name; j++){
618                 namelen=strlen(calc_type_table[j].func_name);
619                 if(filter && strncmp(filter, calc_type_table[j].func_name, namelen) == 0) {
620                         io->items[i].calc_type=calc_type_table[j].calc_type;
621                         if(*(filter+namelen)=='(') {
622                                 p=filter+namelen+1;
623                                 parenp=strchr(p, ')');
624                                 if(!parenp){
625                                         fprintf(stderr, "\ntshark: Closing parenthesis missing from calculated expression.\n");
626                                         exit(10);
627                                 }
628                                 
629                                 
630                                 if(io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES){
631                                         if(parenp!=p) { 
632                                                 fprintf(stderr, "\ntshark: %s does require or allow a field name within the parens.\n", 
633                                                         calc_type_table[j].func_name);
634                                                 exit(10);
635                                         }
636                                 } else {
637                                         if(parenp==p) { 
638                                                         /* bail out if a field name was not specified */
639                                                         fprintf(stderr, "\ntshark: You didn't specify a field name for %s(*).\n", 
640                                                                 calc_type_table[j].func_name);
641                                                         exit(10);
642                                         }
643                                 }                               
644
645                                 field=g_malloc(parenp-p+1);
646                                 memcpy(field, p, parenp-p);
647                                 field[parenp-p] = '\0';
648                                 flt=parenp + 1;
649                                 if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
650                                         break;
651                                 hfi=proto_registrar_get_byname(field);
652                                 if(!hfi){
653                                         fprintf(stderr, "\ntshark: There is no field named '%s'.\n",
654                                                 field);
655                                         g_free(field);
656                                         exit(10);
657                                 }
658
659                                 io->items[i].hf_index=hfi->id;
660                                 break;
661                         }
662                 } else {
663                         if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
664                                 flt="";
665                 }
666         }
667         if(hfi && !(io->items[i].calc_type==CALC_TYPE_BYTES || 
668                             io->items[i].calc_type==CALC_TYPE_FRAMES || 
669                             io->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES)){
670                 /* check that the type is compatible */
671                 switch(hfi->type){
672                 case FT_UINT8:
673                 case FT_UINT16:
674                 case FT_UINT24:
675                 case FT_UINT32:
676                 case FT_UINT64:
677                 case FT_INT8:
678                 case FT_INT16:
679                 case FT_INT24:
680                 case FT_INT32:
681                 case FT_INT64:
682                         /* these types support all calculations */
683                         break;
684                 case FT_RELATIVE_TIME:
685                         /* this type only supports SUM, COUNT, MAX, MIN, AVG */
686                         switch(io->items[i].calc_type){
687                         case CALC_TYPE_SUM:
688                         case CALC_TYPE_COUNT:
689                         case CALC_TYPE_MAX:
690                         case CALC_TYPE_MIN:
691                         case CALC_TYPE_AVG:
692                                 break;
693                         default:
694                                 fprintf(stderr,
695                                         "\ntshark: %s is a relative-time field, so %s(*) calculations are not supported on it.",
696                                     field,
697                                     calc_type_table[j].func_name);
698                                 exit(10);
699                         }
700                         break;
701                 default:
702                         /*
703                          * XXX - support all operations on floating-point
704                          * numbers?
705                          */
706                         if(io->items[i].calc_type!=CALC_TYPE_COUNT){
707                                 fprintf(stderr,
708                                         "\ntshark: %s doesn't have integral values, so %s(*) calculations are not supported on it.\n",
709                                     field,
710                                     calc_type_table[j].func_name);
711                                 exit(10);
712                         }
713                         break;
714                 }
715                 g_free(field);
716         }
717
718 /*
719 CALC_TYPE_SUM   2
720 CALC_TYPE_MIN   3
721 CALC_TYPE_MAX   4
722 CALC_TYPE_AVG   5
723 */
724
725         error_string=register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE, NULL, iostat_packet, i?NULL:iostat_draw);
726         if(error_string){
727                 g_free(io->items);
728                 g_free(io);
729                 fprintf(stderr, "\ntshark: Couldn't register io,stat tap: %s\n",
730                     error_string->str);
731                 g_string_free(error_string, TRUE);
732                 exit(1);
733         }
734 }
735
736 static void
737 iostat_init(const char *optarg, void* userdata _U_)
738 {
739         gdouble interval_float;
740         gint64 interval;
741         int idx=0;
742         io_stat_t *io;
743         const char *filter=NULL;
744
745         if(sscanf(optarg,"io,stat,%lf,%n",&interval_float,&idx)==1){
746                 if(idx){
747                         if(*(optarg+idx)==',')
748                                 filter=optarg+idx+1;
749                         else
750                                 filter=optarg+idx;
751                 } else {
752                         filter=NULL;
753                 }
754         } else {
755                 fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>]\" argument\n");
756                 exit(1);
757         }
758
759         /* if interval is 0, calculate statistics over the whole file
760          * by setting the interval to G_MAXINT32
761          */
762         if(interval_float==0) {
763                 interval=G_MAXINT32;
764         } else {
765                 /* make interval be number of us rounded to the nearest integer*/
766                 interval=(gint64)(interval_float*1000000.0+0.5); 
767         }
768
769         if(interval<1){
770                 fprintf(stderr, 
771                         "\ntshark: \"-z\" interval must be >=0.000001 seconds or \"0\" for the entire capture duration.\n");
772                 exit(10);
773         }
774
775         io=g_malloc(sizeof(io_stat_t));
776         io->interval=interval;
777         if((!filter)||(filter[0]==0)){
778                 io->num_items=1;
779                 io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
780                 io->filters=g_malloc(sizeof(char *)*io->num_items);
781
782                 register_io_tap(io, 0, NULL);
783         } else {
784                 const char *str,*pos;
785                 char *tmp;
786                 int i;
787                 /* find how many ',' separated filters we have */
788                 str=filter;
789                 io->num_items=1;
790                 while((str=strchr(str,','))){
791                         io->num_items++;
792                         str++;
793                 }
794
795                 io->items=g_malloc(sizeof(io_stat_item_t)*io->num_items);
796                 io->filters=g_malloc(sizeof(char *)*io->num_items);
797
798                 /* for each filter, register a tap listener */
799                 i=0;
800                 str=filter;
801                 do{
802                         pos=strchr(str,',');
803                         if(pos==str){
804                                 register_io_tap(io, i, NULL);
805                         } else if(pos==NULL) {
806                                 tmp=g_strdup(str);
807                                 register_io_tap(io, i, tmp);
808                         } else {
809                                 tmp=g_malloc((pos-str)+1);
810                                 g_strlcpy(tmp,str,(pos-str)+1);
811                                 register_io_tap(io, i, tmp);
812                         }
813                         str=pos+1;
814                         i++;
815                 } while(pos);
816         }
817 }
818
819 void
820 register_tap_listener_iostat(void)
821 {
822         register_stat_cmd_arg("io,stat,", iostat_init, NULL);
823 }