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