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