* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/* With MSVC and a libethereal.dll this file needs to import some variables
- in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
-#define _NEED_VAR_IMPORT_
-
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#include "file.h"
#include "capture.h"
#include "capture_sync.h"
+#include "capture_ui_utils.h"
#include "util.h"
#include "pcap-util.h"
#include "alert_box.h"
#include "simple_dialog.h"
#include <epan/prefs.h>
-#include "globals.h"
#include "conditions.h"
#include "ringbuffer.h"
#endif
#include "ui_util.h"
-/*
- * Capture options.
- */
-capture_options capture_opts;
-gboolean capture_child; /* if this is the child for "-S" */
-
/* Win32 needs the O_BINARY flag for open() */
#ifndef O_BINARY
#define O_BINARY 0
#endif
-static gboolean normal_do_capture(gboolean is_tempfile);
+static gboolean normal_do_capture(capture_options *capture_opts, gboolean is_tempfile);
static void stop_capture_signal_handler(int signo);
-/* Open a specified file, or create a temporary file, and start a capture
- to the file in question. Returns TRUE if the capture starts
- successfully, FALSE otherwise. */
-gboolean
-do_capture(const char *save_file)
-{
+
+/* open the output file (temporary/specified name/ringbuffer) */
+/* Returns TRUE if the file opened successfully, FALSE otherwise. */
+static gboolean
+capture_open_output(capture_options *capture_opts, gboolean *is_tempfile) {
char tmpname[128+1];
- gboolean is_tempfile;
gchar *capfile_name;
- gboolean ret;
- if (save_file != NULL) {
+
+ if (capture_opts->save_file != NULL) {
/* If the Sync option is set, we return to the caller while the capture
* is in progress. Therefore we need to take a copy of save_file in
* case the caller destroys it after we return.
*/
- capfile_name = g_strdup(save_file);
- if (capture_opts.multi_files_on) {
+ capfile_name = g_strdup(capture_opts->save_file);
+ if (capture_opts->multi_files_on) {
/* ringbuffer is enabled */
- cfile.save_file_fd = ringbuf_init(capfile_name,
- (capture_opts.has_ring_num_files) ? capture_opts.ring_num_files : 0);
+ capture_opts->save_file_fd = ringbuf_init(capfile_name,
+ (capture_opts->has_ring_num_files) ? capture_opts->ring_num_files : 0);
} else {
/* Try to open/create the specified file for use as a capture buffer. */
- cfile.save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
+ capture_opts->save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
0600);
}
- is_tempfile = FALSE;
+ *is_tempfile = FALSE;
} else {
- /* Choose a random name for the capture buffer */
- cfile.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
+ /* Choose a random name for the temporary capture buffer */
+ capture_opts->save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
capfile_name = g_strdup(tmpname);
- is_tempfile = TRUE;
+ *is_tempfile = TRUE;
}
- if (cfile.save_file_fd == -1) {
- if (is_tempfile) {
+
+ /* did we fail to open the output file? */
+ if (capture_opts->save_file_fd == -1) {
+ if (*is_tempfile) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "The temporary file to which the capture would be saved (\"%s\")"
+ "The temporary file to which the capture would be saved (\"%s\") "
"could not be opened: %s.", capfile_name, strerror(errno));
} else {
- if (capture_opts.multi_files_on) {
+ if (capture_opts->multi_files_on) {
ringbuf_error_cleanup();
}
open_failure_alert_box(capfile_name, errno, TRUE);
g_free(capfile_name);
return FALSE;
}
- cf_close(&cfile);
- g_assert(cfile.save_file == NULL);
- cfile.save_file = capfile_name;
- /* cfile.save_file is "g_free"ed below, which is equivalent to
+
+ if(capture_opts->save_file != NULL) {
+ g_free(capture_opts->save_file);
+ }
+ capture_opts->save_file = capfile_name;
+ /* capture_opts.save_file is "g_free"ed later, which is equivalent to
"g_free(capfile_name)". */
- if (capture_opts.sync_mode) {
+ return TRUE;
+}
+
+
+/* close the output file (NOT the capture file) */
+static void
+capture_close_output(capture_options *capture_opts)
+{
+ if (capture_opts->multi_files_on) {
+ ringbuf_free();
+ } else {
+ g_free(capture_opts->save_file);
+ }
+ capture_opts->save_file = NULL;
+}
+
+
+/* Open a specified file, or create a temporary file, and start a capture
+ to the file in question. */
+/* Returns TRUE if the capture starts successfully, FALSE otherwise. */
+gboolean
+do_capture(capture_options *capture_opts)
+{
+ gboolean is_tempfile;
+ gboolean ret;
+
+
+ /* open the new output file (temporary/specified name/ringbuffer) */
+ if(!capture_open_output(capture_opts, &is_tempfile)) {
+ return FALSE;
+ }
+
+ /* close the currently loaded capture file */
+ cf_close(capture_opts->cf);
+
+ /* We could simply use TRUE for this expression now, this will work for all
+ * captures except for some of the multiple files options, as these capture
+ * options currently cannot be passed through the command line to the
+ * capture child.
+ *
+ * If this is fixed, we could always use the sync mode, throwing away the
+ * normal mode completely and doing some more cleanup. */
+/* if (TRUE) {*/
+ if (capture_opts->sync_mode) {
/* sync mode: do the capture in a child process */
- ret = sync_pipe_do_capture(is_tempfile);
+ ret = sync_pipe_do_capture(capture_opts, is_tempfile);
/* capture is still running */
- set_main_window_name("(Live Capture in Progress) - Ethereal");
+ cf_callback_invoke(cf_cb_live_capture_prepare, capture_opts);
} else {
/* normal mode: do the capture synchronously */
- set_main_window_name("(Live Capture in Progress) - Ethereal");
- ret = normal_do_capture(is_tempfile);
+ cf_callback_invoke(cf_cb_live_capture_prepare, capture_opts);
+ ret = normal_do_capture(capture_opts, is_tempfile);
/* capture is finished here */
}
}
-/* start a normal capture session */
-static gboolean
-normal_do_capture(gboolean is_tempfile)
+/* we've succeeded a capture, try to read it into a new capture file */
+gboolean
+capture_read(capture_options *capture_opts, gboolean is_tempfile, gboolean drops_known,
+guint32 drops)
{
- int capture_succeeded;
- gboolean stats_known;
- struct pcap_stat stats;
int err;
- /* Not sync mode. */
- capture_succeeded = capture_start(&stats_known, &stats);
- if (capture_opts.quit_after_cap) {
- /* DON'T unlink the save file. Presumably someone wants it. */
- main_window_exit();
- }
- if (!capture_succeeded) {
- /* We didn't succeed in doing the capture, so we don't have a save
- file. */
- if (capture_opts.multi_files_on) {
- ringbuf_free();
- } else {
- g_free(cfile.save_file);
- }
- cfile.save_file = NULL;
- return FALSE;
- }
+
/* Capture succeeded; attempt to read in the capture file. */
- if ((err = cf_open(cfile.save_file, is_tempfile, &cfile)) != 0) {
+ if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
/* We're not doing a capture any more, so we don't have a save
file. */
- if (capture_opts.multi_files_on) {
- ringbuf_free();
- } else {
- g_free(cfile.save_file);
- }
- cfile.save_file = NULL;
return FALSE;
}
/* Set the read filter to NULL. */
- cfile.rfcode = NULL;
+ /* XXX - this is odd here, try to put it somewhere, where it fits better */
+ cf_set_rfcode(capture_opts->cf, NULL);
/* Get the packet-drop statistics.
we'll put them into the capture file that we write, and will
thus not have to set them here - "cf_read()" will get them from
the file and use them. */
- if (stats_known) {
- cfile.drops_known = TRUE;
+ if (drops_known) {
+ cf_set_drops_known(capture_opts->cf, TRUE);
/* XXX - on some systems, libpcap doesn't bother filling in
"ps_ifdrop" - it doesn't even set it to zero - so we don't
several statistics - perhaps including various interface
error statistics - and would tell us which of them it
supplies, allowing us to display only the ones it does. */
- cfile.drops = stats.ps_drop;
+ cf_set_drops(capture_opts->cf, drops);
}
- switch (cf_read(&cfile)) {
+ switch (cf_read(capture_opts->cf)) {
- case READ_SUCCESS:
- case READ_ERROR:
+ case CF_READ_OK:
+ case CF_READ_ERROR:
/* Just because we got an error, that doesn't mean we were unable
to read any of the file; we handle what we could get from the
file. */
break;
- case READ_ABORTED:
+ case CF_READ_ABORTED:
/* Exit by leaving the main loop, so that any quit functions
we registered get called. */
main_window_nested_quit();
return FALSE;
}
- /* We're not doing a capture any more, so we don't have a save
- file. */
- if (capture_opts.multi_files_on) {
- ringbuf_free();
- } else {
- g_free(cfile.save_file);
- }
- cfile.save_file = NULL;
-
/* if we didn't captured even a single packet, close the file again */
- if(cfile.count == 0) {
+ if(cf_packet_count(capture_opts->cf) == 0) {
simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
"%sNo packets captured!%s\n\n"
"As no data was captured, closing the %scapture file!",
simple_dialog_primary_start(), simple_dialog_primary_end(),
- (cfile.is_tempfile) ? "temporary " : "");
- cf_close(&cfile);
+ (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
+ cf_close(capture_opts->cf);
}
return TRUE;
}
+/* start a normal capture session */
+static gboolean
+normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
+{
+ gboolean succeeded;
+ gboolean stats_known;
+ struct pcap_stat stats;
+
+
+ /* Not sync mode. */
+ succeeded = capture_loop_start(capture_opts, &stats_known, &stats);
+ if (capture_opts->quit_after_cap) {
+ /* DON'T unlink the save file. Presumably someone wants it. */
+ main_window_exit();
+ }
+ if (succeeded) {
+ /* We succeed in doing the capture, try to read it in. */
+ succeeded = capture_read(capture_opts, is_tempfile, stats_known, stats.ps_drop);
+ }
+
+ /* wether the capture suceeded or not, we have to close the output file here */
+ capture_close_output(capture_opts);
+ return succeeded;
+}
+
+
static void
stop_capture_signal_handler(int signo _U_)
{
int
-capture_start(gboolean *stats_known, struct pcap_stat *stats)
+capture_child_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
{
+ gchar *err_msg;
+
+ g_assert(capture_opts->capture_child);
+
#ifndef _WIN32
/*
* Catch SIGUSR1, so that we exit cleanly if the parent process
* kills us with it due to the user selecting "Capture->Stop".
*/
- if (capture_child)
signal(SIGUSR1, stop_capture_signal_handler);
#endif
- return capture_loop_start(stats_known, stats);
+ /* parent must have send us a file descriptor for the opened output file */
+ if (capture_opts->save_file_fd == -1) {
+ /* send this to the standard output as something our parent
+ should put in an error message box */
+ err_msg = g_strdup_printf("%s: \"-W\" flag not specified (internal error)\n", CHILD_NAME);
+ sync_pipe_errmsg_to_parent(err_msg);
+ g_free(err_msg);
+ return FALSE;
+ }
+
+ return capture_loop_start(capture_opts, stats_known, stats);
}
void
-capture_stop(void)
+capture_stop(capture_options *capture_opts)
{
-
- if (capture_opts.sync_mode) {
- sync_pipe_stop();
- } else {
- capture_loop_stop();
+ /* stop the capture child, if we have one */
+ if (!capture_opts->capture_child) {
+ sync_pipe_stop(capture_opts);
}
+
+ /* stop the capture loop */
+ capture_loop_stop();
}
void
-kill_capture_child(void)
+capture_kill_child(capture_options *capture_opts)
{
- if (capture_opts.sync_mode) {
- sync_pipe_kill();
+ /* kill the capture child, if we have one */
+ if (!capture_opts->capture_child) {
+ sync_pipe_kill(capture_opts);
}
}