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
This commit is contained in:
Ulf Lamping 2005-04-12 21:44:55 +00:00
parent fcb74124f8
commit 7e9cedfed8
10 changed files with 132 additions and 86 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -300,9 +300,11 @@ static GtkItemFactoryEntry menu_items[] =
capture_prep_cb, 0, ETHEREAL_STOCK_CAPTURE_START),
ITEM_FACTORY_STOCK_ENTRY("/Capture/S_top", "<control>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, "<Branch>", 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);

View File

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