Add the abillity to read and write option comments unedited.
[obnox/wireshark/wip.git] / tap-protohierstat.c
1 /* tap-protohierstat.c
2  * protohierstat   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 /* This module provides ProtocolHierarchyStatistics for tshark */
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
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         const char *proto_name;
51         guint32 frames;
52         guint64 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_node *node;
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(node=edt->tree->first_child;node;node=node->next){
92                 fi=PNODE_FINFO(node);
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, stroff;
139 #define MAXPHSLINE 80
140         char str[MAXPHSLINE];
141         for(;rs;rs=rs->sibling){
142                 if(rs->protocol==-1){
143                         return;
144                 }
145                 str[0]=0;
146                 stroff=0;
147                 for(i=0;i<indentation;i++){
148                         if(i>15){
149                                 stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, "...");
150                                 break;
151                         }
152                         stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, "  ");
153                 }
154                 g_snprintf(str+stroff, MAXPHSLINE-stroff, "%s", rs->proto_name);
155                 printf("%-40s frames:%d bytes:%" G_GINT64_MODIFIER "d\n",str, rs->frames, rs->bytes);
156                 phs_draw(rs->child, indentation+1);
157         }
158 }
159
160 static void
161 protohierstat_draw(void *prs)
162 {
163         phs_t *rs=prs;
164
165         printf("\n");
166         printf("===================================================================\n");
167         printf("Protocol Hierarchy Statistics\n");
168         printf("Filter: %s\n\n",rs->filter?rs->filter:"");
169         phs_draw(rs,0);
170         printf("===================================================================\n");
171 }
172
173
174 static void
175 protohierstat_init(const char *optarg, void* userdata _U_)
176 {
177         phs_t *rs;
178         int pos=0;
179         const char *filter=NULL;
180         GString *error_string;
181
182         if(strcmp("io,phs",optarg)==0){
183                 /* No arguments */
184         } else if(sscanf(optarg,"io,phs,%n",&pos)==0){
185                 if(pos){
186                         filter=optarg+pos;
187                 }
188         } else {
189                 fprintf(stderr, "tshark: 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_strdup(filter);
197         } else {
198                 rs->filter=NULL;
199         }
200
201         error_string=register_tap_listener("frame", rs, filter, TL_REQUIRES_PROTO_TREE, NULL, protohierstat_packet, protohierstat_draw);
202         if(error_string){
203                 /* error, we failed to attach to the tap. clean up */
204                 g_free(rs->filter);
205                 g_free(rs);
206
207                 fprintf(stderr, "tshark: Couldn't register io,phs tap: %s\n",
208                     error_string->str);
209                 g_string_free(error_string, TRUE);
210                 exit(1);
211         }
212 }
213
214
215 void
216 register_tap_listener_protohierstat(void)
217 {
218         register_stat_cmd_arg("io,phs", protohierstat_init, NULL);
219 }
220