From 1bfc30f6e5f7e843b8f61a0e7b0847f84eed7c75 Mon Sep 17 00:00:00 2001 From: sahlberg Date: Thu, 5 Sep 2002 06:46:38 +0000 Subject: [PATCH] Added a mutex to protect a critical region in Gtk2 where the list can be modified while the draw thread is walking it. Changed the cmdline switch to -z so the same one can be used both for ethereal and tethereal. Updated man pages to reflect the RPCSTAT feature. (Try this with Tools/Statistics/ONC-RPC/RTT and load a capture containing onc-rpc. ) git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@6189 f5534014-38df-0310-8fa8-9805f1628bb7 --- AUTHORS | 1 + doc/ethereal.pod.template | 24 ++++++++++++++++++++++++ doc/tethereal.pod.template | 8 ++++---- gtk2/gtk2-rpcstat.c | 24 +++++++++++++++++++++--- gtk2/main.c | 30 ++++++++++++++++++++++++++++-- tap.c | 38 +++++++++++++++++++------------------- tethereal.c | 12 ++++++------ 7 files changed, 103 insertions(+), 34 deletions(-) diff --git a/AUTHORS b/AUTHORS index 485c86007a..1a3885206c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -614,6 +614,7 @@ Ronnie Sahlberg { MAPI skeleton dissector DCE/RPC fragment reassembly TCP ACK/SEQ number analysis and relative sequence numbers + TAP system and RPCSTAT example for tethereal and Gtk2 } Borosa Tomislav { diff --git a/doc/ethereal.pod.template b/doc/ethereal.pod.template index 68ee936d86..798dc600bb 100644 --- a/doc/ethereal.pod.template +++ b/doc/ethereal.pod.template @@ -30,6 +30,7 @@ S<[ B<-T> tree view height ]> S<[ B<-t> time stamp format ]> S<[ B<-v> ]> S<[ B<-w> savefile]> +S<[ B<-z> statistics-string ]> S<[ infile ]> =head1 DESCRIPTION @@ -265,6 +266,20 @@ Print the version and exit. Set the default capture file name. +=item -z + +Get B to collect various types of statistics and display the result +in a window that updates in semi-real time. +Currently implemented statistics are: + +B<-z> rpc,rtt,I,I + +Collect call/reply RTT data for I/I. Data collected +is number of calls for each procedure, MinRTT, MaxRTT and AvgRTT. +Example: use B<-z rpc,rtt,100003,3> to collect data for NFS v3. This +option can be used multiple times on the command line. + +This feature is only available for the Gtk2 port of B. =back =head1 INTERFACE @@ -514,6 +529,15 @@ last-protocol counts show you how many packets (and the byte count associated with those packets) B in a particular protocol. In the table, they are listed under "End Packets" and "End Bytes". +=item Tools:Statistics:ONC-RPC:RTT + +Open a window to display statistics for an arbitrary ONC-RPC program interface +and display B, B, B, B and B for all procedures for that program/version. +These windows opened will update in semi-real time to reflect changes when +doing live captures or when reading new capture files into B. + +This feature is only availabe for the Gtk2 version of B. + =head2 WINDOWS =over 4 diff --git a/doc/tethereal.pod.template b/doc/tethereal.pod.template index 5dec6050b5..daeb7af048 100644 --- a/doc/tethereal.pod.template +++ b/doc/tethereal.pod.template @@ -29,7 +29,7 @@ S<[ B<-v> ]> S<[ B<-V> ]> S<[ B<-w> savefile ]> S<[ B<-x> ]> -S<[ B<-Z> statistics-string ]> +S<[ B<-z> statistics-string ]> S<[ filter expression ]> =head1 DESCRIPTION @@ -303,17 +303,17 @@ I is "-". Cause B to print a hex and ASCII dump of the packet data after printing the summary or protocol tree. -=item -Z +=item -z Get B to collect various types of statistics and display the result after finishing reading the capture file. Currently implemented statistics are: -B<-Z> rpc,rtt,I,I +B<-z> rpc,rtt,I,I Collect call/reply RTT data for I/I. Data collected is number of calls for each procedure, MinRTT, MaxRTT and AvgRTT. -Example: use B<-Z rpc,rtt,100003,3> to collect data for NFS v3. This +Example: use B<-z rpc,rtt,100003,3> to collect data for NFS v3. This option can be used multiple times on the command line. =back diff --git a/gtk2/gtk2-rpcstat.c b/gtk2/gtk2-rpcstat.c index 2b1484ee34..f87d372a06 100644 --- a/gtk2/gtk2-rpcstat.c +++ b/gtk2/gtk2-rpcstat.c @@ -1,7 +1,7 @@ /* gtk2-rpcstat.c * rpcstat 2002 Ronnie Sahlberg * - * $Id: gtk2-rpcstat.c,v 1.1 2002/09/04 22:18:12 sahlberg Exp $ + * $Id: gtk2-rpcstat.c,v 1.2 2002/09/05 06:46:38 sahlberg Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -46,6 +46,7 @@ #include "tap-rpcstat.h" #include "packet-rpc.h" +extern GStaticMutex update_thread_mutex; /* used to keep track of statistics for a specific procedure */ typedef struct _rpc_procedure_t { @@ -254,20 +255,29 @@ rpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_) return NULL; } +/* 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 + */ static void win_destroy_cb(GtkWindow *win _U_, gpointer data) { rpcstat_t *rs=(rpcstat_t *)data; + g_static_mutex_lock(&update_thread_mutex); remove_tap_listener(rs); + g_static_mutex_unlock(&update_thread_mutex); + g_free(rs->procedures); g_free(rs); } /* When called, this function will create a new instance of gtk2-rpcstat. */ -static void -rpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_) +void +gtk2_rpcstat_init(guint32 program, guint32 version) { rpcstat_t *rs; guint32 i; @@ -276,6 +286,8 @@ rpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_) GtkWidget *stat_label; GtkWidget *tmp; + rpc_program=program; + rpc_version=version; rs=g_malloc(sizeof(rpcstat_t)); rs->prog=rpc_prog_name(rpc_program); rs->program=rpc_program; @@ -381,6 +393,12 @@ rpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_) gtk_widget_show_all(rs->win); } +static void +rpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_) +{ + gtk2_rpcstat_init(rpc_program, rpc_version); +} + diff --git a/gtk2/main.c b/gtk2/main.c index 2757484101..1dcd6bede5 100644 --- a/gtk2/main.c +++ b/gtk2/main.c @@ -1,6 +1,6 @@ /* main.c * - * $Id: main.c,v 1.2 2002/09/04 22:19:42 sahlberg Exp $ + * $Id: main.c,v 1.3 2002/09/05 06:46:38 sahlberg Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -135,6 +135,7 @@ #include "image/clist_ascend.xpm" #include "image/clist_descend.xpm" #include "../tap.h" +#include "gtk2-rpcstat.h" #ifdef WIN32 #include "capture-wpcap.h" @@ -1211,13 +1212,18 @@ set_autostop_criterion(const char *autostoparg) } #endif + +GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT; + gpointer update_thread(gpointer data _U_) { while(1){ struct timeval tv1, tv2; gettimeofday(&tv1, NULL); + g_static_mutex_lock(&update_thread_mutex); draw_tap_listeners(FALSE); + g_static_mutex_unlock(&update_thread_mutex); do{ g_thread_yield(); gettimeofday(&tv2, NULL); @@ -1272,7 +1278,7 @@ main(int argc, char *argv[]) gboolean prefs_write_needed = FALSE; -#define OPTSTRING_INIT "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:v" +#define OPTSTRING_INIT "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:vz:" #ifdef HAVE_LIBPCAP #ifdef WIN32 @@ -1708,6 +1714,26 @@ main(int argc, char *argv[]) break; #endif + case 'z': + if(!strncmp(optarg,"rpc,",4)){ + if(!strncmp(optarg,"rpc,rtt,",8)){ + int rpcprogram, rpcversion; + if(sscanf(optarg,"rpc,rtt,%d,%d",&rpcprogram,&rpcversion)==2){ + gtk2_rpcstat_init(rpcprogram,rpcversion); + } else { + fprintf(stderr, "ethereal: invalid \"-z rpc,rtt,,\" argument\n"); + exit(1); + } + } else { + fprintf(stderr, "ethereal: invalid -z argument. Argument must be \"-z rpc,rtt,...\"\n"); + exit(1); + } + } else { + fprintf(stderr, "ethereal: invalid -z argument. Argument must be \"-z rpc,...\"\n"); + exit(1); + } + break; + #ifdef _WIN32 #ifdef HAVE_LIBPCAP /* Hidden option supporting Sync mode */ diff --git a/tap.c b/tap.c index ce57f786ca..9a61724893 100644 --- a/tap.c +++ b/tap.c @@ -1,7 +1,7 @@ /* tap.c * packet tap interface 2002 Ronnie Sahlberg * - * $Id: tap.c,v 1.1 2002/09/04 09:40:24 sahlberg Exp $ + * $Id: tap.c,v 1.2 2002/09/05 06:46:34 sahlberg Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -77,13 +77,12 @@ typedef struct _tap_listener_t { int (*packet)(void *tapdata, packet_info *pinfo, void *data); void (*draw)(void *tapdata); } tap_listener_t; -static tap_listener_t *tap_listener_queue=NULL; +static volatile tap_listener_t *tap_listener_queue=NULL; static union wtap_pseudo_header *l_pseudo_header=NULL; static const u_char *l_buf=NULL; static frame_data *l_fdata; - /* ********************************************************************** * Init routine only called from epan at application startup * ********************************************************************** */ @@ -180,7 +179,6 @@ tap_queue_packet(int tap_id, packet_info *pinfo, void *tap_specific_data) return; } -/*printf("tap_queue_packet %d %d\n",pinfo->fd->num,tapping_is_active);*/ /* get a free tap_packet structure, this is CHEAP */ tpt=tap_packet_list_free; tap_packet_list_free=tpt->next; @@ -190,6 +188,7 @@ tap_queue_packet(int tap_id, packet_info *pinfo, void *tap_specific_data) tpt->tap_id=tap_id; tpt->pinfo=pinfo; tpt->tap_specific_data=tap_specific_data; + } @@ -211,7 +210,6 @@ tap_queue_init(union wtap_pseudo_header *pseudo_header, const u_char *buf, frame l_buf=buf; l_fdata=fdata; -/*printf("tap_queue_init\n");*/ tapping_is_active=1; tpt=tap_packet_list_queue; @@ -239,9 +237,8 @@ tap_push_tapped_queue(void) epan_dissect_t *edt; tapping_is_active=0; -/*printf("tap_push_tapped_queue\n");*/ for(tp=tap_packet_list_queue;tp;tp=tp->next){ - for(tl=tap_listener_queue;tl;tl=tl->next){ + for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){ if(tp->tap_id==tl->tap_id){ int passed=TRUE; if(tl->code){ @@ -262,7 +259,6 @@ tap_push_tapped_queue(void) } } - /*draw_tap_listeners();*/ /*XXX until we have a thread for this */ } /* This function is called when we need to reset all tap listeners, for example @@ -273,15 +269,16 @@ reset_tap_listeners(void) { tap_listener_t *tl; -/*printf("reset_tap_listeners\n");*/ - for(tl=tap_listener_queue;tl;tl=tl->next){ + for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){ if(tl->reset){ tl->reset(tl->tapdata); } tl->needs_redraw=1; } + } + /* This function is called when we need to redraw all tap listeners, for example when we open/start a new capture or if we need to rescan the packet list. this one should be called from a low priority thread say once every 3 seconds @@ -294,8 +291,7 @@ draw_tap_listeners(gboolean draw_all) { tap_listener_t *tl; -/*printf("draw_tap_listeners\n");*/ - for(tl=tap_listener_queue;tl;tl=tl->next){ + for(tl=(tap_listener_t *)tap_listener_queue;tl;tl=tl->next){ if(tl->needs_redraw || draw_all){ if(tl->draw){ tl->draw(tl->tapdata); @@ -364,7 +360,7 @@ register_tap_listener(char *tapname, void *tapdata, char *fstring, void (*reset) tl->reset=reset; tl->packet=packet; tl->draw=draw; - tl->next=tap_listener_queue; + tl->next=(tap_listener_t *)tap_listener_queue; tap_listener_queue=tl; @@ -372,7 +368,7 @@ register_tap_listener(char *tapname, void *tapdata, char *fstring, void (*reset) } /* this function removes a tap listener -*/ + */ void remove_tap_listener(void *tapdata) { @@ -383,10 +379,10 @@ remove_tap_listener(void *tapdata) } if(tap_listener_queue->tapdata==tapdata){ - tl=tap_listener_queue; + tl=(tap_listener_t *)tap_listener_queue; tap_listener_queue=tap_listener_queue->next; } else { - for(tl2=tap_listener_queue;tl2->next;tl=tl2->next){ + for(tl2=(tap_listener_t *)tap_listener_queue;tl2->next;tl2=tl2->next){ if(tl2->next->tapdata==tapdata){ tl=tl2->next; tl2->next=tl2->next->next; @@ -396,11 +392,15 @@ remove_tap_listener(void *tapdata) } } - if(tl->code){ - dfilter_free(tl->code); + if(tl){ + if(tl->code){ + dfilter_free(tl->code); + } + g_free(tl); } - g_free(tl); + return; } + diff --git a/tethereal.c b/tethereal.c index d7be13a6cb..3ee2e07c75 100644 --- a/tethereal.c +++ b/tethereal.c @@ -1,6 +1,6 @@ /* tethereal.c * - * $Id: tethereal.c,v 1.154 2002/09/04 09:40:24 sahlberg Exp $ + * $Id: tethereal.c,v 1.155 2002/09/05 06:46:34 sahlberg Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -456,7 +456,7 @@ main(int argc, char *argv[]) #endif /* Now get our args */ - while ((opt = getopt(argc, argv, "a:b:c:Df:F:hi:lnN:o:pqr:R:s:St:vw:VxZ:")) != -1) { + while ((opt = getopt(argc, argv, "a:b:c:Df:F:hi:lnN:o:pqr:R:s:St:vw:Vxz:")) != -1) { switch (opt) { case 'a': /* autostop criteria */ #ifdef HAVE_LIBPCAP @@ -647,22 +647,22 @@ main(int argc, char *argv[]) case 'x': /* Print packet data in hex (and ASCII) */ print_hex = TRUE; break; - case 'Z': + case 'z': if(!strncmp(optarg,"rpc,",4)){ if(!strncmp(optarg,"rpc,rtt,",8)){ int rpcprogram, rpcversion; if(sscanf(optarg,"rpc,rtt,%d,%d",&rpcprogram,&rpcversion)==2){ rpcstat_init(rpcprogram,rpcversion); } else { - fprintf(stderr, "tethereal: invalid \"-Z rpc,rtt,,\" argument\n"); + fprintf(stderr, "tethereal: invalid \"-z rpc,rtt,,\" argument\n"); exit(1); } } else { - fprintf(stderr, "tethereal: invalid -Z argument. Argument must be \"-Z rpc,rtt,...\"\n"); + fprintf(stderr, "tethereal: invalid -z argument. Argument must be \"-z rpc,rtt,...\"\n"); exit(1); } } else { - fprintf(stderr, "tethereal: invalid -Z argument. Argument must be \"-Z rpc,...\"\n"); + fprintf(stderr, "tethereal: invalid -z argument. Argument must be \"-z rpc,...\"\n"); exit(1); } break; -- 2.34.1