diff options
author | guy <guy@f5534014-38df-0310-8fa8-9805f1628bb7> | 2003-09-02 22:47:59 +0000 |
---|---|---|
committer | guy <guy@f5534014-38df-0310-8fa8-9805f1628bb7> | 2003-09-02 22:47:59 +0000 |
commit | fac8d77d0a001c7f5628ab142819d4b5c7539f10 (patch) | |
tree | e4f81d2c0758513eab172c7bbe79d2c773832295 | |
parent | 81178a720701445aa54030ee325f20fdfd70d285 (diff) |
From Jean-Michel Fayard: BOOTP/DHCP, HTTP, and WSP statistics taps.
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@8345 f5534014-38df-0310-8fa8-9805f1628bb7
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | Makefile.am | 7 | ||||
-rw-r--r-- | Makefile.nmake | 7 | ||||
-rw-r--r-- | gtk/Makefile.am | 7 | ||||
-rw-r--r-- | gtk/Makefile.nmake | 7 | ||||
-rw-r--r-- | gtk/bootp_stat.c | 335 | ||||
-rw-r--r-- | gtk/http_stat.c | 579 | ||||
-rw-r--r-- | gtk/wsp_stat.c | 483 | ||||
-rw-r--r-- | packet-bootp.c | 7 | ||||
-rw-r--r-- | packet-http.c | 48 | ||||
-rw-r--r-- | packet-http.h | 8 | ||||
-rw-r--r-- | packet-wsp.c | 24 | ||||
-rw-r--r-- | packet-wsp.h | 12 | ||||
-rw-r--r-- | tap-bootpstat.c | 186 | ||||
-rw-r--r-- | tap-httpstat.c | 329 | ||||
-rw-r--r-- | tap-wspstat.c | 284 |
16 files changed, 2309 insertions, 15 deletions
@@ -1814,6 +1814,7 @@ Vincent Jardin <vincent.jardin [AT] 6wind.com> { Jean-Michel Fayard <jean-michel.fayard [AT] moufrei.de> { Show in Tools:Summary window statistics about packets that passed the current display filter + BOOTP/DHCP, HTTP, and WSP statistics taps } And assorted fixes and enhancements by the people listed above and by: diff --git a/Makefile.am b/Makefile.am index 762c406ccf..bd519c3591 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for Ethereal # -# $Id: Makefile.am,v 1.616 2003/08/29 22:27:14 guy Exp $ +# $Id: Makefile.am,v 1.617 2003/09/02 22:47:56 guy Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs <gerald@ethereal.com> @@ -862,7 +862,9 @@ ethereal_LDADD = \ @PCAP_LIBS@ @GTK_LIBS@ @ADNS_LIBS@ TETHEREAL_TAP_SRC = \ + tap-bootpstat.c \ tap-dcerpcstat.c \ + tap-httpstat.c \ tap-iostat.c \ tap-iousers.c \ tap-mgcpstat.c \ @@ -871,7 +873,8 @@ TETHEREAL_TAP_SRC = \ tap-rpcstat.c \ tap-rpcprogs.c \ tap-smbsids.c \ - tap-smbstat.c + tap-smbstat.c \ + tap-wspstat.c tethereal_SOURCES = \ $(DISSECTOR_SRC) \ diff --git a/Makefile.nmake b/Makefile.nmake index ea2d2df706..6d0cb72dba 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -1,7 +1,7 @@ ## Makefile for building ethereal.exe with Microsoft C and nmake ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake # -# $Id: Makefile.nmake,v 1.329 2003/08/29 22:27:14 guy Exp $ +# $Id: Makefile.nmake,v 1.330 2003/09/02 22:47:56 guy Exp $ include config.nmake include <win32.mak> @@ -383,7 +383,9 @@ DISSECTOR_SRC = \ DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj) TETHEREAL_TAP_SRC = \ + tap-bootpstat.c \ tap-dcerpcstat.c \ + tap-httpstat.c \ tap-iostat.c \ tap-iousers.c \ tap-mgcpstat.c \ @@ -392,7 +394,8 @@ TETHEREAL_TAP_SRC = \ tap-rpcstat.c \ tap-rpcprogs.c \ tap-smbsids.c \ - tap-smbstat.c + tap-smbstat.c \ + tap-wspstat.c TETHEREAL_TAP_OBJECTS = $(TETHEREAL_TAP_SRC:.c=.obj) diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 577be543cc..bffaccc82f 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for the GTK interface routines for Ethereal # -# $Id: Makefile.am,v 1.65 2003/08/29 10:59:12 sahlberg Exp $ +# $Id: Makefile.am,v 1.66 2003/09/02 22:47:58 guy Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs <gerald@ethereal.com> @@ -28,6 +28,7 @@ CLEANFILES = \ *~ ETHEREAL_TAP_SRC = \ + bootp_stat.c \ dcerpc_stat.c \ endpoint_talkers_eth.c \ endpoint_talkers_fc.c \ @@ -38,12 +39,14 @@ ETHEREAL_TAP_SRC = \ endpoint_talkers_tr.c \ endpoint_talkers_udpip.c \ fc_stat.c \ + http_stat.c \ io_stat.c \ mgcp_stat.c \ rpc_stat.c \ rpc_progs.c \ smb_stat.c \ - tap_rtp.c + tap_rtp.c \ + wsp_stat.c ethereal-tap-register.c: $(ETHEREAL_TAP_SRC) $(top_srcdir)/make-tapreg-dotc @echo Making ethereal-tap-register.c diff --git a/gtk/Makefile.nmake b/gtk/Makefile.nmake index 765c4d9c01..766b0e502b 100644 --- a/gtk/Makefile.nmake +++ b/gtk/Makefile.nmake @@ -1,7 +1,7 @@ ## Makefile for building ethereal.exe with Microsoft C and nmake ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake # -# $Id: Makefile.nmake,v 1.50 2003/08/29 10:59:12 sahlberg Exp $ +# $Id: Makefile.nmake,v 1.51 2003/09/02 22:47:58 guy Exp $ include ..\config.nmake @@ -20,6 +20,7 @@ CVARSDLL=-DWIN32 -DNULL=0 -D_MT -D_DLL $(CC) $(CVARSDLL) $(CFLAGS) -Fd.\ -c $< ETHEREAL_TAP_SRC = \ + bootp_stat.c \ dcerpc_stat.c \ endpoint_talkers_eth.c \ endpoint_talkers_fc.c \ @@ -30,12 +31,14 @@ ETHEREAL_TAP_SRC = \ endpoint_talkers_tr.c \ endpoint_talkers_udpip.c \ fc_stat.c \ + http_stat.c \ io_stat.c \ mgcp_stat.c \ rpc_stat.c \ rpc_progs.c \ smb_stat.c \ - tap_rtp.c + tap_rtp.c \ + wsp_stat.c ETHEREAL_TAP_OBJECTS = $(ETHEREAL_TAP_SRC:.c=.obj) diff --git a/gtk/bootp_stat.c b/gtk/bootp_stat.c new file mode 100644 index 0000000000..49c23f4034 --- /dev/null +++ b/gtk/bootp_stat.c @@ -0,0 +1,335 @@ +/* bootp_stat.c + * boop_stat 2003 Jean-Michel FAYARD + * + * $Id: bootp_stat.c,v 1.1 2003/09/02 22:47:58 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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. + */ + +/* #define DEBUG do{ printf("%s:%d ",__FILE__,__LINE__);} while(0); */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gtk/gtk.h> +#include "menu.h" +#include "epan/packet_info.h" +#include "simple_dialog.h" +#include "tap.h" +#include "../register.h" +#include "../globals.h" +#include "compat_macros.h" +#include <string.h> + + +typedef const char* bootp_info_value_t; + +/* used to keep track of the statictics for an entire program interface */ +typedef struct _dhcp_stats_t { + char *filter; + GtkWidget *win; + GHashTable *hash; + GtkWidget *table_message_type; + guint index; /* Number of to display */ +} dhcpstat_t; +/* used to keep track of a single DHCP message type */ +typedef struct _dhcp_message_type_t { + const char *name; + guint32 packets; + GtkWidget *widget;/* label in which we print the number of packets */ + dhcpstat_t *sp; /* entire program interface */ +} dhcp_message_type_t; + +static GtkWidget *dlg=NULL, *dlg_box; +static GtkWidget *filter_box; +static GtkWidget *filter_label, *filter_entry; +static GtkWidget *start_button; + +static void +dhcp_free_hash( gpointer key _U_ , gpointer value, gpointer user_data _U_ ) +{ + g_free(value); +} +static void +dhcp_reset_hash(gchar *key _U_ , dhcp_message_type_t *data, gpointer ptr _U_ ) +{ + data->packets = 0; +} + +/* Update the entry corresponding to the number of packets of a special DHCP Message Type + * or create it if it don't exist. + */ +static void +dhcp_draw_message_type(gchar *key _U_, dhcp_message_type_t *data, gchar * string_buff ) +{ + if ((data==NULL) || (data->packets==0)) + return; + if (data->widget==NULL){ /* create an entry in the table */ + GtkWidget *tmp; + int x = 2*((data->sp->index) % 2); + int y = (data->sp->index) /2; + + + /* Maybe we should display the hexadecimal value ? */ + /* sprintf(string_buff, "%s (0X%x)", data->name, *key); */ + tmp = gtk_label_new( data->name /* string_buff */ ); + gtk_table_attach_defaults(GTK_TABLE(data->sp->table_message_type), tmp, x, x+1, y, y+1); + gtk_label_set_justify(GTK_LABEL(tmp), GTK_JUSTIFY_LEFT); + gtk_widget_show(tmp); + + sprintf( string_buff, "%9d", data->packets ); + data->widget = gtk_label_new( string_buff ); + gtk_table_attach_defaults(GTK_TABLE(data->sp->table_message_type), data->widget, x+1, x+2, y, y+1); + gtk_label_set_justify(GTK_LABEL(data->widget), GTK_JUSTIFY_LEFT); + gtk_widget_show( data->widget ); + + data->sp->index++; + } else { + /* Just update the label string */ + sprintf( string_buff, "%9d", data->packets ); + gtk_label_set( GTK_LABEL(data->widget), string_buff); + } +} +static void +dhcpstat_reset(void *psp) +{ + dhcpstat_t *sp=psp; + g_hash_table_foreach( sp->hash, (GHFunc)dhcp_reset_hash, NULL); +} +static int +dhcpstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *pri) +{ + dhcpstat_t *sp=psp; + bootp_info_value_t value=pri; + dhcp_message_type_t *sc; + + if (sp==NULL) + return 0; + sc = g_hash_table_lookup( + sp->hash, + value); + if (!sc) { + /*g_warning("%s:%d What's Wrong for %s, doc ?", __FILE__, __LINE__, value);*/ + sc = g_malloc( sizeof(dhcp_message_type_t) ); + sc -> packets = 1; + sc -> name = value; + sc -> widget=NULL; + sc -> sp = sp; + g_hash_table_insert( + sp->hash, + (gpointer) value, + sc); + } else { + /*g_warning("sc(%s)->packets++", sc->name);*/ + sc->packets++; + } + return 1; +} + + +static void +dhcpstat_draw(void *psp) +{ + dhcpstat_t *sp=psp; + char str[256]; + guint index; + + index=sp->index; + g_hash_table_foreach( sp->hash, (GHFunc) dhcp_draw_message_type, str ); + if (index != sp->index){ + /* We have inserted a new entry corresponding to a status code , + * let's resize the table */ + gtk_table_resize ( GTK_TABLE(sp->table_message_type), sp->index % 2 , 4); + } + +} + + + +/* since the gtk2 implementation of tap is multithreaded we must protect + * remove_tap_listener() from modifying the list while draw_tap_listener() + * is running. the other protected block is in main.c + * + * there should not be any other critical regions in gtk2 + */ +void protect_thread_critical_region(void); +void unprotect_thread_critical_region(void); +static void +win_destroy_cb(GtkWindow *win _U_, gpointer data) +{ + dhcpstat_t *sp=(dhcpstat_t *)data; + + protect_thread_critical_region(); + remove_tap_listener(sp); + unprotect_thread_critical_region(); + + g_free(sp->filter); + g_hash_table_foreach( sp->hash, (GHFunc)dhcp_free_hash, NULL); + g_hash_table_destroy( sp->hash); + g_free(sp); +} + + + +/* When called, this function will create a new instance of gtk2-dhcpstat. + */ +static void +gtk_dhcpstat_init(char *optarg) +{ + dhcpstat_t *sp; + char *filter=NULL; + char *title=NULL; + GString *error_string; + GtkWidget *message_type_fr ; + + if (!strncmp (optarg, "bootp,stat,", 11)){ + filter=optarg+11; + } else { + filter=NULL; + } + + sp = g_malloc( sizeof(dhcpstat_t) ); + sp->hash = g_hash_table_new( g_str_hash, g_str_equal); + if(filter){ + sp->filter=g_malloc(strlen(filter)+1); + strcpy(sp->filter,filter); + title=g_strdup_printf("DHCP Stats with filter: %s", filter); + } else { + sp->filter=NULL; + title=g_strdup("DHCP Stats"); + } + + sp->win = gtk_window_new( GTK_WINDOW_TOPLEVEL); + gtk_window_set_title( GTK_WINDOW(sp->win), title ); + g_free(title); + SIGNAL_CONNECT( sp->win, "destroy", win_destroy_cb, sp); + + + /* Status Codes frame */ + message_type_fr = gtk_frame_new("DHCP Message Type"); + gtk_container_add(GTK_CONTAINER(sp->win), message_type_fr); + gtk_widget_show(message_type_fr); + + sp->table_message_type = gtk_table_new( 0, 4, FALSE); + gtk_table_set_col_spacings( GTK_TABLE(sp->table_message_type), 10); + gtk_container_add( GTK_CONTAINER( message_type_fr), sp->table_message_type); + gtk_container_set_border_width( GTK_CONTAINER(sp->table_message_type) , 10); + sp->index = 0; /* Nothing to display yet */ + + + error_string = register_tap_listener( + "bootp", + sp, + filter, + dhcpstat_reset, + dhcpstat_packet, + dhcpstat_draw); + if (error_string){ + /* error, we failed to attach to the tap. clean up */ + simple_dialog( ESD_TYPE_WARN, NULL, error_string->str ); + g_free(sp->filter); + g_free(sp); + g_string_free(error_string, TRUE); + return ; + } + if (dlg){ + gtk_widget_destroy( dlg ); + } + gtk_widget_show_all( sp->win ); + redissect_packets(&cfile); +} + + + +static void +dhcp_start_button_clicked(GtkWidget *item _U_, gpointer data _U_) +{ + char *filter; + char str[256]; + + filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry)); + if(filter[0]==0){ + gtk_dhcpstat_init("dhcp,stat,"); + } else { + sprintf(str, "dhcp,stat,%s", filter); + gtk_dhcpstat_init(str); + } +} + +static void +dlg_destroy_cb(void) +{ + dlg=NULL; +} + +static void +gtk_dhcpstat_cb(GtkWidget *w _U_, gpointer d _U_) +{ + /* if the window is already open, bring it to front */ + if(dlg){ + gdk_window_raise(dlg->window); + return; + } + + dlg=gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(dlg), "WSP Statistics"); + SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL); + dlg_box=gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(dlg), dlg_box); + gtk_widget_show(dlg_box); + + + /* filter box */ + filter_box=gtk_hbox_new(FALSE, 10); + /* Filter label */ + gtk_container_set_border_width(GTK_CONTAINER(filter_box), 10); + filter_label=gtk_label_new("Filter:"); + gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0); + gtk_widget_show(filter_label); + + filter_entry=gtk_entry_new_with_max_length(250); + gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, FALSE, FALSE, 0); + gtk_widget_show(filter_entry); + + gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0); + gtk_widget_show(filter_box); + + + /* the start button */ + start_button=gtk_button_new_with_label("Create Stat"); + SIGNAL_CONNECT_OBJECT(start_button, "clicked", + dhcp_start_button_clicked, NULL); + gtk_box_pack_start(GTK_BOX(dlg_box), start_button, TRUE, TRUE, 0); + gtk_widget_show(start_button); + + gtk_widget_show_all(dlg); +} + + +void +register_tap_listener_gtkdhcpstat(void) +{ + register_ethereal_tap("bootp,stat,", gtk_dhcpstat_init); +} + +void +register_tap_menu_gtkdhcpstat(void) +{ + register_tap_menu_item("Watch protocol/BOOTP-DHCP", gtk_dhcpstat_cb); +} diff --git a/gtk/http_stat.c b/gtk/http_stat.c new file mode 100644 index 0000000000..94277d21c1 --- /dev/null +++ b/gtk/http_stat.c @@ -0,0 +1,579 @@ +/* http_stat.c + * http_stat 2003 Jean-Michel FAYARD + * + * $Id: http_stat.c,v 1.1 2003/09/02 22:47:59 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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 <gtk/gtk.h> +#include "menu.h" +#include "epan/packet_info.h" +#include "simple_dialog.h" +#include "tap.h" +#include "../register.h" +#include "../globals.h" +#include "compat_macros.h" +#include "../packet-http.h" +#include <string.h> + + +/* used to keep track of the statictics for an entire program interface */ +typedef struct _http_stats_t { + char *filter; + GtkWidget *win; + GHashTable *hash_responses; + GHashTable *hash_requests; + guint32 packets; /* number of http packets, including HTTP continuation */ + GtkWidget *packets_label; + + GtkWidget *request_box; /* container for GET, ... */ + + GtkWidget *informational_table; /* Status code between 100 and 199 */ + GtkWidget *success_table; /* 200 and 299 */ + GtkWidget *redirection_table; /* 300 and 399 */ + GtkWidget *client_error_table; /* 400 and 499 */ + GtkWidget *server_errors_table; /* 500 and 599 */ +} httpstat_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 http/1.1 404 Not Found */ +typedef struct _http_response_methode_t { + guint32 packets; /* 3 */ + guint response_method; /* 404 */ + gchar *name; /* Not Found */ + GtkWidget *widget; /* Label where we display it */ + GtkWidget *table; /* Table in which we put it, e.g. client_error_box */ + httpstat_t *sp; +} http_response_methode_t; +/* used to keep track of the stats for a specific request string */ +typedef struct _http_request_methode_t { + gchar *response; /* eg. : GET */ + guint32 packets; + GtkWidget *widget; + httpstat_t *sp; +} http_request_methode_t; + +static GtkWidget *dlg=NULL, *dlg_box; +static GtkWidget *filter_box; +static GtkWidget *filter_label, *filter_entry; +static GtkWidget *start_button; + +static const value_string vals_status_code[] = { + { 100, "Continue" }, + { 101, "Switching Protocols" }, + { 199, "Informational - Others" }, + + { 200, "OK"}, + { 201, "Created"}, + { 202, "Accepted"}, + { 203, "Non-authoritative Information"}, + { 204, "No Content"}, + { 205, "Reset Content"}, + { 206, "Partial Content"}, + { 299, "Success - Others"}, /* used to keep track of others Success packets */ + + { 300, "Multiple Choices"}, + { 301, "Moved Permanently"}, + { 302, "Moved Temporarily"}, + { 303, "See Other"}, + { 304, "Not Modified"}, + { 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 Time-out"}, + { 409, "Conflict"}, + { 410, "Gone"}, + { 411, "Length Required"}, + { 412, "Precondition Failed"}, + { 413, "Request Entity Too Large"}, + { 414, "Request-URI Too Large"}, + { 415, "Unsupported Media Type"}, + { 499, "Client Error - Others"}, + + { 500, "Internal Server Error"}, + { 501, "Not Implemented"}, + { 502, "Bad Gateway"}, + { 503, "Service Unavailable"}, + { 504, "Gateway Time-out"}, + { 505, "HTTP Version not supported"}, + { 599, "Server Error - Others"}, + + { 0, NULL} +} ; + +/* insert some entries */ +static void +http_init_hash( httpstat_t *sp) +{ + int i; + + sp->hash_responses = g_hash_table_new( g_int_hash, g_int_equal); + + for (i=0 ; vals_status_code[i].strptr ; i++ ) + { + gint *key = g_malloc (sizeof(gint)); + http_response_methode_t *sc = g_malloc (sizeof(http_response_methode_t)); + *key = vals_status_code[i].value; + sc->packets=0; + sc->response_method = *key; + sc->name=vals_status_code[i].strptr; + sc->widget=NULL; + sc->table=NULL; + 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 +http_draw_hash_requests( gchar *key _U_ , http_request_methode_t *data, gchar * string_buff) +{ + if (data->packets==0) + return; + sprintf(string_buff, " %-11s : %3d packets", data->response, data->packets); + if (data->widget==NULL){ + data->widget=gtk_label_new( string_buff ); + gtk_misc_set_alignment(GTK_MISC(data->widget), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(data->sp->request_box), data->widget,FALSE,FALSE, 0); + gtk_widget_show(data->widget); + } else { + gtk_label_set( GTK_LABEL(data->widget), string_buff); + } +} + + +static void +http_draw_hash_responses( gint * key _U_ , http_response_methode_t *data, gchar * string_buff) +{ + if (data==NULL) + g_warning("C'est quoi ce borderl key=%d\n", *key); + if (data->packets==0) + return; + /*sprintf(string_buff, "%d packets %d:%s", data->packets, data->response_method, data->name); */ + if (data->widget==NULL){ /* create an entry in the relevant box of the window */ + guint16 x; + GtkWidget *tmp; + guint i = data->response_method; + + if ( (i<100)||(i>=600) ) + return; + if (i<200) + data->table = data->sp->informational_table; + else if (i<300) + data->table = data->sp->success_table; + else if (i<400) + data->table = data->sp->redirection_table; + else if (i<500) + data->table = data->sp->client_error_table; + else + data->table = data->sp->server_errors_table; + x=GTK_TABLE( data->table)->nrows; + + sprintf(string_buff, "HTTP %3d %s ", data->response_method, data->name ); + tmp = gtk_label_new( string_buff ); + + gtk_table_attach_defaults( GTK_TABLE(data->table), tmp, 0,1, x, x+1); + gtk_label_set_justify( GTK_LABEL(tmp), GTK_JUSTIFY_LEFT); + gtk_widget_show( tmp ); + + sprintf(string_buff, "%9d", data->packets); + data->widget=gtk_label_new( string_buff); + + gtk_table_attach_defaults( GTK_TABLE(data->table), data->widget, 1, 2,x,x+1); + gtk_label_set_justify( GTK_LABEL(data->widget), GTK_JUSTIFY_RIGHT); + gtk_widget_show( data->widget ); + + gtk_table_resize( GTK_TABLE(data->table), x+1, 4); + + } else { + /* Just update the label string */ + sprintf(string_buff, "%9d", data->packets ); + gtk_label_set( GTK_LABEL(data->widget), string_buff); + } +} + + + +static void +http_free_hash( gpointer key, gpointer value, gpointer user_data _U_ ) +{ + g_free(key); + g_free(value); +} +static void +http_reset_hash_responses(gchar *key _U_ , http_response_methode_t *data, gpointer ptr _U_ ) +{ + data->packets = 0; +} +static void +http_reset_hash_requests(gchar *key _U_ , http_request_methode_t *data, gpointer ptr _U_ ) +{ + data->packets = 0; +} + +static void +httpstat_reset(void *psp ) +{ + httpstat_t *sp=psp; + if (!sp) { + g_hash_table_foreach( sp->hash_responses, (GHFunc)http_reset_hash_responses, NULL); + g_hash_table_foreach( sp->hash_responses, (GHFunc)http_reset_hash_requests, NULL); + } +} + +static int +httpstat_packet(void *psp , packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *pri) +{ + http_info_value_t *value=pri; + httpstat_t *sp=(httpstat_t *) psp; + + /* total number of packets, including HTTP continuation packets */ + sp->packets++; + + /* We are only interested in reply packets with a status code */ + /* Request or reply packets ? */ + if (value->response_method!=0) { + guint *key=g_malloc( sizeof(guint) ); + http_response_methode_t *sc; + + *key=value->response_method ; + 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_method; + 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){ + http_request_methode_t *sc; + + sc = g_hash_table_lookup( + sp->hash_requests, + value->request_method); + if (sc==NULL){ + sc=g_malloc( sizeof(http_request_methode_t) ); + sc->response=g_strdup( value->request_method ); + sc->packets=1; + sc->widget=NULL; + sc->sp = sp; + g_hash_table_insert( sp->hash_requests, sc->response, sc); + } else { + sc->packets++; + } + /* g_free( value->request_method ); */ + } else { + return 0; + } + return 1; +} + + +#define SUM_STR_MAX 1024 +static void +httpstat_draw(void *psp ) +{ + gchar string_buff[SUM_STR_MAX]; + httpstat_t *sp=psp; + + sprintf( string_buff, "HTTP stats (%d packets)", sp->packets); + gtk_label_set( GTK_LABEL(sp->packets_label), string_buff); + g_hash_table_foreach( sp->hash_responses, (GHFunc)http_draw_hash_responses, string_buff); + g_hash_table_foreach( sp->hash_requests, (GHFunc)http_draw_hash_requests, string_buff); +} + + +/* since the gtk2 implementation of tap is multithreaded we must protect + * remove_tap_listener() from modifying the list while draw_tap_listener() + * is running. the other protected block is in main.c + * + * there should not be any other critical regions in gtk2 + */ +void protect_thread_critical_region(void); +void unprotect_thread_critical_region(void); +static void +win_destroy_cb(GtkWindow *win _U_, gpointer data) +{ + httpstat_t *sp=(httpstat_t *)data; + + protect_thread_critical_region(); + remove_tap_listener(sp); + unprotect_thread_critical_region(); + + g_hash_table_foreach( sp->hash_responses, (GHFunc)http_free_hash, NULL); + g_hash_table_destroy( sp->hash_responses); + g_hash_table_foreach( sp->hash_requests, (GHFunc)http_free_hash, NULL); + g_hash_table_destroy( sp->hash_requests); + g_free(sp->filter); + g_free(sp); +} + + +/* When called, this function will create a new instance of gtk_httpstat. + */ +static void +gtk_httpstat_init(char *optarg) +{ + httpstat_t *sp; + char *filter=NULL; + char *title=NULL; + GString *error_string; + GtkWidget *main_vb, *separator, + *informational_fr, *success_fr, *redirection_fr, + *client_errors_fr, *server_errors_fr, *request_fr; + + if (!strncmp (optarg, "http,stat,", 10)){ + filter=optarg+10; + } else { + filter=NULL; + } + + sp = g_malloc( sizeof(httpstat_t) ); + if(filter){ + sp->filter=g_malloc(strlen(filter)+1); + strcpy(sp->filter,filter); + title=g_strdup_printf("HTTP Stats with filter: %s", filter); + } else { + sp->filter=NULL; + title=g_strdup("HTTP Stats"); + } + + /* top level window */ + sp->win = gtk_window_new( GTK_WINDOW_TOPLEVEL); + gtk_window_set_title( GTK_WINDOW(sp->win), title ); + g_free(title); + SIGNAL_CONNECT( sp->win, "destroy", win_destroy_cb, sp); + + /* container for each group of status code */ + main_vb = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(main_vb), 10); + gtk_container_add(GTK_CONTAINER(sp->win), main_vb); + gtk_widget_show(main_vb); + + /* number of packets */ + sp->packets=0; + sp->packets_label = gtk_label_new("HTTP stats (0 HTTP packets)"); + gtk_container_add( GTK_CONTAINER(main_vb), sp->packets_label); + gtk_widget_show(sp->packets_label); + + /* Informational response frame */ + informational_fr = gtk_frame_new("Informational HTTP 1xx"); + gtk_container_add(GTK_CONTAINER(main_vb), informational_fr); + gtk_widget_show(informational_fr); + + sp->informational_table = gtk_table_new( 0, 2, FALSE); + gtk_container_add(GTK_CONTAINER(informational_fr), sp->informational_table); + gtk_widget_show(sp->informational_table); + + + /* success response frame */ + success_fr = gtk_frame_new ("Success HTTP 2xx"); + gtk_container_add(GTK_CONTAINER(main_vb), success_fr); + gtk_widget_show(success_fr); + + sp->success_table = gtk_table_new( 0, 2, FALSE); + gtk_container_add(GTK_CONTAINER(success_fr), sp->success_table); + gtk_widget_show(sp->success_table); + + + /* redirection response frame */ + redirection_fr = gtk_frame_new ("Redirection HTTP 3xx"); + gtk_container_add(GTK_CONTAINER(main_vb), redirection_fr); + gtk_widget_show(redirection_fr); + + sp->redirection_table = gtk_table_new( 0, 2, FALSE); + gtk_container_add(GTK_CONTAINER(redirection_fr), sp->redirection_table); + gtk_widget_show(sp->redirection_table); + + + /* client_errors response frame */ + client_errors_fr = gtk_frame_new("Client errors HTTP 4xx"); + gtk_container_add(GTK_CONTAINER(main_vb), client_errors_fr); + gtk_widget_show(client_errors_fr); + + sp->client_error_table = gtk_table_new( 0, 2, FALSE); + gtk_container_add(GTK_CONTAINER(client_errors_fr), sp->client_error_table); + gtk_widget_show(sp->client_error_table); + + + /* server_errors response frame */ + server_errors_fr = gtk_frame_new("Server errors HTTP 5xx"); + gtk_container_add(GTK_CONTAINER(main_vb), server_errors_fr); + gtk_widget_show(server_errors_fr); + + sp->server_errors_table = gtk_table_new( 0, 2, FALSE); + gtk_container_add(GTK_CONTAINER(server_errors_fr), sp->server_errors_table); + gtk_widget_show(sp->server_errors_table); + + + separator = gtk_hseparator_new(); + gtk_container_add(GTK_CONTAINER(main_vb), separator ); + + /* request response frame */ + request_fr = gtk_frame_new("List of request methods"); + gtk_container_add(GTK_CONTAINER(main_vb), request_fr); + gtk_container_border_width(GTK_CONTAINER(request_fr), 0); + gtk_widget_show(request_fr); + + sp->request_box = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(request_fr), sp->request_box); + gtk_widget_show(sp->request_box); + + error_string = register_tap_listener( + "http", + sp, + filter, + httpstat_reset, + httpstat_packet, + httpstat_draw); + if (error_string){ + /* error, we failed to attach to the tap. clean up */ + simple_dialog( ESD_TYPE_WARN, NULL, error_string->str ); + g_free(sp->filter); + g_free(sp); + g_string_free(error_string, TRUE); + return ; + } + if (dlg) + { + gtk_widget_destroy( dlg ); + } + + gtk_widget_show_all( sp->win ); + http_init_hash(sp); + redissect_packets(&cfile); +} + + + +static void +httpstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_) +{ + char *filter; + char str[256]; + + filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry)); + if(filter[0]==0){ + gtk_httpstat_init("http,stat,"); + } else { + sprintf(str, "http,stat,%s", filter); + gtk_httpstat_init(str); + } +} + +static void +dlg_destroy_cb(void) +{ + dlg=NULL; +} + +static void +gtk_httpstat_cb(GtkWidget *w _U_, gpointer d _U_) +{ + /* if the window is already open, bring it to front */ + if(dlg){ + gdk_window_raise(dlg->window); + return; + } + + dlg=gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(dlg), "HTTP Statistics"); + SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL); + dlg_box=gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(dlg), dlg_box); + gtk_widget_show(dlg_box); + + + /* filter box */ + filter_box=gtk_hbox_new(FALSE, 10); + /* Filter label */ + gtk_container_set_border_width(GTK_CONTAINER(filter_box), 10); + filter_label=gtk_label_new("Filter:"); + gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0); + gtk_widget_show(filter_label); + + filter_entry=gtk_entry_new_with_max_length(250); + gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, FALSE, FALSE, 0); + gtk_widget_show(filter_entry); + + gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0); + gtk_widget_show(filter_box); + + + /* the start button */ + start_button=gtk_button_new_with_label("Create Stat"); + SIGNAL_CONNECT_OBJECT(start_button, "clicked", + httpstat_start_button_clicked, NULL); + gtk_box_pack_start(GTK_BOX(dlg_box), start_button, TRUE, TRUE, 0); + gtk_widget_show(start_button); + + gtk_widget_show_all(dlg); +} + + +void +register_tap_listener_gtkhttpstat(void) +{ + register_ethereal_tap("http,stat,", gtk_httpstat_init); +} + +void +register_tap_menu_gtkhttpstat(void) +{ + register_tap_menu_item("Watch protocol/HTTP", gtk_httpstat_cb); +} diff --git a/gtk/wsp_stat.c b/gtk/wsp_stat.c new file mode 100644 index 0000000000..db5a8ea1dd --- /dev/null +++ b/gtk/wsp_stat.c @@ -0,0 +1,483 @@ +/* wsp_stat.c + * wsp_stat 2003 Jean-Michel FAYARD + * + * $Id: wsp_stat.c,v 1.1 2003/09/02 22:47:59 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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. + */ + +/* #define DEBUG do{ printf("%s:%d ",__FILE__,__LINE__);} while(0); */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gtk/gtk.h> +#include "menu.h" +#include "epan/packet_info.h" +#include "simple_dialog.h" +#include "tap.h" +#include "../register.h" +#include "../globals.h" +#include "compat_macros.h" +#include "../packet-wsp.h" +#include <string.h> + +/* used to keep track of the stats for a specific PDU type*/ +typedef struct _wsp_pdu_t { + GtkLabel *widget; + guint32 packets; +} wsp_pdu_t; + +/* used to keep track of the statictics for an entire program interface */ +typedef struct _wsp_stats_t { + char *filter; + wsp_pdu_t *pdu_stats; + guint32 num_pdus; + GtkWidget *win; + GHashTable *hash; + GtkWidget *table_pdu_types; + GtkWidget *table_status_code; + guint index; /* Number of status code to display */ +} wspstat_t; +/* used to keep track of a single type of status code */ +typedef struct _wsp_status_code_t { + gchar *name; + guint32 packets; + GtkWidget *widget;/* label in which we print the number of packets */ + wspstat_t *sp; /* entire program interface */ +} wsp_status_code_t; + +static GtkWidget *dlg=NULL, *dlg_box; +static GtkWidget *filter_box; +static GtkWidget *filter_label, *filter_entry; +static GtkWidget *start_button; + +static void +wsp_free_hash( gpointer key, gpointer value, gpointer user_data _U_ ) +{ + g_free(key); + g_free(value); +} +static void +wsp_reset_hash(gchar *key _U_ , wsp_status_code_t *data, gpointer ptr _U_ ) +{ + data->packets = 0; +} + +/* Update the entry corresponding to the number of packets of a special status code + * or create it if it don't exist. + */ +static void +wsp_draw_statuscode(gchar *key _U_, wsp_status_code_t *data, gchar * string_buff ) +{ + if ((data==NULL) || (data->packets==0)) + return; + if (data->widget==NULL){ /* create an entry in the table */ + GtkWidget *tmp; + int x = 2*((data->sp->index) % 2); + int y = (data->sp->index) /2; + + + /* Maybe we should display the hexadecimal value ? */ + /* sprintf(string_buff, "%s (0X%x)", data->name, *key); */ + tmp = gtk_label_new( data->name /* string_buff */ ); + gtk_table_attach_defaults(GTK_TABLE(data->sp->table_status_code), tmp, x, x+1, y, y+1); + gtk_label_set_justify(GTK_LABEL(tmp), GTK_JUSTIFY_LEFT); + gtk_widget_show(tmp); + + sprintf( string_buff, "%9d", data->packets ); + data->widget = gtk_label_new( string_buff ); + gtk_table_attach_defaults(GTK_TABLE(data->sp->table_status_code), data->widget, x+1, x+2, y, y+1); + gtk_label_set_justify(GTK_LABEL(data->widget), GTK_JUSTIFY_LEFT); + gtk_widget_show( data->widget ); + + data->sp->index++; + } else { + /* Just update the label string */ + sprintf( string_buff, "%9d", data->packets ); + gtk_label_set( GTK_LABEL(data->widget), string_buff); + } +} +static void +wspstat_reset(void *psp) +{ + wspstat_t *sp=psp; + guint32 i; + + for(i=1;i<=sp->num_pdus;i++) + { + sp->pdu_stats[i].packets=0; + } + g_hash_table_foreach( sp->hash, (GHFunc)wsp_reset_hash, NULL); +} +static gint +pdut2index(gint pdut) +{ + if (pdut<=0x09) return pdut; + if (pdut>=0x40){ + if (pdut <= 0x44){ + return pdut-54; + } else if (pdut==0x60||pdut==0x61){ + return pdut-81; + } + } + return 0; +} +static gint +index2pdut(gint pdut) +{ + if (pdut<=0x09) + return pdut; + if (pdut<=14) + return pdut+54; + if (pdut<=16) + return pdut+81; + return 0; +} + +static int +wspstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *pri) +{ + wspstat_t *sp=psp; + wsp_info_value_t *value=pri; + gint index = pdut2index(value->pdut); + int retour=0; + + if (value->status_code != 0) { + gint *key=g_malloc( sizeof(gint) ); + wsp_status_code_t *sc; + *key=value->status_code ; + sc = g_hash_table_lookup( + sp->hash, + key); + if (!sc) { + g_warning("%s:%d What's Wrong, doc ?\n", __FILE__, __LINE__); + sc = g_malloc( sizeof(wsp_status_code_t) ); + sc -> packets = 1; + sc -> name = NULL; + sc -> widget=NULL; + sc -> sp = sp; + g_hash_table_insert( + sp->hash, + key, + sc); + } else { + sc->packets++; + } + retour=1; + } + + + + if (index!=0) { + sp->pdu_stats[ index ].packets++; + retour = 1; + } + return retour; + +} + + + +static void +wspstat_draw(void *psp) +{ + wspstat_t *sp=psp; + guint32 i; + char str[256]; + guint index; + + for(i=1;i<=sp->num_pdus ; i++) + { + sprintf(str, "%9d", sp->pdu_stats[i ].packets); + gtk_label_set( GTK_LABEL(sp->pdu_stats[i].widget), str); + } + + index=sp->index; + g_hash_table_foreach( sp->hash, (GHFunc) wsp_draw_statuscode, str ); + if (index != sp->index){ + /* We have inserted a new entry corresponding to a status code , + * let's resize the table */ + gtk_table_resize ( GTK_TABLE(sp->table_status_code), sp->index % 2 , 4); + } + +} + + + +/* since the gtk2 implementation of tap is multithreaded we must protect + * remove_tap_listener() from modifying the list while draw_tap_listener() + * is running. the other protected block is in main.c + * + * there should not be any other critical regions in gtk2 + */ +void protect_thread_critical_region(void); +void unprotect_thread_critical_region(void); +static void +win_destroy_cb(GtkWindow *win _U_, gpointer data) +{ + wspstat_t *sp=(wspstat_t *)data; + + protect_thread_critical_region(); + remove_tap_listener(sp); + unprotect_thread_critical_region(); + + g_free(sp->pdu_stats); + g_free(sp->filter); + g_hash_table_foreach( sp->hash, (GHFunc)wsp_free_hash, NULL); + g_hash_table_destroy( sp->hash); + g_free(sp); +} + +static void +add_table_entry(wspstat_t *sp, char *str, int x, int y, int index) +{ + GtkWidget *tmp; + + tmp=gtk_label_new( str ); + gtk_table_attach_defaults(GTK_TABLE(sp->table_pdu_types), tmp, x, x+1, y, y+1); + gtk_label_set_justify(GTK_LABEL(tmp), GTK_JUSTIFY_LEFT); + gtk_widget_show(tmp); + if (index != 0) { + sp->pdu_stats [index] .widget = GTK_LABEL( tmp ) ; + } +} + + +static void +wsp_init_table(wspstat_t *sp) +{ + int pos=0; + guint32 i; + /* gchar buffer[51]; */ + + add_table_entry( sp, "PDU Type " , 0, pos, 0); + add_table_entry( sp, "packets " , 1, pos, 0); + add_table_entry( sp, "PDU Type " , 2, pos, 0); + add_table_entry( sp, "packets " , 3, pos, 0); + pos++; + for (i=1 ; i <= sp->num_pdus ; i++ ) + { + int x = 0; + if (i> (sp->num_pdus+1) /2 ){ + x=2; + } + /* Maybe we should display the hexadecimal value ? */ + /* snprintf(buffer, 50, "%s (0X%x)", match_strval( index2pdut( i ), vals_pdu_type), index2pdut(i) );*/ + add_table_entry( sp, + match_strval(index2pdut(i), vals_pdu_type), /* or buffer, */ + x, + pos, + 0 + ); + add_table_entry( sp, "0", x+1, pos + , i /* keep a pointer to this widget to update it in _draw() */ + ); + pos++; + if (i== (sp->num_pdus+1) /2) { + pos=1; + } + } +} + +/* When called, this function will create a new instance of gtk2-wspstat. + */ +static void +gtk_wspstat_init(char *optarg) +{ + wspstat_t *sp; + char *filter=NULL; + char *title=NULL; + GString *error_string; + GtkWidget *main_vb, *pdutypes_fr, *statuscode_fr ; + guint32 i; + wsp_status_code_t *sc; + + + if (!strncmp (optarg, "wsp,stat,", 9)){ + filter=optarg+9; + } else { + filter=NULL; + } + + sp = g_malloc( sizeof(wspstat_t) ); + sp->hash = g_hash_table_new( g_int_hash, g_int_equal); + for (i=0 ; vals_status[i].strptr ; i++ ) + { + gint *key; + sc=g_malloc( sizeof(wsp_status_code_t) ); + key=g_malloc( sizeof(gint) ); + sc->name=vals_status[i].strptr; + sc->packets=0; + sc->widget=NULL; + sc->sp = sp; + *key=vals_status[i].value; + g_hash_table_insert( + sp->hash, + key, + sc); + } + sp->num_pdus = 16; + sp->pdu_stats=g_malloc( (sp->num_pdus+1) * sizeof( wsp_pdu_t) ); + if(filter){ + sp->filter=g_malloc(strlen(filter)+1); + strcpy(sp->filter,filter); + title=g_strdup_printf("WSP Stats with filter: %s", filter); + } else { + sp->filter=NULL; + title=g_strdup("WSP Stats"); + } + for (i=0;i<=sp->num_pdus; i++) + { + sp->pdu_stats[i].packets=0; + } + + sp->win = gtk_window_new( GTK_WINDOW_TOPLEVEL); + gtk_window_set_title( GTK_WINDOW(sp->win), title ); + g_free(title); + SIGNAL_CONNECT( sp->win, "destroy", win_destroy_cb, sp); + + + /* container for the two frames */ + main_vb = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(main_vb), 10); + gtk_container_add(GTK_CONTAINER(sp->win), main_vb); + gtk_widget_show(main_vb); + + /* PDU Types frame */ + pdutypes_fr = gtk_frame_new("Summary of PDU Types (wsp.pdu_type)"); + gtk_container_add(GTK_CONTAINER(main_vb), pdutypes_fr); + gtk_widget_show(pdutypes_fr); + + sp->table_pdu_types = gtk_table_new( (sp->num_pdus+1) / 2 + 1, 4, FALSE); + gtk_container_add( GTK_CONTAINER( pdutypes_fr), sp->table_pdu_types); + gtk_container_set_border_width( GTK_CONTAINER(sp->table_pdu_types) , 10); + + wsp_init_table(sp); + gtk_widget_show( sp->table_pdu_types ); + + /* Status Codes frame */ + statuscode_fr = gtk_frame_new("Summary of Status Code (wsp.reply.status)"); + gtk_container_add(GTK_CONTAINER(main_vb), statuscode_fr); + gtk_widget_show(statuscode_fr); + + sp->table_status_code = gtk_table_new( 0, 4, FALSE); + gtk_container_add( GTK_CONTAINER( statuscode_fr), sp->table_status_code); + gtk_container_set_border_width( GTK_CONTAINER(sp->table_status_code) , 10); + sp->index = 0; /* No answers to display yet */ + + + error_string = register_tap_listener( + "wsp", + sp, + filter, + wspstat_reset, + wspstat_packet, + wspstat_draw); + if (error_string){ + /* error, we failed to attach to the tap. clean up */ + simple_dialog( ESD_TYPE_WARN, NULL, error_string->str ); + g_free(sp->pdu_stats); + g_free(sp->filter); + g_free(sp); + g_string_free(error_string, TRUE); + return ; + } + gtk_widget_show_all( sp->win ); + redissect_packets(&cfile); +} + + + +static void +wspstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_) +{ + char *filter; + char str[256]; + + filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry)); + if(filter[0]==0){ + gtk_wspstat_init("wsp,stat,"); + } else { + sprintf(str, "wsp,stat,%s", filter); + gtk_wspstat_init(str); + } +} + +static void +dlg_destroy_cb(void) +{ + dlg=NULL; +} + +static void +gtk_wspstat_cb(GtkWidget *w _U_, gpointer d _U_) +{ + /* if the window is already open, bring it to front */ + if(dlg){ + gdk_window_raise(dlg->window); + return; + } + + dlg=gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(dlg), "WSP Statistics"); + SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL); + dlg_box=gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(dlg), dlg_box); + gtk_widget_show(dlg_box); + + + /* filter box */ + filter_box=gtk_hbox_new(FALSE, 10); + /* Filter label */ + gtk_container_set_border_width(GTK_CONTAINER(filter_box), 10); + filter_label=gtk_label_new("Filter:"); + gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0); + gtk_widget_show(filter_label); + + filter_entry=gtk_entry_new_with_max_length(250); + gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, FALSE, FALSE, 0); + gtk_widget_show(filter_entry); + + gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0); + gtk_widget_show(filter_box); + + + /* the start button */ + start_button=gtk_button_new_with_label("Create Stat"); + SIGNAL_CONNECT_OBJECT(start_button, "clicked", + wspstat_start_button_clicked, NULL); + gtk_box_pack_start(GTK_BOX(dlg_box), start_button, TRUE, TRUE, 0); + gtk_widget_show(start_button); + + gtk_widget_show_all(dlg); +} + + +void +register_tap_listener_gtkwspstat(void) +{ + register_ethereal_tap("wsp,stat,", gtk_wspstat_init); +} + +void +register_tap_menu_gtkwspstat(void) +{ + register_tap_menu_item("Watch protocol/WAP-WSP", gtk_wspstat_cb); +} diff --git a/packet-bootp.c b/packet-bootp.c index f2ffe15305..e14acfcf47 100644 --- a/packet-bootp.c +++ b/packet-bootp.c @@ -2,7 +2,7 @@ * Routines for BOOTP/DHCP packet disassembly * Gilbert Ramirez <gram@alumni.rice.edu> * - * $Id: packet-bootp.c,v 1.74 2003/07/29 00:35:55 guy Exp $ + * $Id: packet-bootp.c,v 1.75 2003/09/02 22:47:57 guy Exp $ * * The information used comes from: * RFC 951: Bootstrap Protocol @@ -46,6 +46,9 @@ #include <epan/packet.h> #include "packet-arp.h" +#include "tap.h" + +static int bootp_dhcp_tap = -1; static int proto_bootp = -1; static int hf_bootp_type = -1; static int hf_bootp_hw_type = -1; @@ -1341,6 +1344,7 @@ dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) if (tree) proto_tree_add_boolean_hidden(bp_tree, hf_bootp_dhcp, tvb, 0, 0, 1); + tap_queue_packet( bootp_dhcp_tap, pinfo, (gpointer) dhcp_type); } /* @@ -1475,6 +1479,7 @@ proto_register_bootp(void) "bootp"); proto_register_field_array(proto_bootp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + bootp_dhcp_tap = register_tap("bootp"); } void diff --git a/packet-http.c b/packet-http.c index 80d8232585..f326994dd6 100644 --- a/packet-http.c +++ b/packet-http.c @@ -6,7 +6,7 @@ * Copyright 2002, Tim Potter <tpot@samba.org> * Copyright 1999, Andrew Tridgell <tridge@samba.org> * - * $Id: packet-http.c,v 1.65 2003/06/11 04:25:30 guy Exp $ + * $Id: packet-http.c,v 1.66 2003/09/02 22:47:57 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -48,12 +48,17 @@ typedef enum _http_type { HTTP_OTHERS } http_type_t; +#include "tap.h" + +static int http_tap = -1; + static int proto_http = -1; static int hf_http_notification = -1; static int hf_http_response = -1; static int hf_http_request = -1; static int hf_http_basic = -1; static int hf_http_request_method = -1; +static int hf_http_response_method = -1; static gint ett_http = -1; static gint ett_http_ntlmssp = -1; @@ -91,6 +96,7 @@ static heur_dissector_list_t heur_subdissector_list; static dissector_handle_t ntlmssp_handle=NULL; + /* Return a tvb that contains the binary representation of a base64 string */ @@ -189,6 +195,8 @@ check_auth(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo, return FALSE; } +/* TODO: remove this ugly global variable */ +http_info_value_t *stat_info; static void dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { @@ -210,6 +218,10 @@ dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) int req_strlen; proto_tree *req_tree; + stat_info =g_malloc( sizeof(http_info_value_t)); + stat_info->response_method = 0; + stat_info->request_method = NULL; + switch (pinfo->match_port) { case TCP_PORT_SSDP: /* TCP_PORT_SSDP = UDP_PORT_SSDP */ @@ -429,6 +441,8 @@ dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) http_tree); } } + + tap_queue_packet( http_tap, pinfo, stat_info) ; } /* This can be used to dissect an HTTP request until such time @@ -440,6 +454,18 @@ basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int req_strlen) { proto_tree_add_item(tree, hf_http_request_method, tvb, 0, req_strlen, FALSE); } +static void +response_method_request_dissector(tvbuff_t *tvb, proto_tree *tree, int req_strlen _U_ ) +{ + const guchar *data; + int minor, major, status_code; + data = tvb_get_ptr(tvb, 0, 12); + if (sscanf(data, "HTTP/%d.%d %d", &minor, &major, &status_code)==3) + { + proto_tree_add_uint(tree, hf_http_response_method, tvb, 9, 3, status_code); + stat_info->response_method = status_code; + } +} /* @@ -473,8 +499,14 @@ is_http_request_or_reply(const guchar *data, int linelen, http_type_t *type, * SEARCH */ if (linelen >= 5 && strncmp(data, "HTTP/", 5) == 0) { + *type = HTTP_RESPONSE; isHttpRequestOrReply = TRUE; /* response */ + if (req_dissector && (linelen >= 12) ) + { + *req_dissector = response_method_request_dissector ; + *req_strlen = 3; + } else if (req_dissector) { *req_dissector = NULL; /* no dissector for this yet. */ } @@ -587,6 +619,12 @@ is_http_request_or_reply(const guchar *data, int linelen, http_type_t *type, *req_dissector = basic_request_dissector; *req_strlen = index + prefix_len; } + if (isHttpRequestOrReply && req_dissector) { + if (!stat_info->request_method) + stat_info->request_method = g_malloc( index+1 ); + strncpy( stat_info->request_method, data, index); + stat_info->request_method[index] = '\0'; + } } return isHttpRequestOrReply; @@ -615,6 +653,10 @@ proto_register_http(void) { "Request Method", "http.request.method", FT_STRING, BASE_NONE, NULL, 0x0, "HTTP Request Method", HFILL }}, + { &hf_http_response_method, + { "Response Method", "http.response.method", + FT_UINT16, BASE_DEC, NULL, 0x0, + "HTTP Response Method", HFILL }}, }; static gint *ett[] = { &ett_http, @@ -650,6 +692,10 @@ proto_register_http(void) register_heur_dissector_list("http",&heur_subdissector_list); + /* + * Register for tapping + */ + http_tap = register_tap("http"); } /* diff --git a/packet-http.h b/packet-http.h index 962687431d..82918d3fca 100644 --- a/packet-http.h +++ b/packet-http.h @@ -1,6 +1,6 @@ /* packet-http.h * - * $Id: packet-http.h,v 1.7 2002/08/28 21:00:16 jmayer Exp $ + * $Id: packet-http.h,v 1.8 2003/09/02 22:47:57 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -23,7 +23,13 @@ #ifndef __PACKET_HTTP_H__ #define __PACKET_HTTP_H__ +#include <epan/packet.h> void http_dissector_add(guint32 port, dissector_handle_t handle); +typedef struct _http_info_value_t +{ + guint response_method; + gchar *request_method; +} http_info_value_t ; #endif diff --git a/packet-wsp.c b/packet-wsp.c index a3f3204773..6cdf046a2a 100644 --- a/packet-wsp.c +++ b/packet-wsp.c @@ -2,7 +2,7 @@ * * Routines to dissect WSP component of WAP traffic. * - * $Id: packet-wsp.c,v 1.74 2003/08/04 23:36:12 guy Exp $ + * $Id: packet-wsp.c,v 1.75 2003/09/02 22:47:57 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -47,6 +47,10 @@ #include "packet-wap.h" #include "packet-wsp.h" +/* Statistics (see doc/README.tapping) */ +#include "tap.h" +static int wsp_tap = -1; + /* File scoped variables for the protocol and registered fields */ static int proto_wsp = HF_EMPTY; @@ -221,7 +225,7 @@ static dissector_handle_t wtp_fromudp_handle; /* Handle for WBXML dissector */ static dissector_handle_t wbxml_handle; -static const value_string vals_pdu_type[] = { +const value_string vals_pdu_type[] = { { 0x00, "Reserved" }, { 0x01, "Connect" }, { 0x02, "ConnectReply" }, @@ -288,7 +292,7 @@ static const value_string vals_pdu_type[] = { }; -static const value_string vals_status[] = { +const value_string vals_status[] = { /* 0x00 - 0x0F Reserved */ { 0x10, "Continue" }, @@ -1282,6 +1286,10 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *wsp_tree = NULL; /* proto_tree *wsp_header_fixed; */ + wsp_info_value_t *stat_info; + stat_info = g_malloc( sizeof(wsp_info_value_t) ); + stat_info->status_code = 0; + /* This field shows up as the "Info" column in the display; you should make it, if possible, summarize what's in the packet, so that a user looking at the list of packets can tell what type of packet it is. */ @@ -1473,6 +1481,7 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, if (tree) { reply_status = tvb_get_guint8(tvb, offset); ti = proto_tree_add_item (wsp_tree, hf_wsp_header_status,tvb,offset,1,bo_little_endian); + stat_info->status_code = (gint) tvb_get_guint8( tvb, offset); if (check_col(pinfo->cinfo, COL_INFO)) { /* Append status code to INFO column */ col_append_fstr(pinfo->cinfo, COL_INFO, ": \"0x%02x %s\"", reply_status, @@ -1554,6 +1563,8 @@ dissect_wsp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, break; } + stat_info->pdut = pdut ; + tap_queue_packet (wsp_tap, pinfo, stat_info); } /* @@ -5214,6 +5225,11 @@ proto_register_wsp(void) < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ > */ ); + wsp_tap = register_tap("wsp"); + /* Init the hash table */ +/* wsp_sessions = g_hash_table_new( + (GHashFunc) wsp_session_hash, + (GEqualFunc)wsp_session_equal);*/ /* Required function calls to register the header fields and subtrees used */ proto_register_field_array(proto_wsp, hf, array_length(hf)); @@ -5227,6 +5243,8 @@ proto_register_wsp(void) wsp_fromudp_handle = create_dissector_handle(dissect_wsp_fromudp, proto_wsp); + + }; void diff --git a/packet-wsp.h b/packet-wsp.h index 3874059dce..503558b29a 100644 --- a/packet-wsp.h +++ b/packet-wsp.h @@ -2,7 +2,7 @@ * * Declarations for disassembly of WSP component of WAP traffic. * - * $Id: packet-wsp.h,v 1.7 2003/07/08 18:10:39 guy Exp $ + * $Id: packet-wsp.h,v 1.8 2003/09/02 22:47:58 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -45,10 +45,20 @@ * assumed to be WSP */ extern const value_string vals_wsp_reason_codes[]; +/* These are exported to taps. */ +extern const value_string vals_pdu_type[]; +extern const value_string vals_status[]; + /* * exported functionality */ void add_post_data (proto_tree *, tvbuff_t *, guint, const char *); guint add_content_type (proto_tree *, tvbuff_t *, guint, guint *, const char **); +/* statistics */ +typedef struct _wsp_info_value_t /* see README.tapping and tap-wspstat.c */ +{ + gint status_code; + guint8 pdut; +} wsp_info_value_t; #endif /* packet-wsp.h */ diff --git a/tap-bootpstat.c b/tap-bootpstat.c new file mode 100644 index 0000000000..effb401156 --- /dev/null +++ b/tap-bootpstat.c @@ -0,0 +1,186 @@ +/* tap-bootpstat.c + * boop_stat 2003 Jean-Michel FAYARD + * + * $Id: tap-bootpstat.c,v 1.1 2003/09/02 22:47:58 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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 "epan/packet_info.h" +#include "tap.h" +#include "register.h" +#include <string.h> + + +typedef const char* bootp_info_value_t; + +/* used to keep track of the statictics for an entire program interface */ +typedef struct _dhcp_stats_t { + char *filter; + GHashTable *hash; + guint index; /* Number of to display */ +} dhcpstat_t; +/* used to keep track of a single DHCP message type */ +typedef struct _dhcp_message_type_t { + const char *name; + guint32 packets; + dhcpstat_t *sp; /* entire program interface */ +} dhcp_message_type_t; + + +/* Not used anywhere at this moment */ +/* +static void +dhcp_free_hash( gpointer key _U_ , gpointer value, gpointer user_data _U_ ) +{ + g_free(value); +} +*/ + +static void +dhcp_reset_hash(gchar *key _U_ , dhcp_message_type_t *data, gpointer ptr _U_ ) +{ + data->packets = 0; +} + +/* Update the entry corresponding to the number of packets of a special DHCP Message Type + * or create it if it don't exist. + */ +static void +dhcp_draw_message_type(gchar *key _U_, dhcp_message_type_t *data, gchar * format ) +{ + if ((data==NULL) || (data->packets==0)) + return; + printf( format, data->name, data->packets); +} +static void +dhcpstat_reset(void *psp) +{ + dhcpstat_t *sp=psp; + g_hash_table_foreach( sp->hash, (GHFunc)dhcp_reset_hash, NULL); +} +static int +dhcpstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *pri) +{ + dhcpstat_t *sp=psp; + bootp_info_value_t value=pri; + dhcp_message_type_t *sc; + + if (sp==NULL) + return 0; + sc = g_hash_table_lookup( + sp->hash, + value); + if (!sc) { + sc = g_malloc( sizeof(dhcp_message_type_t) ); + sc -> packets = 1; + sc -> name = value; + sc -> sp = sp; + g_hash_table_insert( + sp->hash, + (gpointer) value, + sc); + } else { + /*g_warning("sc(%s)->packets++", sc->name);*/ + sc->packets++; + } + return 1; +} + + +static void +dhcpstat_draw(void *psp) +{ + dhcpstat_t *sp=psp; + + printf("\n"); + printf("===================================================================\n"); + + if (sp->filter==NULL) + printf("BOOTP Statistics\n"); + else + printf("BOOTP Statistics with filter %s\n", sp->filter); + printf("BOOTP Option 53: DHCP Messages Types:\n"); + printf("DHCP Message Type Packets nb\n" ); + g_hash_table_foreach( sp->hash, (GHFunc) dhcp_draw_message_type, + "%23s %-9d\n" ); + printf("===================================================================\n"); + +} + + + + +/* When called, this function will create a new instance of tap-boopstat. + */ +static void +dhcpstat_init(char *optarg) +{ + dhcpstat_t *sp; + char *filter=NULL; + GString *error_string; + + if (!strncmp (optarg, "bootp,stat,", 11)){ + filter=optarg+11; + } else { + filter=NULL; + } + + sp = g_malloc( sizeof(dhcpstat_t) ); + sp->hash = g_hash_table_new( g_str_hash, g_str_equal); + if(filter){ + sp->filter=g_malloc(strlen(filter)+1); + strcpy(sp->filter,filter); + } else { + sp->filter=NULL; + } + sp->index = 0; /* Nothing to display yet */ + + error_string = register_tap_listener( + "bootp", + sp, + filter, + dhcpstat_reset, + dhcpstat_packet, + dhcpstat_draw); + if (error_string){ + /* error, we failed to attach to the tap. clean up */ + g_free(sp->filter); + g_free(sp); + fprintf(stderr, "tethereal: Couldn't register dhcp,stat tap: %s\n", + error_string->str); + g_string_free(error_string, TRUE); + exit(1); + } +} + + + +void +register_tap_listener_gtkdhcpstat(void) +{ + register_ethereal_tap("bootp,stat,", dhcpstat_init); +} + diff --git a/tap-httpstat.c b/tap-httpstat.c new file mode 100644 index 0000000000..e03101c590 --- /dev/null +++ b/tap-httpstat.c @@ -0,0 +1,329 @@ +/* tap-httpstat.c + * tap-httpstat 2003 Jean-Michel FAYARD + * + * $Id: tap-httpstat.c,v 1.1 2003/09/02 22:47:58 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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 "epan/packet_info.h" +#include "epan/value_string.h" +#include "tap.h" +#include "register.h" +#include "packet-http.h" +#include <string.h> + + +/* used to keep track of the statictics for an entire program interface */ +typedef struct _http_stats_t { + char *filter; + GHashTable *hash_responses; + GHashTable *hash_requests; +} httpstat_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 http/1.1 404 Not Found */ +typedef struct _http_response_methode_t { + guint32 packets; /* 3 */ + guint response_method; /* 404 */ + gchar *name; /* Not Found */ + httpstat_t *sp; +} http_response_methode_t; +/* used to keep track of the stats for a specific request string */ +typedef struct _http_request_methode_t { + gchar *response; /* eg. : GET */ + guint32 packets; + httpstat_t *sp; +} http_request_methode_t; + + +static const value_string vals_status_code[] = { + { 100, "Continue" }, + { 101, "Switching Protocols" }, + { 199, "Informational - Others" }, + + { 200, "OK"}, + { 201, "Created"}, + { 202, "Accepted"}, + { 203, "Non-authoritative Information"}, + { 204, "No Content"}, + { 205, "Reset Content"}, + { 206, "Partial Content"}, + { 299, "Success - Others"}, /* used to keep track of others Success packets */ + + { 300, "Multiple Choices"}, + { 301, "Moved Permanently"}, + { 302, "Moved Temporarily"}, + { 303, "See Other"}, + { 304, "Not Modified"}, + { 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 Time-out"}, + { 409, "Conflict"}, + { 410, "Gone"}, + { 411, "Length Required"}, + { 412, "Precondition Failed"}, + { 413, "Request Entity Too Large"}, + { 414, "Request-URI Too Large"}, + { 415, "Unsupported Media Type"}, + { 499, "Client Error - Others"}, + + { 500, "Internal Server Error"}, + { 501, "Not Implemented"}, + { 502, "Bad Gateway"}, + { 503, "Service Unavailable"}, + { 504, "Gateway Time-out"}, + { 505, "HTTP Version not supported"}, + { 599, "Server Error - Others"}, + + { 0, NULL} +} ; + +/* insert some entries */ +static void +http_init_hash( httpstat_t *sp) +{ + int i; + + sp->hash_responses = g_hash_table_new( g_int_hash, g_int_equal); + + for (i=0 ; vals_status_code[i].strptr ; i++ ) + { + gint *key = g_malloc (sizeof(gint)); + http_response_methode_t *sc = g_malloc (sizeof(http_response_methode_t)); + *key = vals_status_code[i].value; + sc->packets=0; + sc->response_method = *key; + sc->name=vals_status_code[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 +http_draw_hash_requests( gchar *key _U_ , http_request_methode_t *data, gchar * format) +{ + if (data->packets==0) + return; + printf( format, data->response, data->packets); +} + +static void +http_draw_hash_responses( gint * key _U_ , http_response_methode_t *data, char * format) +{ + if (data==NULL){ + g_warning("C'est quoi ce borderl key=%d\n", *key); + exit(EXIT_FAILURE); + } + if (data->packets==0) + return; + /* " HTTP %3d %-35s %9d packets", */ + printf(format, data->response_method, data->name, data->packets ); +} + + + +/* NOT USED at this moment */ +/* +static void +http_free_hash( gpointer key, gpointer value, gpointer user_data _U_ ) +{ + g_free(key); + g_free(value); +} +*/ +static void +http_reset_hash_responses(gchar *key _U_ , http_response_methode_t *data, gpointer ptr _U_ ) +{ + data->packets = 0; +} +static void +http_reset_hash_requests(gchar *key _U_ , http_request_methode_t *data, gpointer ptr _U_ ) +{ + data->packets = 0; +} + +static void +httpstat_reset(void *psp ) +{ + httpstat_t *sp=psp; + if (!sp) { + g_hash_table_foreach( sp->hash_responses, (GHFunc)http_reset_hash_responses, NULL); + g_hash_table_foreach( sp->hash_responses, (GHFunc)http_reset_hash_requests, NULL); + } +} + +static int +httpstat_packet(void *psp , packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *pri) +{ + http_info_value_t *value=pri; + httpstat_t *sp=(httpstat_t *) psp; + + /* We are only interested in reply packets with a status code */ + /* Request or reply packets ? */ + if (value->response_method!=0) { + guint *key=g_malloc( sizeof(guint) ); + http_response_methode_t *sc; + + *key=value->response_method ; + 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_method; + 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){ + http_request_methode_t *sc; + + sc = g_hash_table_lookup( + sp->hash_requests, + value->request_method); + if (sc==NULL){ + sc=g_malloc( sizeof(http_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 +httpstat_draw(void *psp ) +{ + httpstat_t *sp=psp; + printf("\n"); + printf("===================================================================\n"); + if (! sp->filter[0]) + printf("HTTP Statistics\n"); + else + printf("HTTP Statistics with filter %s\n", sp->filter); + + printf( "* HTTP Status Codes in reply packets\n"); + g_hash_table_foreach( sp->hash_responses, (GHFunc)http_draw_hash_responses, + " HTTP %3d %s\n"); + printf("* List of HTTP Request methods\n"); + g_hash_table_foreach( sp->hash_requests, (GHFunc)http_draw_hash_requests, + " %9s %d \n"); + printf("===================================================================\n"); +} + + + +/* When called, this function will create a new instance of gtk_httpstat. + */ +static void +gtk_httpstat_init(char *optarg) +{ + httpstat_t *sp; + char *filter=NULL; + GString *error_string; + + if (!strncmp (optarg, "http,stat,", 10)){ + filter=optarg+10; + } else { + filter=NULL; + } + + sp = g_malloc( sizeof(httpstat_t) ); + if(filter){ + sp->filter=g_malloc(strlen(filter)+1); + strcpy(sp->filter,filter); + } else { + sp->filter=NULL; + } + /*g_hash_table_foreach( http_status, (GHFunc)http_reset_hash_responses, NULL);*/ + + + error_string = register_tap_listener( + "http", + sp, + filter, + httpstat_reset, + httpstat_packet, + httpstat_draw); + if (error_string){ + /* error, we failed to attach to the tap. clean up */ + g_free(sp->filter); + g_free(sp); + fprintf (stderr, "tethereal: Coulnd't register http,stat tap: %s\n", + error_string->str); + g_string_free(error_string, TRUE); + exit(1); + } + + http_init_hash(sp); +} + +void +register_tap_listener_gtkhttpstat(void) +{ + register_ethereal_tap("http,stat,", gtk_httpstat_init); +} diff --git a/tap-wspstat.c b/tap-wspstat.c new file mode 100644 index 0000000000..6700244288 --- /dev/null +++ b/tap-wspstat.c @@ -0,0 +1,284 @@ +/* tap-rpcstat.c + * wspstat 2003 Jean-Michel FAYARD + * + * $Id: tap-wspstat.c,v 1.1 2003/09/02 22:47:58 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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. + */ + +/* This module provides WSP statistics to tethereal. + * It is only used by tethereal and not ethereal + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <string.h> +#include "epan/packet_info.h" +#include "tap.h" +#include "register.h" +#include "epan/value_string.h" +#include "packet-wsp.h" + +/* used to keep track of the stats for a specific PDU type*/ +typedef struct _wsp_pdu_t { + gchar *type; + guint32 packets; +} wsp_pdu_t; +/* used to keep track of RTT statistics */ +typedef struct _wsp_status_code_t { + gchar *name; + guint32 packets; +} wsp_status_code_t; +/* used to keep track of the statictics for an entire program interface */ +typedef struct _wsp_stats_t { + char *filter; + wsp_pdu_t *pdu_stats; + guint32 num_pdus; + GHashTable *hash; +} wspstat_t; + +static void +wsp_reset_hash(gchar *key _U_ , wsp_status_code_t *data, gpointer ptr _U_ ) +{ + data->packets = 0; +} +static void +wsp_print_statuscode(gint *key, wsp_status_code_t *data, char* format) +{ + if (data && (data->packets!=0)) + printf(format, *key, data->packets ,data->name); +} +static void +wsp_free_hash_table( gpointer key, gpointer value, gpointer user_data _U_ ) +{ + g_free(key); + g_free(value); +} +static void +wspstat_reset(void *psp) +{ + wspstat_t *sp=psp; + guint32 i; + + for(i=1;i<=sp->num_pdus;i++) + { + sp->pdu_stats[i].packets=0; + } + g_hash_table_foreach( sp->hash, (GHFunc)wsp_reset_hash, NULL); +} + + +/* This callback is invoked whenever the tap system has seen a packet + * we might be interested in. + * The function is to be used to only update internal state information + * in the *tapdata structure, and if there were state changes which requires + * the window to be redrawn, return 1 and (*draw) will be called sometime + * later. + * + * We didnt apply a filter when we registered so we will be called for + * ALL packets and not just the ones we are collecting stats for. + * + */ +static gint +pdut2index(gint pdut) +{ + if (pdut<=0x09) return pdut; + if (pdut>=0x40){ + if (pdut <= 0x44){ + return pdut-54; + } else if (pdut==0x60||pdut==0x61){ + return pdut-81; + } + } + return 0; +} +static gint +index2pdut(gint pdut) +{ + if (pdut<=0x09) + return pdut; + if (pdut<=14) + return pdut+54; + if (pdut<=16) + return pdut+81; + return 0; +} +static int +wspstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *pri) +{ + wspstat_t *sp=psp; + wsp_info_value_t *value=pri; + gint index = pdut2index(value->pdut); + int retour=0; + + if (value->status_code != 0) { + gint *key=g_malloc( sizeof(gint) ); + wsp_status_code_t *sc; + *key=value->status_code ; + sc = g_hash_table_lookup( + sp->hash, + key); + if (!sc) { + sc = g_malloc( sizeof(wsp_status_code_t) ); + sc -> packets = 1; + sc -> name = NULL; + g_hash_table_insert( + sp->hash, + key, + sc); + } else { + sc->packets++; + } + retour=1; + } + + + + if (index!=0) { + sp->pdu_stats[ index ].packets++; + retour = 1; + } + return retour; +} + + +/* This callback is used when tethereal wants us to draw/update our + * data to the output device. Since this is tethereal only output is + * stdout. + * Tethereal will only call this callback once, which is when tethereal has + * finished reading all packets and exists. + * If used with ethereal this may be called any time, perhaps once every 3 + * seconds or so. + * This function may even be called in parallell with (*reset) or (*draw) + * so make sure there are no races. The data in the rpcstat_t can thus change + * beneath us. Beware. + */ +static void +wspstat_draw(void *psp) +{ + wspstat_t *sp=psp; + guint32 i; + + printf("\n"); + printf("===================================================================\n"); + printf("WSP Statistics:\n"); + printf("%-23s %9s || %-23s %9s\n","PDU Type", "Packets", "PDU Type", "Packets"); + for(i=1; i<= ((sp->num_pdus+1)/2) ; i++) + { + guint32 ii=i+sp->num_pdus/2; + printf("%-23s %9d", sp->pdu_stats[i ].type, sp->pdu_stats[i ].packets); + printf(" || "); + if (ii< (sp->num_pdus) ) + printf("%-23s %9d\n", sp->pdu_stats[ii].type, sp->pdu_stats[ii].packets); + else + printf("\n"); + } + printf("\nStatus code in reply packets\n"); + printf( "Status Code Packets Description\n"); + g_hash_table_foreach( sp->hash, (GHFunc) wsp_print_statuscode, + "%11d %9d %s\n" ) ; + printf("===================================================================\n"); +} + +/* When called, this function will create a new instance of wspstat. + * program and version are whick onc-rpc program/version we want to + * collect statistics for. + * This function is called from tethereal when it parses the -Z wsp, arguments + * and it creates a new instance to store statistics in and registers this + * new instance for the wsp tap. + */ +static void +wspstat_init(char *optarg) +{ + wspstat_t *sp; + char *filter=NULL; + guint32 i; + GString *error_string; + wsp_status_code_t *sc; + + if (!strncmp (optarg, "wsp,stat," , 9)){ + filter=optarg+9; + } else { + filter=NULL; + } + + + sp = g_malloc( sizeof(wspstat_t) ); + sp->hash = g_hash_table_new( g_int_hash, g_int_equal); + for (i=0 ; vals_status[i].strptr ; i++ ) + { + gint *key; + sc=g_malloc( sizeof(wsp_status_code_t) ); + key=g_malloc( sizeof(gint) ); + sc->packets=0; + sc->name=vals_status[i].strptr; + *key=vals_status[i].value; + g_hash_table_insert( + sp->hash, + key, + sc); + } + sp->num_pdus = 16; + sp->pdu_stats=g_malloc( (sp->num_pdus+1) * sizeof( wsp_pdu_t) ); + if(filter){ + sp->filter=g_malloc(strlen(filter)+1); + strcpy(sp->filter,filter); + } else { + sp->filter=NULL; + } + for (i=0;i<sp->num_pdus; i++) + { + sp->pdu_stats[i].packets=0; + sp->pdu_stats[i].type = match_strval( index2pdut( i ), vals_pdu_type) ; + } + + error_string = register_tap_listener( + "wsp", + sp, + filter, + wspstat_reset, + wspstat_packet, + wspstat_draw); + if (error_string){ + /* error, we failed to attach to the tap. clean up */ + g_free(sp->pdu_stats); + g_free(sp->filter); + g_free(sp); + g_hash_table_foreach( sp->hash, (GHFunc) wsp_free_hash_table, NULL ) ; + g_hash_table_destroy( sp->hash ); + fprintf(stderr, "tethereal: Couldn't register wsp,stat tap: %s\n", + error_string->str); + g_string_free(error_string, TRUE); + exit(1); + } +} +void +register_tap_listener_wspstat(void) +{ + register_ethereal_tap("wsp,stat,", wspstat_init); +} |