Include config.h first; it defines _FILE_OFFSET_BITS, and if some system
[metze/wireshark/wip.git] / ui / cli / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 /* This module provides ProtocolHierarchyStatistics for tshark */
26
27 #include "config.h"
28
29 #include <stdio.h>
30
31 #include <string.h>
32 #include "epan/packet_info.h"
33 #include "epan/epan_dissect.h"
34 #include "epan/proto.h"
35 #include <epan/tap.h>
36 #include <epan/stat_cmd_args.h>
37
38 typedef struct _phs_t {
39         struct _phs_t *sibling;
40         struct _phs_t *child;
41         struct _phs_t *parent;
42         char *filter;
43         int protocol;
44         const char *proto_name;
45         guint32 frames;
46         guint64 bytes;
47 } phs_t;
48
49
50 static phs_t *
51 new_phs_t(phs_t *parent)
52 {
53         phs_t *rs;
54         rs=g_new(phs_t,1);
55         rs->sibling=NULL;
56         rs->child=NULL;
57         rs->parent=parent;
58         rs->filter=NULL;
59         rs->protocol=-1;
60         rs->proto_name=NULL;
61         rs->frames=0;
62         rs->bytes=0;
63         return rs;
64 }
65
66
67 static int
68 protohierstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
69 {
70         phs_t *rs=(phs_t *)prs;
71         phs_t *tmprs;
72         proto_node *node;
73         field_info *fi;
74
75         if(!edt){
76                 return 0;
77         }
78         if(!edt->tree){
79                 return 0;
80         }
81         if(!edt->tree->first_child){
82                 return 0;
83         }
84
85         for(node=edt->tree->first_child;node;node=node->next){
86                 fi=PNODE_FINFO(node);
87
88                 /* first time we saw a protocol at this leaf */
89                 if(rs->protocol==-1){
90                         rs->protocol=fi->hfinfo->id;
91                         rs->proto_name=fi->hfinfo->abbrev;
92                         rs->frames=1;
93                         rs->bytes=pinfo->fd->pkt_len;
94                         rs->child=new_phs_t(rs);
95                         rs=rs->child;
96                         continue;
97                 }
98
99                 /* find this protocol in the list of siblings */
100                 for(tmprs=rs;tmprs;tmprs=tmprs->sibling){
101                         if(tmprs->protocol==fi->hfinfo->id){
102                                 break;
103                         }
104                 }
105
106                 /* not found, then we must add it to the end of the list */
107                 if(!tmprs){
108                         for(tmprs=rs;tmprs->sibling;tmprs=tmprs->sibling)
109                                 ;
110                         tmprs->sibling=new_phs_t(rs->parent);
111                         rs=tmprs->sibling;
112                         rs->protocol=fi->hfinfo->id;
113                         rs->proto_name=fi->hfinfo->abbrev;
114                 } else {
115                         rs=tmprs;
116                 }
117
118                 rs->frames++;
119                 rs->bytes+=pinfo->fd->pkt_len;
120
121                 if(!rs->child){
122                         rs->child=new_phs_t(rs);
123                 }
124                 rs=rs->child;
125         }
126         return 1;
127 }
128
129 static void
130 phs_draw(phs_t *rs, int indentation)
131 {
132         int i, stroff;
133 #define MAXPHSLINE 80
134         char str[MAXPHSLINE];
135         for(;rs;rs=rs->sibling){
136                 if(rs->protocol==-1){
137                         return;
138                 }
139                 str[0]=0;
140                 stroff=0;
141                 for(i=0;i<indentation;i++){
142                         if(i>15){
143                                 stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, "...");
144                                 break;
145                         }
146                         stroff+=g_snprintf(str+stroff, MAXPHSLINE-stroff, "  ");
147                 }
148                 g_snprintf(str+stroff, MAXPHSLINE-stroff, "%s", rs->proto_name);
149                 printf("%-40s frames:%d bytes:%" G_GINT64_MODIFIER "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=(phs_t *)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(const char *optarg, void* userdata _U_)
170 {
171         phs_t *rs;
172         int pos=0;
173         const char *filter=NULL;
174         GString *error_string;
175
176         if(strcmp("io,phs",optarg)==0){
177                 /* No arguments */
178         } else if(sscanf(optarg,"io,phs,%n",&pos)==0){
179                 if(pos){
180                         filter=optarg+pos;
181                 }
182         } else {
183                 fprintf(stderr, "tshark: invalid \"-z io,phs[,<filter>]\" argument\n");
184                 exit(1);
185         }
186
187         rs=new_phs_t(NULL);
188
189         if(filter){
190                 rs->filter=g_strdup(filter);
191         } else {
192                 rs->filter=NULL;
193         }
194
195         error_string=register_tap_listener("frame", rs, filter, TL_REQUIRES_PROTO_TREE, NULL, protohierstat_packet, protohierstat_draw);
196         if(error_string){
197                 /* error, we failed to attach to the tap. clean up */
198                 g_free(rs->filter);
199                 g_free(rs);
200
201                 fprintf(stderr, "tshark: Couldn't register io,phs tap: %s\n",
202                     error_string->str);
203                 g_string_free(error_string, TRUE);
204                 exit(1);
205         }
206 }
207
208
209 void
210 register_tap_listener_protohierstat(void)
211 {
212         register_stat_cmd_arg("io,phs", protohierstat_init, NULL);
213 }
214