f65280bbbeb0f1867de9bdf986b23bde3b34f6cd
[jlayton/wireshark.git] / ui / cli / tap-wspstat.c
1 /* tap-rpcstat.c
2  * wspstat   2003 Jean-Michel FAYARD
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /* This module provides WSP  statistics to tshark.
24  * It is only used by tshark and not wireshark
25  *
26  */
27
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <glib.h>
35
36 #include <epan/packet_info.h>
37 #include <epan/tap.h>
38 #include <epan/stat_tap_ui.h>
39 #include <epan/value_string.h>
40 #include <epan/dissectors/packet-wsp.h>
41
42 void register_tap_listener_wspstat(void);
43
44 /* used to keep track of the stats for a specific PDU type*/
45 typedef struct _wsp_pdu_t {
46         const gchar     *type;
47         guint32          packets;
48 } wsp_pdu_t;
49 /* used to keep track of SRT statistics */
50 typedef struct _wsp_status_code_t {
51         const gchar     *name;
52         guint32          packets;
53 } wsp_status_code_t;
54 /* used to keep track of the statictics for an entire program interface */
55 typedef struct _wsp_stats_t {
56         char            *filter;
57         wsp_pdu_t       *pdu_stats;
58         guint32 num_pdus;
59         GHashTable      *hash;
60 } wspstat_t;
61
62 static void
63 wsp_reset_hash(gchar *key _U_ , wsp_status_code_t *data, gpointer ptr _U_)
64 {
65         data->packets = 0;
66 }
67 static void
68 wsp_print_statuscode(gint *key, wsp_status_code_t *data, char *format)
69 {
70         if (data && (data->packets != 0))
71                 printf(format, *key, data->packets , data->name);
72 }
73 static void
74 wsp_free_hash_table( gpointer key, gpointer value, gpointer user_data _U_ )
75 {
76         g_free(key);
77         g_free(value);
78 }
79 static void
80 wspstat_reset(void *psp)
81 {
82         wspstat_t *sp = (wspstat_t *)psp;
83         guint32 i;
84
85         for (i=1; i<=sp->num_pdus; i++)
86         {
87                 sp->pdu_stats[i].packets = 0;
88         }
89         g_hash_table_foreach( sp->hash, (GHFunc)wsp_reset_hash, NULL);
90 }
91
92
93 /* This callback is invoked whenever the tap system has seen a packet
94  * we might be interested in.
95  * The function is to be used to only update internal state information
96  * in the *tapdata structure, and if there were state changes which requires
97  * the window to be redrawn, return 1 and (*draw) will be called sometime
98  * later.
99  *
100  * We didn't apply a filter when we registered so we will be called for
101  * ALL packets and not just the ones we are collecting stats for.
102  *
103  */
104 static gint
105 pdut2index(gint pdut)
106 {
107         if (pdut <= 0x09)
108                 return pdut;
109         if (pdut >= 0x40) {
110                 if (pdut <= 0x44) {
111                         return pdut - 54;
112                 } else if (pdut == 0x60 || pdut == 0x61) {
113                         return pdut - 81;
114                 }
115         }
116         return 0;
117 }
118 static gint
119 index2pdut(gint pdut)
120 {
121         if (pdut <= 0x09)
122                 return pdut;
123         if (pdut <= 14)
124                 return pdut + 54;
125         if (pdut <= 16)
126                 return pdut + 81;
127         return 0;
128 }
129 static int
130 wspstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
131 {
132         wspstat_t *sp = (wspstat_t *)psp;
133         const wsp_info_value_t *value = (const wsp_info_value_t *)pri;
134         gint idx = pdut2index(value->pdut);
135         int retour = 0;
136
137         if (value->status_code != 0) {
138                 gint *key = g_new(gint, 1);
139                 wsp_status_code_t *sc;
140                 *key = value->status_code ;
141                 sc = (wsp_status_code_t *)g_hash_table_lookup(
142                                 sp->hash,
143                                 key);
144                 if (!sc) {
145                         sc = g_new(wsp_status_code_t, 1);
146                         sc -> packets = 1;
147                         sc -> name = NULL;
148                         g_hash_table_insert(
149                                 sp->hash,
150                                 key,
151                                 sc);
152                 } else {
153                         sc->packets++;
154                 }
155                 retour = 1;
156         }
157
158
159
160         if (idx != 0) {
161                 sp->pdu_stats[idx].packets++;
162                 retour = 1;
163         }
164         return retour;
165 }
166
167
168 /* This callback is used when tshark wants us to draw/update our
169  * data to the output device. Since this is tshark only output is
170  * stdout.
171  * TShark will only call this callback once, which is when tshark has
172  * finished reading all packets and exists.
173  * If used with wireshark this may be called any time, perhaps once every 3
174  * seconds or so.
175  * This function may even be called in parallell with (*reset) or (*draw)
176  * so make sure there are no races. The data in the rpcstat_t can thus change
177  * beneath us. Beware.
178  */
179 static void
180 wspstat_draw(void *psp)
181 {
182         wspstat_t *sp = (wspstat_t *)psp;
183         guint32 i;
184
185         printf("\n");
186         printf("===================================================================\n");
187         printf("WSP Statistics:\n");
188         printf("%-23s %9s || %-23s %9s\n", "PDU Type", "Packets", "PDU Type", "Packets");
189         for (i=1; i <= ((sp->num_pdus+1)/2); i++)
190         {
191                 guint32 ii = i+sp->num_pdus/2;
192                 printf("%-23s %9u", sp->pdu_stats[i ].type, sp->pdu_stats[i ].packets);
193                 printf(" || ");
194                 if (ii< (sp->num_pdus) )
195                         printf("%-23s %9u\n", sp->pdu_stats[ii].type, sp->pdu_stats[ii].packets);
196                 else
197                         printf("\n");
198                 }
199         printf("\nStatus code in reply packets\n");
200         printf(         "Status Code    Packets  Description\n");
201         g_hash_table_foreach( sp->hash, (GHFunc) wsp_print_statuscode,
202                         (gpointer)"       0x%02X  %9d  %s\n" ) ;
203         printf("===================================================================\n");
204 }
205
206 /* When called, this function will create a new instance of wspstat.
207  * program and version are whick onc-rpc program/version we want to
208  * collect statistics for.
209  * This function is called from tshark when it parses the -z wsp, arguments
210  * and it creates a new instance to store statistics in and registers this
211  * new instance for the wsp tap.
212  */
213 static void
214 wspstat_init(const char *opt_arg, void *userdata _U_)
215 {
216         wspstat_t          *sp;
217         const char         *filter = NULL;
218         guint32             i;
219         gchar              *error_string;
220         wsp_status_code_t  *sc;
221         const value_string *wsp_vals_status_p;
222
223         if (!strncmp (opt_arg, "wsp,stat,", 9)) {
224                 filter = opt_arg+9;
225         } else {
226                 filter = NULL;
227         }
228
229
230         sp = g_new(wspstat_t, 1);
231         sp->hash = g_hash_table_new( g_int_hash, g_int_equal);
232         wsp_vals_status_p = VALUE_STRING_EXT_VS_P(&wsp_vals_status_ext);
233         for (i=0; wsp_vals_status_p[i].strptr; i++ )
234         {
235                 gint *key;
236                 sc = g_new(wsp_status_code_t, 1);
237                 key = g_new(gint, 1);
238                 sc->packets = 0;
239                 sc->name = wsp_vals_status_p[i].strptr;
240                 *key = wsp_vals_status_p[i].value;
241                 g_hash_table_insert(
242                                 sp->hash,
243                                 key,
244                                 sc);
245         }
246         sp->num_pdus = 16;
247         sp->pdu_stats = g_new(wsp_pdu_t, (sp->num_pdus+1));
248         if (filter) {
249                 sp->filter = g_strdup(filter);
250         } else {
251                 sp->filter = NULL;
252         }
253         for (i=0; i<sp->num_pdus; i++)
254         {
255                 sp->pdu_stats[i].packets = 0;
256                 sp->pdu_stats[i].type = try_val_to_str_ext( index2pdut( i ), &wsp_vals_pdu_type_ext) ;
257         }
258
259         error_string = register_tap_listener(
260                         "wsp",
261                         sp,
262                         filter,
263                         0,
264                         wspstat_reset,
265                         wspstat_packet,
266                         wspstat_draw);
267         if (error_string) {
268                 /* error, we failed to attach to the tap. clean up */
269                 g_free(sp->pdu_stats);
270                 g_free(sp->filter);
271                 g_free(sp);
272                 g_hash_table_foreach( sp->hash, (GHFunc) wsp_free_hash_table, NULL ) ;
273                 g_hash_table_destroy( sp->hash );
274                 fprintf(stderr, "tshark: Couldn't register wsp,stat tap: %s\n",
275                                 error_string);
276                 wmem_free(NULL, error_string);
277                 exit(1);
278         }
279 }
280
281 static stat_tap_ui wspstat_ui = {
282         REGISTER_STAT_GROUP_GENERIC,
283         NULL,
284         "wsp,stat",
285         wspstat_init,
286         0,
287         NULL
288 };
289
290 void
291 register_tap_listener_wspstat(void)
292 {
293         register_stat_tap_ui(&wspstat_ui, NULL);
294 }
295
296 /*
297  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
298  *
299  * Local variables:
300  * c-basic-offset: 8
301  * tab-width: 8
302  * indent-tabs-mode: t
303  * End:
304  *
305  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
306  * :indentSize=8:tabSize=8:noTabs=false:
307  */