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));
}
/* 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. */
if(capture_opts->save_file) {
g_free(capture_opts->save_file);
capture_opts->save_file = NULL;
}

View File

@ -56,6 +56,7 @@ typedef struct capture_options_tag {
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,8 +1247,12 @@ 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) {
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) {
@ -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,25 +596,10 @@ sync_pipe_input_cb(gint source, gpointer user_data)
}
switch(indicator) {
case(SP_CAPSTART):
break;
case SP_PACKET_COUNT:
nread = atoi(buffer);
capture_input_new_packets(capture_opts, nread);
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);
@ -632,7 +610,17 @@ sync_pipe_input_cb(gint source, gpointer user_data)
(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;
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 */