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
This commit is contained in:
Anders Broman 2011-06-21 12:45:37 +00:00
parent e9e32d7844
commit 4c219ee855
6 changed files with 504 additions and 0 deletions

View File

@ -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 \

View File

@ -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 \

View File

@ -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 );
}

View File

@ -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__ */

View File

@ -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

282
tap-rtspstat.c Normal file
View File

@ -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);
}