From 7e9cedfed81ac84ac28b5f48e36c843025abe2c8 Mon Sep 17 00:00:00 2001 From: Ulf Lamping Date: Tue, 12 Apr 2005 21:44:55 +0000 Subject: [PATCH] capture engine: add a new feature to clear the currently captured packets and restart the capture with the previous parameters various code cleanup and minor bugfixes Win32: use millisecond resolution in capture_loop, to smooth screen update a bit (500ms instead of 1000ms) svn path=/trunk/; revision=14059 --- capture.c | 28 ++++++++++++++-- capture.h | 8 +++-- capture_loop.c | 62 +++++++++++++++++++++-------------- capture_opts.c | 1 + capture_sync.c | 82 ++++++++++++++++++++--------------------------- capture_sync.h | 4 --- gtk/capture_dlg.c | 6 ++++ gtk/capture_dlg.h | 7 ++++ gtk/menu.c | 7 +++- gtk/toolbar.c | 13 ++++---- 10 files changed, 132 insertions(+), 86 deletions(-) diff --git a/capture.c b/capture.c index 951b02114b..5b4df8b907 100644 --- a/capture.c +++ b/capture.c @@ -102,6 +102,15 @@ capture_stop(capture_options *capture_opts) sync_pipe_stop(capture_opts); } + +void +capture_clear(capture_options *capture_opts) +{ + capture_opts->restart = TRUE; + capture_stop(capture_opts); +} + + void capture_kill_child(capture_options *capture_opts) { @@ -267,6 +276,7 @@ capture_input_new_packets(capture_options *capture_opts, int to_read) file. XXX - abort on a read error? */ + main_window_update(); break; case CF_READ_ABORTED: @@ -325,8 +335,22 @@ capture_input_closed(capture_options *capture_opts) cf_get_drops_known(capture_opts->cf), cf_get_drops(capture_opts->cf)); } - /* We're not doing a capture any more, so we don't have a save file. */ - if(capture_opts->save_file) { + /* does the user wants to restart the current capture? */ + if(capture_opts->restart) { + capture_opts->restart = FALSE; + + unlink(capture_opts->save_file); + + /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */ + if(cf_is_tempfile(capture_opts->cf)) { + g_free(capture_opts->save_file); + capture_opts->save_file = NULL; + } + + /* ... and start the capture again */ + capture_start(capture_opts); + } else { + /* We're not doing a capture any more, so we don't have a save file. */ g_free(capture_opts->save_file); capture_opts->save_file = NULL; } diff --git a/capture.h b/capture.h index fcaaf2527a..98cafb1cc7 100644 --- a/capture.h +++ b/capture.h @@ -53,9 +53,10 @@ typedef struct capture_options_tag { gchar *save_file; /**< the capture file name */ /* GUI related */ - gboolean real_time_mode;/**< Update list of packets in real time */ - gboolean show_info; /**< show the info dialog */ + gboolean real_time_mode; /**< Update list of packets in real time */ + gboolean show_info; /**< show the info dialog */ gboolean quit_after_cap; /** Makes a "capture only mode". Implies -k */ + gboolean restart; /**< restart after closing is done */ /* multiple files (and ringbuffer) */ gboolean multi_files_on; /**< TRUE if ring buffer in use */ @@ -106,6 +107,9 @@ extern gboolean capture_start(capture_options *capture_opts); /** Stop a capture session (usually from a menu item). */ extern void capture_stop(capture_options *capture_opts); +/** Clear the current captured packets and start again. */ +extern void capture_clear(capture_options *capture_opts); + /** Terminate the capture child cleanly when exiting. */ extern void capture_kill_child(capture_options *capture_opts); diff --git a/capture_loop.c b/capture_loop.c index 2bf21491b1..dda243f68c 100644 --- a/capture_loop.c +++ b/capture_loop.c @@ -1037,6 +1037,11 @@ capture_loop_stop_signal_handler(int signo _U_) } #endif +#ifdef _WIN32 +#define TIME_GET() GetTickCount() +#else +#define TIME_GET() time(NULL) +#endif /* * This needs to be static, so that the SIGUSR1 handler can clear the "go" @@ -1144,7 +1149,6 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct update its windows to indicate that we have a live capture in progress. */ fflush(wtap_dump_file(ld.wtap_pdh)); - sync_pipe_capstart_to_parent(); sync_pipe_filename_to_parent(capture_opts->save_file); /* initialize capture stop (and alike) conditions */ @@ -1175,8 +1179,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct } /* init the time values */ - start_time = time(NULL); - upd_time = time(NULL); + start_time = TIME_GET(); + upd_time = TIME_GET(); /* WOW, everything is prepared! */ /* please fasten your seat belts, we will enter now the actual capture loop */ @@ -1186,6 +1190,26 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct /* dispatch incoming packets */ inpkts = capture_loop_dispatch(capture_opts, &ld, errmsg, sizeof(errmsg)); + main_window_update(); + +#ifdef _WIN32 + /* some news from our parent (signal pipe)? -> just stop the capture */ + { + HANDLE handle; + DWORD avail = 0; + gboolean result; + + + handle = (HANDLE) _get_osfhandle (0); + result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); + + if(!result || avail > 0) { + ld.go = FALSE; + /*g_warning("loop closing");*/ + } + } +#endif + if (inpkts > 0) { ld.packets_sync_pipe += inpkts; @@ -1223,9 +1247,13 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct } /* inpkts */ /* Only update once a second so as not to overload slow displays */ - cur_time = time(NULL); - if (cur_time > upd_time) { - upd_time = cur_time; + cur_time = TIME_GET(); +#ifdef _WIN32 + if ( (cur_time - upd_time) > 500) { +#else + if (cur_time - upd_time > 0) { +#endif + upd_time = cur_time; /*if (pcap_stats(pch, stats) >= 0) { *stats_known = TRUE; @@ -1234,29 +1262,15 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct /* calculate and display running time */ if(capture_opts->show_info) { cur_time -= start_time; +#ifdef _WIN32 + capture_ui.running_time = cur_time / 1000; +#else capture_ui.running_time = cur_time; +#endif capture_ui.new_packets = ld.packets_sync_pipe; capture_info_update(&capture_ui); } -#ifdef _WIN32 - /* some news from our parent (signal pipe)? -> just stop the capture */ - { - HANDLE handle; - DWORD avail = 0; - gboolean result; - - - handle = (HANDLE) _get_osfhandle (0); - result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); - - if(!result || avail > 0) { - ld.go = FALSE; - /*g_warning("loop closing");*/ - } - } -#endif - /* Let the parent process know. */ if (ld.packets_sync_pipe) { /* do sync here */ diff --git a/capture_opts.c b/capture_opts.c index f00f2fc9a8..3c4f126dc2 100644 --- a/capture_opts.c +++ b/capture_opts.c @@ -63,6 +63,7 @@ capture_opts_init(capture_options *capture_opts, void *cfile) capture_opts->real_time_mode = TRUE; capture_opts->show_info = TRUE; capture_opts->quit_after_cap = FALSE; + capture_opts->restart = FALSE; capture_opts->multi_files_on = FALSE; capture_opts->has_file_duration = FALSE; diff --git a/capture_sync.c b/capture_sync.c index 169014dde5..b03cb9eb32 100644 --- a/capture_sync.c +++ b/capture_sync.c @@ -118,12 +118,11 @@ static void sync_pipe_wait_for_child(capture_options *capture_opts, gboolean alw /* * Indications sent out on the sync pipe. */ -#define SP_CAPSTART 'S' /* capture start message */ -#define SP_CAPQUIT 'Q' /* capture quit message */ -#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */ -#define SP_ERROR_MSG 'E' /* error message */ -#define SP_DROPS 'D' /* count of packets dropped in capture */ #define SP_FILE 'F' /* the name of the recently opened file */ +#define SP_ERROR_MSG 'E' /* error message */ +#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */ +#define SP_DROPS 'D' /* count of packets dropped in capture */ +#define SP_QUIT 'Q' /* capture quit message (from parent to child) */ /* write a message to the recipient pipe in the standard format @@ -132,7 +131,7 @@ static void sync_pipe_wait_for_child(capture_options *capture_opts, gboolean alw static void pipe_write_block(int pipe, char indicator, int len, const char *msg) { - char lenbuf[SP_DECISIZE+1+1]; + char lenbuf[3+1+1]; /* 3 digit len + indicator + zero terminator */ int ret; /*g_warning("write %d enter", pipe);*/ @@ -140,17 +139,21 @@ pipe_write_block(int pipe, char indicator, int len, const char *msg) g_assert(len < 1000); g_assert(indicator < '0' || indicator > '9'); - /* write header (3 digit len + indicator + zero terminator) */ + /* write header (3 digit len + indicator) */ g_snprintf(lenbuf, 5, "%03u%c", len, indicator); ret = write(pipe, lenbuf, strlen(lenbuf)); - g_assert(ret != -1); + if(ret == -1) { + return; + } /* write value (if we have one) */ if(len) { /*g_warning("write %d indicator: %c value len: %u msg: %s", pipe, indicator, len, msg);*/ ret = write(pipe, msg, len); - g_assert(ret != -1); + if(ret == -1) { + return; + } } else { /*g_warning("write %d indicator: %c no value", pipe, indicator);*/ } @@ -221,23 +224,13 @@ pipe_read_block(int pipe, char *indicator, int len, char *msg) { return len + 4; } -void -sync_pipe_capstart_to_parent(void) -{ -/* static const char capstart_msg = SP_CAPSTART; - - write(1, &capstart_msg, 1);*/ - - pipe_write_block(1, SP_CAPSTART, 0, NULL); -} - void sync_pipe_packet_count_to_parent(int packet_count) { char tmp[SP_DECISIZE+1+1]; - g_snprintf(tmp, SP_DECISIZE, "%d", packet_count); + g_snprintf(tmp, sizeof(tmp), "%d", packet_count); pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp); } @@ -260,7 +253,7 @@ sync_pipe_drops_to_parent(int drops) char tmp[SP_DECISIZE+1+1]; - g_snprintf(tmp, SP_DROPS, "%d", drops); + g_snprintf(tmp, sizeof(tmp), "%d", drops); pipe_write_block(1, SP_DROPS, strlen(tmp)+1, tmp); } @@ -269,11 +262,11 @@ sync_pipe_drops_to_parent(int drops) #ifdef _WIN32 static void -signal_pipe_capend_to_child(capture_options *capture_opts) +signal_pipe_capquit_to_child(capture_options *capture_opts) { - pipe_write_block(capture_opts->signal_pipe_fd, SP_CAPQUIT, 0, NULL); + pipe_write_block(capture_opts->signal_pipe_fd, SP_QUIT, 0, NULL); } #endif @@ -603,37 +596,32 @@ sync_pipe_input_cb(gint source, gpointer user_data) } switch(indicator) { - case(SP_CAPSTART): - break; + case SP_FILE: + if(!capture_input_new_file(capture_opts, buffer)) { + /* We weren't able to open the new capture file; user has been + alerted. Close the sync pipe. */ + /* XXX - is it safe to close the pipe inside this callback? */ + close(source); + + /* the child has send us a filename which we couldn't open. + this probably means, the child is creating files faster than we can handle it. + this should only be the case for very fast file switches + we can't do much more than telling the child to stop + (this is the emergency brake if user e.g. wants to switch files every second) */ + sync_pipe_stop(capture_opts); + } + break; case SP_PACKET_COUNT: nread = atoi(buffer); capture_input_new_packets(capture_opts, nread); break; + case SP_ERROR_MSG: + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, buffer); + break; case SP_DROPS: cf_set_drops_known(capture_opts->cf, TRUE); cf_set_drops(capture_opts->cf, atoi(buffer)); break; - case SP_ERROR_MSG: - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, buffer); - break; - case SP_FILE: - if(!capture_input_new_file(capture_opts, buffer)) { - /* We weren't able to open the new capture file; user has been - alerted. Close the sync pipe. */ - - /* XXX - how to kill things here ? */ - /* XXX - is it safe to close the pipe inside this callback? */ - close(source); - - /* the child has send us a filename which we couldn't open. - this probably means, the child is creating files faster than we can handle it. - this should only be the case for very fast file switches - we can't do much more than telling the child to stop - (this is the emergency brake if user e.g. wants to switch files every second) */ - sync_pipe_stop(capture_opts); - } - - break; default: g_assert_not_reached(); } @@ -803,7 +791,7 @@ sync_pipe_stop(capture_options *capture_opts) #else /* Win32 doesn't have the kill() system call, use the special signal pipe instead to close the capture child gracefully. */ - signal_pipe_capend_to_child(capture_opts); + signal_pipe_capquit_to_child(capture_opts); #endif } } diff --git a/capture_sync.h b/capture_sync.h index b429cc4184..fc6b0a63c9 100644 --- a/capture_sync.h +++ b/capture_sync.h @@ -58,10 +58,6 @@ extern void sync_pipe_kill(capture_options *capture_opts); -/** the child will immediately start capturing, notify the parent */ -extern void -sync_pipe_capstart_to_parent(void); - /** the child has opened a new capture file, notify the parent */ extern void sync_pipe_filename_to_parent(const char *filename); diff --git a/gtk/capture_dlg.c b/gtk/capture_dlg.c index 470a22cf37..91be8dd60e 100644 --- a/gtk/capture_dlg.c +++ b/gtk/capture_dlg.c @@ -126,6 +126,12 @@ capture_stop_cb(GtkWidget *w _U_, gpointer d _U_) capture_stop(capture_opts); } +void +capture_clear_cb(GtkWidget *w _U_, gpointer d _U_) +{ + capture_clear(capture_opts); +} + /* * Keep a static pointer to the current "Capture Options" window, if * any, so that if somebody tries to do "Capture:Start" while there's diff --git a/gtk/capture_dlg.h b/gtk/capture_dlg.h index 3bd1904d2b..0dc9e92be0 100644 --- a/gtk/capture_dlg.h +++ b/gtk/capture_dlg.h @@ -45,6 +45,13 @@ void capture_prep_cb(GtkWidget *widget, gpointer data); */ void capture_stop_cb(GtkWidget *widget, gpointer data); +/** User requested capture clear by menu or toolbar. + * + * @param widget parent widget (unused) + * @param data unused + */ +void capture_clear_cb(GtkWidget *widget, gpointer data); + /** Create the "Capture Options" dialog box. */ void capture_prep(void); diff --git a/gtk/menu.c b/gtk/menu.c index 41d483c05d..449c0449e9 100644 --- a/gtk/menu.c +++ b/gtk/menu.c @@ -300,9 +300,11 @@ static GtkItemFactoryEntry menu_items[] = capture_prep_cb, 0, ETHEREAL_STOCK_CAPTURE_START), ITEM_FACTORY_STOCK_ENTRY("/Capture/S_top", "E", capture_stop_cb, 0, GTK_STOCK_STOP), + ITEM_FACTORY_STOCK_ENTRY("/Capture/_Clear", NULL, capture_clear_cb, + 0, GTK_STOCK_CLEAR), ITEM_FACTORY_ENTRY("/Capture/_Interfaces...", NULL, capture_if_cb, 0, NULL, NULL), - ITEM_FACTORY_STOCK_ENTRY("/Capture/_Capture Filters...", NULL, cfilter_dialog_cb, + ITEM_FACTORY_STOCK_ENTRY("/Capture/Capture _Filters...", NULL, cfilter_dialog_cb, 0, ETHEREAL_STOCK_CAPTURE_FILTER), #endif /* HAVE_LIBPCAP */ ITEM_FACTORY_ENTRY("/_Analyze", NULL, NULL, 0, "", NULL), @@ -566,6 +568,7 @@ menus_init(void) { set_menus_for_captured_packets(FALSE); set_menus_for_selected_packet(&cfile); set_menus_for_selected_tree_row(&cfile); + set_menus_for_capture_in_progress(FALSE); /* init with an empty recent files list */ clear_menu_recent_capture_file_cmd_cb(NULL, NULL); @@ -1538,6 +1541,8 @@ set_menus_for_capture_in_progress(gboolean capture_in_progress) !capture_in_progress); set_menu_sensitivity(main_menu_factory, "/Capture/Stop", capture_in_progress); + set_menu_sensitivity(main_menu_factory, "/Capture/Clear", + capture_in_progress); set_toolbar_for_capture_in_progress(capture_in_progress); set_capture_if_dialog_for_capture_in_progress(capture_in_progress); diff --git a/gtk/toolbar.c b/gtk/toolbar.c index 459a88bd48..bedaa4059e 100644 --- a/gtk/toolbar.c +++ b/gtk/toolbar.c @@ -117,7 +117,7 @@ static gboolean toolbar_init = FALSE; #ifdef HAVE_LIBPCAP -static GtkWidget *new_button, *stop_button; +static GtkWidget *new_button, *stop_button, *clear_button; static GtkWidget *capture_filter_button; #endif /* HAVE_LIBPCAP */ static GtkWidget *open_button, *save_button, *save_as_button, *close_button, *reload_button; @@ -283,13 +283,15 @@ void set_toolbar_for_capture_in_progress(gboolean capture_in_progress) { if (toolbar_init) { #ifdef HAVE_LIBPCAP gtk_widget_set_sensitive(new_button, !capture_in_progress); - if (capture_in_progress) { + gtk_widget_set_sensitive(stop_button, capture_in_progress); + gtk_widget_set_sensitive(clear_button, capture_in_progress); + /*if (capture_in_progress) { gtk_widget_hide(new_button); gtk_widget_show(stop_button); } else { gtk_widget_show(new_button); gtk_widget_hide(stop_button); - } + }*/ #endif /* HAVE_LIBPCAP */ gtk_widget_set_sensitive(open_button, !capture_in_progress); } @@ -391,13 +393,12 @@ toolbar_new(void) #ifdef HAVE_LIBPCAP - /* either start OR stop button can be valid at a time, so no space - * between them is needed here (stop button is hidden by default) */ - toolbar_item(new_button, window, main_tb, ETHEREAL_STOCK_CAPTURE_START, "Start a new live capture...", capture_24_xpm, capture_prep_cb, NULL); toolbar_item(stop_button, window, main_tb, GTK_STOCK_STOP, "Stop the running live capture", stock_stop_24_xpm, capture_stop_cb, NULL); + toolbar_item(clear_button, window, main_tb, + GTK_STOCK_CLEAR, "Clear the captured packets", stock_clear_24_xpm, capture_clear_cb, NULL); toolbar_append_separator(main_tb); #endif /* HAVE_LIBPCAP */