From Menno Andriesse
[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, stroff;
140 #define MAXPHSLINE 80
141         char str[MAXPHSLINE];
142         for(;rs;rs=rs->sibling){
143                 if(rs->protocol==-1){
144                         return;
145                 }
146                 str[0]=0;
147                 stroff=0;
148                 for(i=0;i<indentation;i++){
149                         if(i>15){
150                                 stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, "...");
151                                 break;
152                         }
153                         stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, "  ");
154                 }
155                 stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, rs->proto_name);
156                 printf("%-40s frames:%d bytes:%d\n",str, rs->frames, rs->bytes);
157                 phs_draw(rs->child, indentation+1);
158         }
159 }
160
161 static void
162 protohierstat_draw(void *prs)
163 {
164         phs_t *rs=prs;
165
166         printf("\n");
167         printf("===================================================================\n");
168         printf("Protocol Hierarchy Statistics\n");
169         printf("Filter: %s\n\n",rs->filter?rs->filter:"");
170         phs_draw(rs,0);
171         printf("===================================================================\n");
172 }
173
174
175 static void
176 protohierstat_init(const char *optarg, void* userdata _U_)
177 {
178         phs_t *rs;
179         int pos=0;
180         const char *filter=NULL;
181         GString *error_string;
182
183         if(!strcmp("io,phs",optarg)){
184                 filter="frame";
185         } else if(sscanf(optarg,"io,phs,%n",&pos)==0){
186                 if(pos){
187                         filter=optarg+pos;
188                 } else {
189                         /* We must use a filter to guarantee that edt->tree
190                            will be populated. "frame" matches everything so
191                            that one is used instead of no filter.
192                         */
193                         filter="frame"; 
194                 }
195         } else {
196                 fprintf(stderr, "tethereal: invalid \"-z io,phs[,<filter>]\" argument\n");
197                 exit(1);
198         }
199
200         rs=new_phs_t(NULL);
201
202         if(filter){
203                 rs->filter=g_malloc(strlen(filter)+1);
204                 strcpy(rs->filter, filter);
205         } else {
206                 rs->filter=NULL;
207         }
208
209         error_string=register_tap_listener("frame", rs, filter, NULL, protohierstat_packet, protohierstat_draw);
210         if(error_string){
211                 /* error, we failed to attach to the tap. clean up */
212                 g_free(rs->filter);
213                 g_free(rs);
214
215                 fprintf(stderr, "tethereal: Couldn't register io,phs tap: %s\n",
216                     error_string->str);
217                 g_string_free(error_string, TRUE);
218                 exit(1);
219         }
220 }
221
222
223 void
224 register_tap_listener_protohierstat(void)
225 {
226         register_stat_cmd_arg("io,phs", protohierstat_init, NULL);
227 }
228