Update:
[obnox/wireshark/wip.git] / tap-rtspstat.c
1 /* tap-rtspstat.c
2  * tap-rtspstat   March 2011 
3  *
4  * Stephane GORSE (Orange Labs / France Telecom)
5  * Copied from Jean-Michel FAYARD's works (HTTP)
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <string.h>
34
35 #include "epan/packet_info.h"
36 #include "epan/value_string.h"
37 #include <epan/tap.h>
38 #include <epan/stat_cmd_args.h>
39 #include "register.h"
40 #include <epan/dissectors/packet-rtsp.h>
41
42         
43 /* used to keep track of the statictics for an entire program interface */
44 typedef struct _rtsp_stats_t {
45         char            *filter;
46         GHashTable      *hash_responses;
47         GHashTable      *hash_requests;
48 } rtspstat_t;
49
50 /* used to keep track of the stats for a specific response code
51  * for example it can be { 3, 404, "Not Found" ,...}
52  * which means we captured 3 reply rtsp/1.1 404 Not Found */
53 typedef struct _rtsp_response_code_t {
54         guint32          packets;               /* 3 */
55         guint            response_code; /* 404 */
56         const gchar     *name;                  /* Not Found */
57         rtspstat_t      *sp;
58 } rtsp_response_code_t;
59
60 /* used to keep track of the stats for a specific request string */
61 typedef struct _rtsp_request_methode_t {
62         gchar           *response;      /* eg. : SETUP */
63         guint32          packets;
64         rtspstat_t      *sp;
65 } rtsp_request_methode_t;
66
67
68 /* insert some entries */
69 static void
70 rtsp_init_hash( rtspstat_t *sp)
71 {
72         int i;
73
74         sp->hash_responses = g_hash_table_new( g_int_hash, g_int_equal);                
75                         
76         for (i=0 ; rtsp_status_code_vals[i].strptr ; i++ )
77         {
78                 gint *key = g_malloc (sizeof(gint));
79                 rtsp_response_code_t *sc = g_malloc (sizeof(rtsp_response_code_t));
80                 *key = rtsp_status_code_vals[i].value;
81                 sc->packets=0;
82                 sc->response_code =  *key;
83                 sc->name=rtsp_status_code_vals[i].strptr;
84                 sc->sp = sp;
85                 g_hash_table_insert( sc->sp->hash_responses, key, sc);
86         }
87         sp->hash_requests = g_hash_table_new( g_str_hash, g_str_equal);
88 }
89 static void
90 rtsp_draw_hash_requests( gchar *key _U_ , rtsp_request_methode_t *data, gchar * format)
91 {
92         if (data->packets==0)
93                 return;
94         printf( format, data->response, data->packets);                 
95 }
96
97 static void
98 rtsp_draw_hash_responses( gint * key _U_ , rtsp_response_code_t *data, char * format)
99 {
100         if (data==NULL) {
101                 g_warning("No data available, key=%d\n", *key);
102                 exit(EXIT_FAILURE);
103         }
104         if (data->packets==0)
105                 return;
106         /* "     RTSP %3d %-35s %9d packets", */
107         printf(format,  data->response_code, data->name, data->packets );
108 }
109                 
110
111                 
112 /* NOT USED at this moment */
113 /*
114 static void
115 rtsp_free_hash( gpointer key, gpointer value, gpointer user_data _U_ )
116 {
117         g_free(key);
118         g_free(value);
119 }
120 */
121 static void
122 rtsp_reset_hash_responses(gchar *key _U_ , rtsp_response_code_t *data, gpointer ptr _U_ )
123 {       
124         data->packets = 0;
125 }
126 static void
127 rtsp_reset_hash_requests(gchar *key _U_ , rtsp_request_methode_t *data, gpointer ptr _U_ )
128 {       
129         data->packets = 0;
130 }
131
132 static void
133 rtspstat_reset(void *psp  )
134 {
135         rtspstat_t *sp=psp;
136
137         g_hash_table_foreach( sp->hash_responses, (GHFunc)rtsp_reset_hash_responses, NULL);
138         g_hash_table_foreach( sp->hash_requests, (GHFunc)rtsp_reset_hash_requests, NULL);
139
140 }
141
142 static int
143 rtspstat_packet(void *psp , packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
144 {
145         const rtsp_info_value_t *value=pri;
146         rtspstat_t *sp=(rtspstat_t *) psp;
147
148         /* We are only interested in reply packets with a status code */
149         /* Request or reply packets ? */
150         if (value->response_code!=0) {
151                 guint *key=g_malloc( sizeof(guint) );
152                 rtsp_response_code_t *sc;
153
154                 *key=value->response_code;
155                 sc =  g_hash_table_lookup( 
156                                 sp->hash_responses, 
157                                 key);
158                 if (sc==NULL){
159                         /* non standard status code ; we classify it as others
160                          * in the relevant category (Informational,Success,Redirection,Client Error,Server Error)
161                          */
162                         int i = value->response_code;
163                         if ((i<100) || (i>=600)) {
164                                 return 0;
165                         }
166                         else if (i<200){
167                                 *key=199;       /* Hopefully, this status code will never be used */
168                         }
169                         else if (i<300){
170                                 *key=299;
171                         }
172                         else if (i<400){
173                                 *key=399;
174                         }
175                         else if (i<500){
176                                 *key=499;
177                         }
178                         else{
179                                 *key=599;
180                         }
181                         sc =  g_hash_table_lookup( 
182                                 sp->hash_responses, 
183                                 key);
184                         if (sc==NULL)
185                                 return 0;
186                 }
187                 sc->packets++;
188         } 
189         else if (value->request_method){
190                 rtsp_request_methode_t *sc;
191
192                 sc =  g_hash_table_lookup( 
193                                 sp->hash_requests, 
194                                 value->request_method);
195                 if (sc==NULL){
196                         sc=g_malloc( sizeof(rtsp_request_methode_t) );
197                         sc->response=g_strdup( value->request_method );
198                         sc->packets=1;
199                         sc->sp = sp;
200                         g_hash_table_insert( sp->hash_requests, sc->response, sc);
201                 } else {
202                         sc->packets++;
203                 }
204         } else {
205                 return 0;
206         }
207         return 1;
208 }
209
210
211 static void
212 rtspstat_draw(void *psp  )
213 {
214         rtspstat_t *sp=psp;
215         printf("\n");
216         printf("===================================================================\n");
217         if (! sp->filter[0])
218                 printf("RTSP Statistics\n");
219         else
220                 printf("RTSP Statistics with filter %s\n", sp->filter);
221
222         printf( "* RTSP Status Codes in reply packets\n");
223         g_hash_table_foreach( sp->hash_responses, (GHFunc)rtsp_draw_hash_responses,
224                 "    RTSP %3d %s\n");
225         printf("* List of RTSP Request methods\n");
226         g_hash_table_foreach( sp->hash_requests,  (GHFunc)rtsp_draw_hash_requests,
227                 "    %9s %d \n");
228         printf("===================================================================\n");
229 }
230
231
232
233 /* When called, this function will create a new instance of gtk_rtspstat.
234  */
235 static void
236 gtk_rtspstat_init(const char *optarg,void* userdata _U_)
237 {
238         rtspstat_t *sp;
239         const char *filter=NULL;
240         GString *error_string;
241         
242         if (!strncmp (optarg, "rtsp,stat,", 10)){
243                 filter=optarg+10;
244         } else {
245                 filter=NULL;
246         }
247         
248         sp = g_malloc( sizeof(rtspstat_t) );
249         if(filter){
250                 sp->filter=g_strdup(filter);
251         } else {
252                 sp->filter=NULL;
253         }
254         /*g_hash_table_foreach( rtsp_status, (GHFunc)rtsp_reset_hash_responses, NULL);*/
255
256
257         error_string = register_tap_listener( 
258                         "rtsp",
259                         sp,
260                         filter,
261                         0,
262                         rtspstat_reset,
263                         rtspstat_packet,
264                         rtspstat_draw);
265         if (error_string){
266                 /* error, we failed to attach to the tap. clean up */
267                 g_free(sp->filter);
268                 g_free(sp);
269                 fprintf (stderr, "tshark: Couldn't register rtsp,stat tap: %s\n",
270                                 error_string->str);
271                 g_string_free(error_string, TRUE);
272                 exit(1);
273         }
274
275         rtsp_init_hash(sp);
276 }
277
278 void
279 register_tap_listener_gtkrtspstat(void)
280 {
281         register_stat_cmd_arg("rtsp,stat,", gtk_rtspstat_init,NULL);
282 }