Fix grammaro, indent example code.
[obnox/wireshark/wip.git] / tap-wspstat.c
1 /* tap-rpcstat.c
2  * wspstat   2003 Jean-Michel FAYARD
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 WSP  statistics to tshark.
26  * It is only used by tshark and not wireshark
27  *
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #include <string.h>
41 #include "epan/packet_info.h"
42 #include <epan/tap.h>
43 #include <epan/stat_cmd_args.h>
44 #include "register.h"
45 #include "epan/value_string.h"
46 #include <epan/dissectors/packet-wsp.h>
47
48 /* used to keep track of the stats for a specific PDU type*/
49 typedef struct _wsp_pdu_t {
50         const gchar     *type;
51         guint32          packets;
52 } wsp_pdu_t;
53 /* used to keep track of RTT statistics */
54 typedef struct _wsp_status_code_t {
55         const gchar     *name;
56         guint32          packets;
57 } wsp_status_code_t;
58 /* used to keep track of the statictics for an entire program interface */
59 typedef struct _wsp_stats_t {
60         char            *filter;
61         wsp_pdu_t       *pdu_stats;
62         guint32 num_pdus;
63         GHashTable      *hash;
64 } wspstat_t;
65         
66 static void
67 wsp_reset_hash(gchar *key _U_ , wsp_status_code_t *data, gpointer ptr _U_ ) 
68 {       
69         data->packets = 0;
70 }
71 static void
72 wsp_print_statuscode(gint *key, wsp_status_code_t *data, char* format)
73 {
74         if (data && (data->packets!=0))
75                 printf(format, *key, data->packets ,data->name);
76 }
77 static void
78 wsp_free_hash_table( gpointer key, gpointer value, gpointer user_data _U_ )
79 {
80         g_free(key);
81         g_free(value);
82 }
83 static void
84 wspstat_reset(void *psp)
85 {
86         wspstat_t *sp=psp;
87         guint32 i;
88
89         for(i=1;i<=sp->num_pdus;i++)
90         {
91                 sp->pdu_stats[i].packets=0;
92         }
93         g_hash_table_foreach( sp->hash, (GHFunc)wsp_reset_hash, NULL);
94 }
95
96
97 /* This callback is invoked whenever the tap system has seen a packet
98  * we might be interested in.
99  * The function is to be used to only update internal state information
100  * in the *tapdata structure, and if there were state changes which requires
101  * the window to be redrawn, return 1 and (*draw) will be called sometime
102  * later.
103  *
104  * We didnt apply a filter when we registered so we will be called for
105  * ALL packets and not just the ones we are collecting stats for.
106  *
107  */
108 static gint 
109 pdut2index(gint pdut)
110 {
111         if (pdut<=0x09)         return pdut;
112         if (pdut>=0x40){
113                 if (pdut <= 0x44){
114                         return pdut-54;
115                 } else if (pdut==0x60||pdut==0x61){
116                         return pdut-81;
117                 }
118         }
119         return 0;
120 }
121 static gint
122 index2pdut(gint pdut)
123 {
124         if (pdut<=0x09)
125                 return pdut;
126         if (pdut<=14)
127                 return pdut+54;
128         if (pdut<=16)
129                 return pdut+81;
130         return 0;
131 }
132 static int
133 wspstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
134 {
135         wspstat_t *sp=psp;
136         const wsp_info_value_t *value=pri;
137         gint idx = pdut2index(value->pdut);
138         int retour=0;
139
140         if (value->status_code != 0) {
141                 gint *key=g_malloc( sizeof(gint) );
142                 wsp_status_code_t *sc;
143                 *key=value->status_code ;
144                 sc = g_hash_table_lookup( 
145                                 sp->hash, 
146                                 key);
147                 if (!sc) {
148                         sc = g_malloc( sizeof(wsp_status_code_t) );
149                         sc -> packets = 1;
150                         sc -> name = NULL;
151                         g_hash_table_insert(
152                                 sp->hash,
153                                 key,
154                                 sc);
155                 } else {
156                         sc->packets++;
157                 }
158                 retour=1;
159         }
160
161                 
162
163         if (idx!=0) {
164                 sp->pdu_stats[ idx ].packets++;
165                 retour = 1;
166         }
167         return retour;
168 }
169
170
171 /* This callback is used when tshark wants us to draw/update our
172  * data to the output device. Since this is tshark only output is
173  * stdout.
174  * TShark will only call this callback once, which is when tshark has
175  * finished reading all packets and exists.
176  * If used with wireshark this may be called any time, perhaps once every 3 
177  * seconds or so.
178  * This function may even be called in parallell with (*reset) or (*draw)
179  * so make sure there are no races. The data in the rpcstat_t can thus change
180  * beneath us. Beware.
181  */
182 static void
183 wspstat_draw(void *psp)
184 {
185         wspstat_t *sp=psp;
186         guint32 i;
187
188         printf("\n");
189         printf("===================================================================\n");
190         printf("WSP Statistics:\n");
191         printf("%-23s %9s || %-23s %9s\n","PDU Type", "Packets", "PDU Type", "Packets");
192         for(i=1; i<= ((sp->num_pdus+1)/2) ; i++)
193         {
194                 guint32 ii=i+sp->num_pdus/2;
195                 printf("%-23s %9d", sp->pdu_stats[i ].type, sp->pdu_stats[i ].packets);
196                 printf(" || ");
197                 if (ii< (sp->num_pdus) )
198                         printf("%-23s %9d\n", sp->pdu_stats[ii].type, sp->pdu_stats[ii].packets);
199                 else 
200                         printf("\n");
201                 }
202         printf("\nStatus code in reply packets\n");
203         printf(         "Status Code    Packets  Description\n");
204         g_hash_table_foreach( sp->hash, (GHFunc) wsp_print_statuscode, 
205                         "       0x%02X  %9d  %s\n" ) ;
206         printf("===================================================================\n");
207 }
208
209 /* When called, this function will create a new instance of wspstat.
210  * program and version are whick onc-rpc program/version we want to
211  * collect statistics for.
212  * This function is called from tshark when it parses the -z wsp, arguments
213  * and it creates a new instance to store statistics in and registers this
214  * new instance for the wsp tap.
215  */
216 static void
217 wspstat_init(const char *optarg, void* userdata _U_)
218 {
219         wspstat_t *sp;
220         const char *filter=NULL;
221         guint32 i;
222         GString *error_string;
223         wsp_status_code_t *sc;
224         
225         if (!strncmp (optarg, "wsp,stat," , 9)){
226                 filter=optarg+9;
227         } else {
228                 filter=NULL;
229         }
230         
231                 
232         sp = g_malloc( sizeof(wspstat_t) );
233         sp->hash = g_hash_table_new( g_int_hash, g_int_equal);
234         for (i=0 ; vals_status[i].strptr ; i++ )
235         {
236                 gint *key;
237                 sc=g_malloc( sizeof(wsp_status_code_t) );
238                 key=g_malloc( sizeof(gint) );
239                 sc->packets=0;
240                 sc->name=vals_status[i].strptr;
241                 *key=vals_status[i].value;
242                 g_hash_table_insert(
243                                 sp->hash,
244                                 key,
245                                 sc);
246         }
247         sp->num_pdus = 16;
248         sp->pdu_stats=g_malloc( (sp->num_pdus+1) * sizeof( wsp_pdu_t) );
249         if(filter){
250                 sp->filter=g_strdup(filter);
251         } else {
252                 sp->filter=NULL;
253         }
254         for (i=0;i<sp->num_pdus; i++)
255         {
256                 sp->pdu_stats[i].packets=0;
257                 sp->pdu_stats[i].type = match_strval( index2pdut( i ), vals_pdu_type) ;
258         }
259
260         error_string = register_tap_listener( 
261                         "wsp",
262                         sp,
263                         filter,
264                         0,
265                         wspstat_reset,
266                         wspstat_packet,
267                         wspstat_draw);
268         if (error_string){
269                 /* error, we failed to attach to the tap. clean up */
270                 g_free(sp->pdu_stats);
271                 g_free(sp->filter);
272                 g_free(sp);
273                 g_hash_table_foreach( sp->hash, (GHFunc) wsp_free_hash_table, NULL ) ;
274                 g_hash_table_destroy( sp->hash );
275                 fprintf(stderr, "tshark: Couldn't register wsp,stat tap: %s\n",
276                                 error_string->str);
277                 g_string_free(error_string, TRUE);
278                 exit(1);
279         }
280 }
281 void 
282 register_tap_listener_wspstat(void)
283 {
284         register_stat_cmd_arg("wsp,stat,", wspstat_init,NULL);
285 }