aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2011-06-21 12:45:37 +0000
committerAnders Broman <anders.broman@ericsson.com>2011-06-21 12:45:37 +0000
commit4c219ee855e8c867f487b072035dfd7687f55e87 (patch)
tree9a4fdf0d4b573658ad73771d19beb05864fbc361
parente9e32d78444c7cde6754b6795c67c6ad229b404e (diff)
From Stéphane Gorse:
The menu gets a new item (Statistics -> RTSP -> Packet Counter). Like HTTP, filter can be set and then the dialog windows shows the result of the RTSP analysis. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6042 svn path=/trunk/; revision=37741
-rw-r--r--Makefile.common1
-rw-r--r--epan/dissectors/Makefile.common1
-rw-r--r--epan/dissectors/packet-rtsp.c179
-rw-r--r--epan/dissectors/packet-rtsp.h40
-rw-r--r--epan/libwireshark.def1
-rw-r--r--tap-rtspstat.c282
6 files changed, 504 insertions, 0 deletions
diff --git a/Makefile.common b/Makefile.common
index f702baea49..88f9440517 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -129,6 +129,7 @@ TSHARK_TAP_SRC = \
tap-rpcstat.c \
tap-rpcprogs.c \
tap-rtp.c \
+ tap-rtspstat.c \
tap-scsistat.c \
tap-sctpchunkstat.c \
tap-sipstat.c \
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
index 50d207a1dd..5e1d8bff54 100644
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -1286,6 +1286,7 @@ DISSECTOR_INCLUDES = \
packet-rtps2.h \
packet-rtp-events.h \
packet-rtse.h \
+ packet-rtsp.h \
packet-rwall.h \
packet-rx.h \
packet-s1ap.h \
diff --git a/epan/dissectors/packet-rtsp.c b/epan/dissectors/packet-rtsp.c
index debbc2e260..2682ccef9a 100644
--- a/epan/dissectors/packet-rtsp.c
+++ b/epan/dissectors/packet-rtsp.c
@@ -48,12 +48,76 @@
#include <epan/emem.h>
#include <epan/tap.h>
#include <epan/tap-voip.h>
+#include <epan/stats_tree.h>
#include <wsutil/str_util.h>
#include "packet-rdt.h"
#include "packet-rtp.h"
#include "packet-rtcp.h"
#include "packet-e164.h"
+#include "packet-rtsp.h"
+
+static int rtsp_tap = -1;
+static rtsp_info_value_t *rtsp_stat_info;
+
+/* http://www.iana.org/assignments/rtsp-parameters/rtsp-parameters.xml */
+
+const value_string rtsp_status_code_vals[] = {
+ { 100, "Continue" },
+ { 199, "Informational - Others" },
+
+ { 200, "OK"},
+ { 201, "Created"},
+ { 250, "Low on Storage Space"},
+ { 299, "Success - Others"},
+
+ { 300, "Multiple Choices"},
+ { 301, "Moved Permanently"},
+ { 302, "Moved Temporarily"},
+ { 303, "See Other"},
+ { 305, "Use Proxy"},
+ { 399, "Redirection - Others"},
+
+ { 400, "Bad Request"},
+ { 401, "Unauthorized"},
+ { 402, "Payment Required"},
+ { 403, "Forbidden"},
+ { 404, "Not Found"},
+ { 405, "Method Not Allowed"},
+ { 406, "Not Acceptable"},
+ { 407, "Proxy Authentication Required"},
+ { 408, "Request Timeout"},
+ { 410, "Gone"},
+ { 411, "Length Required"},
+ { 412, "Precondition Failed"},
+ { 413, "Request Entity Too Large"},
+ { 414, "Request-URI Too Long"},
+ { 415, "Unsupported Media Type"},
+ { 451, "Invalid Parameter"},
+ { 452, "Illegal Conferenec Identifier"},
+ { 453, "Not Enough Bandwidth"},
+ { 454, "Session Not Found"},
+ { 455, "Method Not Valid In This State"},
+ { 456, "Header Field Not Valid"},
+ { 457, "Invalid Range"},
+ { 458, "Parameter Is Read-Only"},
+ { 459, "Aggregate Operation Not Allowed"},
+ { 460, "Only Aggregate Operation Allowed"},
+ { 461, "Unsupported Transport"},
+ { 462, "Destination Unreachable"},
+ { 499, "Client Error - Others"},
+
+ { 500, "Internal Server Error"},
+ { 501, "Not Implemented"},
+ { 502, "Bad Gateway"},
+ { 503, "Service Unavailable"},
+ { 504, "Gateway Timeout"},
+ { 505, "RTSP Version not supported"},
+ { 551, "Option Not Support"},
+ { 599, "Server Error - Others"},
+
+ { 0, NULL}
+};
static int proto_rtsp = -1;
@@ -80,6 +144,90 @@ static dissector_handle_t rtcp_handle;
static dissector_handle_t rdt_handle;
static dissector_table_t media_type_dissector_table;
+static const gchar *st_str_packets = "Total RTSP Packets";
+static const gchar *st_str_requests = "RTSP Request Packets";
+static const gchar *st_str_responses = "RTSP Response Packets";
+static const gchar *st_str_resp_broken = "???: broken";
+static const gchar *st_str_resp_100 = "1xx: Informational";
+static const gchar *st_str_resp_200 = "2xx: Success";
+static const gchar *st_str_resp_300 = "3xx: Redirection";
+static const gchar *st_str_resp_400 = "4xx: Client Error";
+static const gchar *st_str_resp_500 = "5xx: Server Error";
+static const gchar *st_str_other = "Other RTSP Packets";
+
+static int st_node_packets = -1;
+static int st_node_requests = -1;
+static int st_node_responses = -1;
+static int st_node_resp_broken = -1;
+static int st_node_resp_100 = -1;
+static int st_node_resp_200 = -1;
+static int st_node_resp_300 = -1;
+static int st_node_resp_400 = -1;
+static int st_node_resp_500 = -1;
+static int st_node_other = -1;
+
+static void
+rtsp_stats_tree_init(stats_tree* st)
+{
+ st_node_packets = stats_tree_create_node(st, st_str_packets, 0, TRUE);
+ st_node_requests = stats_tree_create_pivot(st, st_str_requests, st_node_packets);
+ st_node_responses = stats_tree_create_node(st, st_str_responses, st_node_packets, TRUE);
+ st_node_resp_broken = stats_tree_create_node(st, st_str_resp_broken, st_node_responses, TRUE);
+ st_node_resp_100 = stats_tree_create_node(st, st_str_resp_100, st_node_responses, TRUE);
+ st_node_resp_200 = stats_tree_create_node(st, st_str_resp_200, st_node_responses, TRUE);
+ st_node_resp_300 = stats_tree_create_node(st, st_str_resp_300, st_node_responses, TRUE);
+ st_node_resp_400 = stats_tree_create_node(st, st_str_resp_400, st_node_responses, TRUE);
+ st_node_resp_500 = stats_tree_create_node(st, st_str_resp_500, st_node_responses, TRUE);
+ st_node_other = stats_tree_create_node(st, st_str_other, st_node_packets,FALSE);
+}
+
+/* RTSP/Packet Counter stats packet function */
+static int
+rtsp_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p)
+{
+ const rtsp_info_value_t* v = p;
+ guint i = v->response_code;
+ int resp_grp;
+ const gchar *resp_str;
+ static gchar str[64];
+
+ tick_stat_node(st, st_str_packets, 0, FALSE);
+
+ if (i) {
+ tick_stat_node(st, st_str_responses, st_node_packets, FALSE);
+
+ if ( (i<100)||(i>=600) ) {
+ resp_grp = st_node_resp_broken;
+ resp_str = st_str_resp_broken;
+ } else if (i<200) {
+ resp_grp = st_node_resp_100;
+ resp_str = st_str_resp_100;
+ } else if (i<300) {
+ resp_grp = st_node_resp_200;
+ resp_str = st_str_resp_200;
+ } else if (i<400) {
+ resp_grp = st_node_resp_300;
+ resp_str = st_str_resp_300;
+ } else if (i<500) {
+ resp_grp = st_node_resp_400;
+ resp_str = st_str_resp_400;
+ } else {
+ resp_grp = st_node_resp_500;
+ resp_str = st_str_resp_500;
+ }
+
+ tick_stat_node(st, resp_str, st_node_responses, FALSE);
+
+ g_snprintf(str, sizeof(str),"%u %s",i,val_to_str(i,rtsp_status_code_vals, "Unknown (%d)"));
+ tick_stat_node(st, str, resp_grp, FALSE);
+ } else if (v->request_method) {
+ stats_tree_tick_pivot(st,st_node_requests,v->request_method);
+ } else {
+ tick_stat_node(st, st_str_other, st_node_packets, FALSE);
+ }
+
+ return 1;
+}
void proto_reg_handoff_rtsp(void);
/*
@@ -298,6 +446,9 @@ static gboolean
is_rtsp_request_or_reply(const guchar *line, size_t linelen, rtsp_type_t *type)
{
unsigned ii;
+ const guchar *next_token;
+ int tokenlen;
+ gchar response_chars[4];
/* Is this an RTSP reply? */
if (linelen >= 5 && g_ascii_strncasecmp("RTSP/", line, 5) == 0) {
@@ -305,6 +456,17 @@ is_rtsp_request_or_reply(const guchar *line, size_t linelen, rtsp_type_t *type)
* Yes.
*/
*type = RTSP_REPLY;
+ /* The first token is the version. */
+ tokenlen = get_token_len(line, line+5, &next_token);
+ if (tokenlen != 0) {
+ /* The next token is the status code. */
+ tokenlen = get_token_len(next_token, line+linelen, &next_token);
+ if (tokenlen >= 3) {
+ memcpy(response_chars, next_token, 3);
+ response_chars[3] = '\0';
+ rtsp_stat_info->response_code = strtoul(response_chars, NULL, 10);
+ }
+ }
return TRUE;
}
@@ -320,6 +482,7 @@ is_rtsp_request_or_reply(const guchar *line, size_t linelen, rtsp_type_t *type)
(len == linelen || isspace(line[len])))
{
*type = RTSP_REQUEST;
+ rtsp_stat_info->request_method = ep_strndup(rtsp_methods[ii], len+1);
return TRUE;
}
}
@@ -559,6 +722,13 @@ dissect_rtspmessage(tvbuff_t *tvb, int offset, packet_info *pinfo,
gchar *session_id = NULL;
voip_packet_info_t *stat_info = NULL;
+ rtsp_stat_info = ep_alloc(sizeof(rtsp_info_value_t));
+ rtsp_stat_info->framenum = pinfo->fd->num;
+ rtsp_stat_info->response_code = 0;
+ rtsp_stat_info->request_method = NULL;
+ rtsp_stat_info->request_uri = NULL;
+ rtsp_stat_info->rtsp_host = NULL;
+
/*
* Is this a request or response?
*
@@ -1097,6 +1267,9 @@ dissect_rtspmessage(tvbuff_t *tvb, int offset, packet_info *pinfo,
*/
offset += datalen;
}
+
+ tap_queue_packet(rtsp_tap, pinfo, rtsp_stat_info);
+
return offset - orig_offset;
}
@@ -1305,6 +1478,10 @@ proto_register_rtsp(void)
"of a request spanning multiple TCP segments",
&rtsp_desegment_body);
+ /*
+ * Register for tapping
+ */
+ rtsp_tap = register_tap("rtsp"); /* RTSP statistics tap */
}
void
@@ -1338,5 +1515,7 @@ proto_reg_handoff_rtsp(void)
saved_rtsp_tcp_port = global_rtsp_tcp_port;
saved_rtsp_tcp_alternate_port = global_rtsp_tcp_alternate_port;
+
+ stats_tree_register("rtsp","rtsp","RTSP/Packet Counter", 0, rtsp_stats_tree_packet, rtsp_stats_tree_init, NULL );
}
diff --git a/epan/dissectors/packet-rtsp.h b/epan/dissectors/packet-rtsp.h
new file mode 100644
index 0000000000..f0d78b3468
--- /dev/null
+++ b/epan/dissectors/packet-rtsp.h
@@ -0,0 +1,40 @@
+/* packet-rtsp.h
+ *
+ * $Id$
+ * Liberally copied from packet-http.h,
+ * by Stephane GORSE (Orange Labs / France Telecom)
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PACKET_RTSP_H__
+#define __PACKET_RTSP_H__
+
+/* Used for RTSP statistics */
+typedef struct _rtsp_info_value_t {
+ guint32 framenum;
+ gchar *request_method;
+ guint response_code;
+ gchar *rtsp_host;
+ gchar *request_uri;
+} rtsp_info_value_t;
+
+WS_VAR_IMPORT const value_string rtsp_status_code_vals[];
+
+#endif /* __PACKET_RTSP_H__ */
diff --git a/epan/libwireshark.def b/epan/libwireshark.def
index b6b1b5fec2..f5cee19fd3 100644
--- a/epan/libwireshark.def
+++ b/epan/libwireshark.def
@@ -930,6 +930,7 @@ rtp_add_address
rtp_free_hash_dyn_payload
rtp_payload_type_short_vals_ext DATA
rtp_payload_type_vals_ext DATA
+rtsp_status_code_vals DATA
running_in_build_directory
rval_to_str
sccp_message_type_acro_values DATA
diff --git a/tap-rtspstat.c b/tap-rtspstat.c
new file mode 100644
index 0000000000..feb8c8bd8e
--- /dev/null
+++ b/tap-rtspstat.c
@@ -0,0 +1,282 @@
+/* tap-rtspstat.c
+ * tap-rtspstat March 2011
+ *
+ * Stephane GORSE (Orange Labs / France Telecom)
+ * Copied from Jean-Michel FAYARD's works (HTTP)
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "epan/packet_info.h"
+#include "epan/value_string.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include "register.h"
+#include <epan/dissectors/packet-rtsp.h>
+
+
+/* used to keep track of the statictics for an entire program interface */
+typedef struct _rtsp_stats_t {
+ char *filter;
+ GHashTable *hash_responses;
+ GHashTable *hash_requests;
+} rtspstat_t;
+
+/* used to keep track of the stats for a specific response code
+ * for example it can be { 3, 404, "Not Found" ,...}
+ * which means we captured 3 reply rtsp/1.1 404 Not Found */
+typedef struct _rtsp_response_code_t {
+ guint32 packets; /* 3 */
+ guint response_code; /* 404 */
+ const gchar *name; /* Not Found */
+ rtspstat_t *sp;
+} rtsp_response_code_t;
+
+/* used to keep track of the stats for a specific request string */
+typedef struct _rtsp_request_methode_t {
+ gchar *response; /* eg. : SETUP */
+ guint32 packets;
+ rtspstat_t *sp;
+} rtsp_request_methode_t;
+
+
+/* insert some entries */
+static void
+rtsp_init_hash( rtspstat_t *sp)
+{
+ int i;
+
+ sp->hash_responses = g_hash_table_new( g_int_hash, g_int_equal);
+
+ for (i=0 ; rtsp_status_code_vals[i].strptr ; i++ )
+ {
+ gint *key = g_malloc (sizeof(gint));
+ rtsp_response_code_t *sc = g_malloc (sizeof(rtsp_response_code_t));
+ *key = rtsp_status_code_vals[i].value;
+ sc->packets=0;
+ sc->response_code = *key;
+ sc->name=rtsp_status_code_vals[i].strptr;
+ sc->sp = sp;
+ g_hash_table_insert( sc->sp->hash_responses, key, sc);
+ }
+ sp->hash_requests = g_hash_table_new( g_str_hash, g_str_equal);
+}
+static void
+rtsp_draw_hash_requests( gchar *key _U_ , rtsp_request_methode_t *data, gchar * format)
+{
+ if (data->packets==0)
+ return;
+ printf( format, data->response, data->packets);
+}
+
+static void
+rtsp_draw_hash_responses( gint * key _U_ , rtsp_response_code_t *data, char * format)
+{
+ if (data==NULL) {
+ g_warning("No data available, key=%d\n", *key);
+ exit(EXIT_FAILURE);
+ }
+ if (data->packets==0)
+ return;
+ /* " RTSP %3d %-35s %9d packets", */
+ printf(format, data->response_code, data->name, data->packets );
+}
+
+
+
+/* NOT USED at this moment */
+/*
+static void
+rtsp_free_hash( gpointer key, gpointer value, gpointer user_data _U_ )
+{
+ g_free(key);
+ g_free(value);
+}
+*/
+static void
+rtsp_reset_hash_responses(gchar *key _U_ , rtsp_response_code_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+static void
+rtsp_reset_hash_requests(gchar *key _U_ , rtsp_request_methode_t *data, gpointer ptr _U_ )
+{
+ data->packets = 0;
+}
+
+static void
+rtspstat_reset(void *psp )
+{
+ rtspstat_t *sp=psp;
+
+ g_hash_table_foreach( sp->hash_responses, (GHFunc)rtsp_reset_hash_responses, NULL);
+ g_hash_table_foreach( sp->hash_requests, (GHFunc)rtsp_reset_hash_requests, NULL);
+
+}
+
+static int
+rtspstat_packet(void *psp , packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri)
+{
+ const rtsp_info_value_t *value=pri;
+ rtspstat_t *sp=(rtspstat_t *) psp;
+
+ /* We are only interested in reply packets with a status code */
+ /* Request or reply packets ? */
+ if (value->response_code!=0) {
+ guint *key=g_malloc( sizeof(guint) );
+ rtsp_response_code_t *sc;
+
+ *key=value->response_code;
+ sc = g_hash_table_lookup(
+ sp->hash_responses,
+ key);
+ if (sc==NULL){
+ /* non standard status code ; we classify it as others
+ * in the relevant category (Informational,Success,Redirection,Client Error,Server Error)
+ */
+ int i = value->response_code;
+ if ((i<100) || (i>=600)) {
+ return 0;
+ }
+ else if (i<200){
+ *key=199; /* Hopefully, this status code will never be used */
+ }
+ else if (i<300){
+ *key=299;
+ }
+ else if (i<400){
+ *key=399;
+ }
+ else if (i<500){
+ *key=499;
+ }
+ else{
+ *key=599;
+ }
+ sc = g_hash_table_lookup(
+ sp->hash_responses,
+ key);
+ if (sc==NULL)
+ return 0;
+ }
+ sc->packets++;
+ }
+ else if (value->request_method){
+ rtsp_request_methode_t *sc;
+
+ sc = g_hash_table_lookup(
+ sp->hash_requests,
+ value->request_method);
+ if (sc==NULL){
+ sc=g_malloc( sizeof(rtsp_request_methode_t) );
+ sc->response=g_strdup( value->request_method );
+ sc->packets=1;
+ sc->sp = sp;
+ g_hash_table_insert( sp->hash_requests, sc->response, sc);
+ } else {
+ sc->packets++;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+
+static void
+rtspstat_draw(void *psp )
+{
+ rtspstat_t *sp=psp;
+ printf("\n");
+ printf("===================================================================\n");
+ if (! sp->filter[0])
+ printf("RTSP Statistics\n");
+ else
+ printf("RTSP Statistics with filter %s\n", sp->filter);
+
+ printf( "* RTSP Status Codes in reply packets\n");
+ g_hash_table_foreach( sp->hash_responses, (GHFunc)rtsp_draw_hash_responses,
+ " RTSP %3d %s\n");
+ printf("* List of RTSP Request methods\n");
+ g_hash_table_foreach( sp->hash_requests, (GHFunc)rtsp_draw_hash_requests,
+ " %9s %d \n");
+ printf("===================================================================\n");
+}
+
+
+
+/* When called, this function will create a new instance of gtk_rtspstat.
+ */
+static void
+gtk_rtspstat_init(const char *optarg,void* userdata _U_)
+{
+ rtspstat_t *sp;
+ const char *filter=NULL;
+ GString *error_string;
+
+ if (!strncmp (optarg, "rtsp,stat,", 10)){
+ filter=optarg+10;
+ } else {
+ filter=NULL;
+ }
+
+ sp = g_malloc( sizeof(rtspstat_t) );
+ if(filter){
+ sp->filter=g_strdup(filter);
+ } else {
+ sp->filter=NULL;
+ }
+ /*g_hash_table_foreach( rtsp_status, (GHFunc)rtsp_reset_hash_responses, NULL);*/
+
+
+ error_string = register_tap_listener(
+ "rtsp",
+ sp,
+ filter,
+ 0,
+ rtspstat_reset,
+ rtspstat_packet,
+ rtspstat_draw);
+ if (error_string){
+ /* error, we failed to attach to the tap. clean up */
+ g_free(sp->filter);
+ g_free(sp);
+ fprintf (stderr, "tshark: Couldn't register rtsp,stat tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+
+ rtsp_init_hash(sp);
+}
+
+void
+register_tap_listener_gtkrtspstat(void)
+{
+ register_stat_cmd_arg("rtsp,stat,", gtk_rtspstat_init,NULL);
+}