Rename epan/stat.[ch] to epan/stat_cmd_args.[ch] - it only deals with
[obnox/wireshark/wip.git] / tap-protohierstat.c
1 /* tap-protohierstat.c
2  * protohierstat   2002 Ronnie Sahlberg
3  *
4  * $Id$
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 ProtocolHierarchyStatistics for tethereal */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #include <string.h>
38 #include "epan/packet_info.h"
39 #include "epan/epan_dissect.h"
40 #include "epan/proto.h"
41 #include <epan/tap.h>
42 #include <epan/stat_cmd_args.h>
43 #include "register.h"
44
45 typedef struct _phs_t {
46         struct _phs_t *sibling;
47         struct _phs_t *child;
48         struct _phs_t *parent;
49         char *filter;
50         int protocol;
51         const char *proto_name;
52         guint32 frames;
53         guint32 bytes;
54 } phs_t;
55
56
57 static phs_t *
58 new_phs_t(phs_t *parent)
59 {
60         phs_t *rs;
61         rs=g_malloc(sizeof(phs_t));
62         rs->sibling=NULL;
63         rs->child=NULL;
64         rs->parent=parent;
65         rs->filter=NULL;
66         rs->protocol=-1;
67         rs->proto_name=NULL;
68         rs->frames=0;
69         rs->bytes=0;
70         return rs;
71 }
72
73
74 static int
75 protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
76 {
77         phs_t *rs=prs;
78         phs_t *tmprs;
79         proto_tree *tree;
80         field_info *fi;
81
82         if(!edt){
83                 return 0;
84         }
85         if(!edt->tree){
86                 return 0;
87         }
88         if(!edt->tree->first_child){
89                 return 0;
90         }
91
92         for(tree=edt->tree->first_child;tree;tree=tree->next){
93                 fi=PITEM_FINFO(tree);
94
95                 /* first time we saw a protocol at this leaf */
96                 if(rs->protocol==-1){
97                         rs->protocol=fi->hfinfo->id;
98                         rs->proto_name=fi->hfinfo->abbrev;
99                         rs->frames=1;
100                         rs->bytes=pinfo->fd->pkt_len;
101                         rs->child=new_phs_t(rs);
102                         rs=rs->child;
103                         continue;
104                 }
105
106                 /* find this protocol in the list of siblings */
107                 for(tmprs=rs;tmprs;tmprs=tmprs->sibling){
108                         if(tmprs->protocol==fi->hfinfo->id){
109                                 break;
110                         }
111                 }
112
113                 /* not found, then we must add it to the end of the list */
114                 if(!tmprs){
115                         for(tmprs=rs;tmprs->sibling;tmprs=tmprs->sibling)
116                                 ;
117                         tmprs->sibling=new_phs_t(rs->parent);
118                         rs=tmprs->sibling;
119                         rs->protocol=fi->hfinfo->id;
120                         rs->proto_name=fi->hfinfo->abbrev;
121                 } else {
122                         rs=tmprs;
123                 }
124
125                 rs->frames++;
126                 rs->bytes+=pinfo->fd->pkt_len;
127
128                 if(!rs->child){
129                         rs->child=new_phs_t(rs);
130                 }
131                 rs=rs->child;
132         }
133         return 1;
134 }
135
136 static void
137 phs_draw(phs_t *rs, int indentation)
138 {
139         int i;
140         char str[80];
141         for(;rs;rs=rs->sibling){
142                 if(rs->protocol==-1){
143                         return;
144                 }
145                 str[0]=0;
146                 for(i=0;i<indentation;i++){
147                         strcat(str,"  ");
148                 }
149                 strcat(str, rs->proto_name);
150                 printf("%-40s frames:%d bytes:%d\n",str, rs->frames, rs->bytes);
151                 phs_draw(rs->child, indentation+1);
152         }
153 }
154
155 static void
156 protohierstat_draw(void *prs)
157 {
158         phs_t *rs=prs;
159
160         printf("\n");
161         printf("===================================================================\n");
162         printf("Protocol Hierarchy Statistics\n");
163         printf("Filter: %s\n\n",rs->filter?rs->filter:"");
164         phs_draw(rs,0);
165         printf("===================================================================\n");
166 }
167
168
169 static void
170 protohierstat_init(const char *optarg)
171 {
172         phs_t *rs;
173         int pos=0;
174         const char *filter=NULL;
175         GString *error_string;
176
177         if(!strcmp("io,phs",optarg)){
178                 filter="frame";
179         } else if(sscanf(optarg,"io,phs,%n",&pos)==0){
180                 if(pos){
181                         filter=optarg+pos;
182                 } else {
183                         /* We must use a filter to guarantee that edt->tree
184                            will be populated. "frame" matches everything so
185                            that one is used instead of no filter.
186                         */
187                         filter="frame"; 
188                 }
189         } else {
190                 fprintf(stderr, "tethereal: invalid \"-z io,phs[,<filter>]\" argument\n");
191                 exit(1);
192         }
193
194         rs=new_phs_t(NULL);
195
196         if(filter){
197                 rs->filter=g_malloc(strlen(filter)+1);
198                 strcpy(rs->filter, filter);
199         } else {
200                 rs->filter=NULL;
201         }
202
203         error_string=register_tap_listener("frame", rs, filter, NULL, protohierstat_packet, protohierstat_draw);
204         if(error_string){
205                 /* error, we failed to attach to the tap. clean up */
206                 g_free(rs->filter);
207                 g_free(rs);
208
209                 fprintf(stderr, "tethereal: Couldn't register io,phs tap: %s\n",
210                     error_string->str);
211                 g_string_free(error_string, TRUE);
212                 exit(1);
213         }
214 }
215
216
217 void
218 register_tap_listener_protohierstat(void)
219 {
220         register_stat_cmd_arg("io,phs", protohierstat_init);
221 }
222