aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.common2
-rw-r--r--capture.c725
-rw-r--r--capture_sync.c796
-rw-r--r--capture_sync.h76
4 files changed, 882 insertions, 717 deletions
diff --git a/Makefile.common b/Makefile.common
index 13d78709a6..09044da7ac 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -140,6 +140,7 @@ ethereal_SOURCES = \
$(ETHEREAL_COMMON_SRC) \
alert_box.c \
capture.c \
+ capture_sync.c \
capture_combo_utils.c \
color_filters.c \
file.c \
@@ -153,6 +154,7 @@ ethereal_SOURCES = \
ethereal_INCLUDES = \
alert_box.h \
capture.h \
+ capture_sync.h \
capture_combo_utils.h \
color_filters.h \
filters.h \
diff --git a/capture.c b/capture.c
index e848d29d6d..e59899b531 100644
--- a/capture.c
+++ b/capture.c
@@ -105,10 +105,6 @@
# include "snprintf.h"
#endif
-#ifdef _WIN32
-#include <process.h> /* For spawning child process */
-#endif
-
/*
* We don't want to do a "select()" on the pcap_t's file descriptor on
* BSD (because "select()" doesn't work correctly on BPF devices on at
@@ -136,6 +132,7 @@
#include <epan/dfilter/dfilter.h>
#include "file.h"
#include "capture.h"
+#include "capture_sync.h"
#include "util.h"
#include "pcap-util.h"
#include "alert_box.h"
@@ -179,22 +176,6 @@ capture_options capture_opts;
gboolean quit_after_cap = FALSE;/* Makes a "capture only mode". Implies -k */
gboolean capture_child; /* if this is the child for "-S" */
-static int sync_pipe[2]; /* used to sync father */
-enum PIPES { READ, WRITE }; /* Constants 0 and 1 for READ and WRITE */
-static int fork_child = -1; /* If not -1, in parent, process ID of child */
-
-/* Size of buffer to hold decimal representation of
- signed/unsigned 64-bit int */
-#define SP_DECISIZE 20
-
-/*
- * Indications sent out on the sync pipe.
- */
-#define SP_CAPSTART ';' /* capture start message */
-#define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */
-#define SP_ERROR_MSG '!' /* followed by length of error message that follows */
-#define SP_DROPS '#' /* followed by count of packets dropped in capture */
-
typedef struct _loop_data {
gboolean go; /* TRUE as long as we're supposed to keep capturing */
@@ -224,14 +205,6 @@ typedef struct _loop_data {
#define O_BINARY 0
#endif
-static gboolean sync_pipe_do_capture(gboolean is_tempfile);
-static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
-static void sync_pipe_wait_for_child(gboolean);
-static void sync_pipe_errmsg_to_parent(const char *);
-#ifndef _WIN32
-static char *sync_pipe_signame(int);
-#endif
-
static gboolean normal_do_capture(gboolean is_tempfile);
static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *,
const guchar *);
@@ -303,7 +276,6 @@ do_capture(const char *save_file)
cfile.save_file = capfile_name;
/* cfile.save_file is "g_free"ed below, which is equivalent to
"g_free(capfile_name)". */
- fork_child = -1;
if (capture_opts.sync_mode) {
/* sync mode: do the capture in a child process */
@@ -322,660 +294,9 @@ do_capture(const char *save_file)
-/* Add a string pointer to a NULL-terminated array of string pointers. */
-static char **
-sync_pipe_add_arg(char **args, int *argc, char *arg)
-{
- /* Grow the array; "*argc" currently contains the number of string
- pointers, *not* counting the NULL pointer at the end, so we have
- to add 2 in order to get the new size of the array, including the
- new pointer and the terminating NULL pointer. */
- args = g_realloc(args, (*argc + 2) * sizeof (char *));
-
- /* Stuff the pointer into the penultimate element of the array, which
- is the one at the index specified by "*argc". */
- args[*argc] = arg;
-
- /* Now bump the count. */
- (*argc)++;
-
- /* We overwrite the NULL pointer; put it back right after the
- element we added. */
- args[*argc] = NULL;
-
- return args;
-}
-
-#ifdef _WIN32
-/* Given a string, return a pointer to a quote-encapsulated version of
- the string, so we can pass it as an argument with "spawnvp" even
- if it contains blanks. */
-char *
-sync_pipe_quote_encapsulate(const char *string)
-{
- char *encapsulated_string;
-
- encapsulated_string = g_new(char, strlen(string) + 3);
- sprintf(encapsulated_string, "\"%s\"", string);
- return encapsulated_string;
-}
-#endif
-
-
-
-static gboolean
-sync_pipe_do_capture(gboolean is_tempfile) {
- guint byte_count;
- int i;
- guchar c;
- char *msg;
- int err;
- char ssnap[24];
- char scount[24]; /* need a constant for len of numbers */
- char sautostop_filesize[24]; /* need a constant for len of numbers */
- char sautostop_duration[24]; /* need a constant for len of numbers */
- char save_file_fd[24];
-#ifndef _WIN32
- char errmsg[1024+1];
-#endif
- int error;
- int argc;
- char **argv;
-#ifdef _WIN32
- char sync_pipe_fd[24];
- char *fontstring;
- char *filterstring;
-#endif
-
- /* Allocate the string pointer array with enough space for the
- terminating NULL pointer. */
- argc = 0;
- argv = g_malloc(sizeof (char *));
- *argv = NULL;
-
- /* Now add those arguments used on all platforms. */
- argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
-
- argv = sync_pipe_add_arg(argv, &argc, "-i");
- argv = sync_pipe_add_arg(argv, &argc, cfile.iface);
-
- argv = sync_pipe_add_arg(argv, &argc, "-w");
- argv = sync_pipe_add_arg(argv, &argc, cfile.save_file);
-
- argv = sync_pipe_add_arg(argv, &argc, "-W");
- sprintf(save_file_fd,"%d",cfile.save_file_fd); /* in lieu of itoa */
- argv = sync_pipe_add_arg(argv, &argc, save_file_fd);
-
- if (capture_opts.has_autostop_packets) {
- argv = sync_pipe_add_arg(argv, &argc, "-c");
- sprintf(scount,"%d",capture_opts.autostop_packets);
- argv = sync_pipe_add_arg(argv, &argc, scount);
- }
-
- if (capture_opts.has_snaplen) {
- argv = sync_pipe_add_arg(argv, &argc, "-s");
- sprintf(ssnap,"%d",capture_opts.snaplen);
- argv = sync_pipe_add_arg(argv, &argc, ssnap);
- }
-
- if (capture_opts.linktype != -1) {
- argv = sync_pipe_add_arg(argv, &argc, "-y");
-#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
- sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts.linktype));
-#else
- /* XXX - just treat it as a number */
- sprintf(ssnap,"%d",capture_opts.linktype);
-#endif
- argv = sync_pipe_add_arg(argv, &argc, ssnap);
- }
-
- if (capture_opts.has_autostop_filesize) {
- argv = sync_pipe_add_arg(argv, &argc, "-a");
- sprintf(sautostop_filesize,"filesize:%d",capture_opts.autostop_filesize);
- argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
- }
-
- if (capture_opts.has_autostop_duration) {
- argv = sync_pipe_add_arg(argv, &argc, "-a");
- sprintf(sautostop_duration,"duration:%d",capture_opts.autostop_duration);
- argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
- }
-
- if (!capture_opts.show_info) {
- argv = sync_pipe_add_arg(argv, &argc, "-H");
- }
-
- if (!capture_opts.promisc_mode)
- argv = sync_pipe_add_arg(argv, &argc, "-p");
-
-#ifdef _WIN32
- /* Create a pipe for the child process */
-
- if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
- /* Couldn't create the pipe between parent and child. */
- error = errno;
- unlink(cfile.save_file);
- g_free(cfile.save_file);
- cfile.save_file = NULL;
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
- strerror(error));
- return FALSE;
- }
-
- /* Convert font name to a quote-encapsulated string and pass to child */
- argv = sync_pipe_add_arg(argv, &argc, "-m");
- fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
- argv = sync_pipe_add_arg(argv, &argc, fontstring);
-
- /* Convert pipe write handle to a string and pass to child */
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
- itoa(sync_pipe[WRITE], sync_pipe_fd, 10);
- argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
-
- /* Convert filter string to a quote delimited string and pass to child */
- filterstring = NULL;
- if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
- argv = sync_pipe_add_arg(argv, &argc, "-f");
- filterstring = sync_pipe_quote_encapsulate(cfile.cfilter);
- argv = sync_pipe_add_arg(argv, &argc, filterstring);
- }
-
- /* Spawn process */
- fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
- g_free(fontstring);
- if (filterstring) {
- g_free(filterstring);
- }
-#else
- if (pipe(sync_pipe) < 0) {
- /* Couldn't create the pipe between parent and child. */
- error = errno;
- unlink(cfile.save_file);
- g_free(cfile.save_file);
- cfile.save_file = NULL;
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
- strerror(error));
- return FALSE;
- }
-
- argv = sync_pipe_add_arg(argv, &argc, "-m");
- argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
-
- if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
- argv = sync_pipe_add_arg(argv, &argc, "-f");
- argv = sync_pipe_add_arg(argv, &argc, cfile.cfilter);
- }
-
- if ((fork_child = fork()) == 0) {
- /*
- * Child process - run Ethereal with the right arguments to make
- * it just pop up the live capture dialog box and capture with
- * the specified capture parameters, writing to the specified file.
- *
- * args: -i interface specification
- * -w file to write
- * -W file descriptor to write
- * -c count to capture
- * -s snaplen
- * -m / -b fonts
- * -f "filter expression"
- */
- close(1);
- dup(sync_pipe[WRITE]);
- close(sync_pipe[READ]);
- execvp(ethereal_path, argv);
- snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
- ethereal_path, strerror(errno));
- sync_pipe_errmsg_to_parent(errmsg);
-
- /* Exit with "_exit()", so that we don't close the connection
- to the X server (and cause stuff buffered up by our parent but
- not yet sent to be sent, as that stuff should only be sent by
- our parent). */
- _exit(2);
- }
-#endif
-
- /* Parent process - read messages from the child process over the
- sync pipe. */
- g_free(argv); /* free up arg array */
-
- /* Close the write side of the pipe, so that only the child has it
- open, and thus it completely closes, and thus returns to us
- an EOF indication, if the child closes it (either deliberately
- or by exiting abnormally). */
- close(sync_pipe[WRITE]);
-
- /* Close the save file FD, as we won't be using it - we'll be opening
- it and reading the save file through Wiretap. */
- close(cfile.save_file_fd);
-
- if (fork_child == -1) {
- /* We couldn't even create the child process. */
- error = errno;
- close(sync_pipe[READ]);
- unlink(cfile.save_file);
- g_free(cfile.save_file);
- cfile.save_file = NULL;
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Couldn't create child process: %s", strerror(error));
- return FALSE;
- }
-
- /* Read a byte count from "sync_pipe[READ]", terminated with a
- colon; if the count is 0, the child process created the
- capture file and we should start reading from it, otherwise
- the capture couldn't start and the count is a count of bytes
- of error message, and we should display the message. */
- byte_count = 0;
- for (;;) {
- i = read(sync_pipe[READ], &c, 1);
- if (i == 0) {
- /* EOF - the child process died.
- Close the read side of the sync pipe, remove the capture file,
- and report the failure. */
- close(sync_pipe[READ]);
- unlink(cfile.save_file);
- g_free(cfile.save_file);
- cfile.save_file = NULL;
- sync_pipe_wait_for_child(TRUE);
- return FALSE;
- }
- if (c == SP_CAPSTART || c == SP_ERROR_MSG)
- break;
- if (!isdigit(c)) {
- /* Child process handed us crap.
- Close the read side of the sync pipe, remove the capture file,
- and report the failure. */
- close(sync_pipe[READ]);
- unlink(cfile.save_file);
- g_free(cfile.save_file);
- cfile.save_file = NULL;
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Capture child process sent us a bad message");
- return FALSE;
- }
- byte_count = byte_count*10 + c - '0';
- }
- if (c != SP_CAPSTART) {
- /* Failure - the child process sent us a message indicating
- what the problem was. */
- if (byte_count == 0) {
- /* Zero-length message? */
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Capture child process failed, but its error message was empty.");
- } else {
- msg = g_malloc(byte_count + 1);
- if (msg == NULL) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Capture child process failed, but its error message was too big.");
- } else {
- i = read(sync_pipe[READ], msg, byte_count);
- msg[byte_count] = '\0';
- if (i < 0) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Capture child process failed: Error %s reading its error message.",
- strerror(errno));
- } else if (i == 0) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Capture child process failed: EOF reading its error message.");
- sync_pipe_wait_for_child(FALSE);
- } else
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
- g_free(msg);
- }
-
- /* Close the sync pipe. */
- close(sync_pipe[READ]);
-
- /* Get rid of the save file - the capture never started. */
- unlink(cfile.save_file);
- g_free(cfile.save_file);
- cfile.save_file = NULL;
- }
- return FALSE;
- }
-
- /* The child process started a capture.
- Attempt to open the capture file and set up to read it. */
- err = cf_start_tail(cfile.save_file, is_tempfile, &cfile);
- if (err != 0) {
- /* We weren't able to open the capture file; user has been
- alerted. Close the sync pipe. */
-
- close(sync_pipe[READ]);
-
- /* Don't unlink the save file - leave it around, for debugging
- purposes. */
- g_free(cfile.save_file);
- cfile.save_file = NULL;
- return FALSE;
- }
- /* We were able to open and set up to read the capture file;
- arrange that our callback be called whenever it's possible
- to read from the sync pipe, so that it's called when
- the child process wants to tell us something. */
- pipe_input_set_handler(sync_pipe[READ], (gpointer) &cfile, &fork_child, sync_pipe_input_cb);
-
- return TRUE;
-}
-
-
-/* There's stuff to read from the sync pipe, meaning the child has sent
- us a message, or the sync pipe has closed, meaning the child has
- closed it (perhaps because it exited). */
-static gboolean
-sync_pipe_input_cb(gint source, gpointer user_data)
-{
- capture_file *cf = (capture_file *)user_data;
-#define BUFSIZE 4096
- char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
- int nread, msglen, chars_to_copy;
- int to_read = 0;
- int err;
-
-
- if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
- /* The child has closed the sync pipe, meaning it's not going to be
- capturing any more packets. Pick up its exit status, and
- complain if it did anything other than exit with status 0. */
- sync_pipe_wait_for_child(FALSE);
-
- /* Read what remains of the capture file, and finish the capture.
- XXX - do something if this fails? */
- switch (cf_finish_tail(cf, &err)) {
-
- case READ_SUCCESS:
- if(cf->count == 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(),
- (cf->is_tempfile) ? "temporary " : "");
- cf_close(cf);
- }
- break;
- case 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:
- /* Exit by leaving the main loop, so that any quit functions
- we registered get called. */
- main_window_quit();
- return FALSE;
- }
-
- /* We're not doing a capture any more, so we don't have a save
- file. */
- g_free(cf->save_file);
- cf->save_file = NULL;
-
- return FALSE;
- }
-
- buffer[nread] = '\0';
-
- while (nread != 0) {
- /* look for (possibly multiple) indications */
- switch (*q) {
- case SP_PACKET_COUNT :
- to_read += atoi(p);
- p = q + 1;
- q++;
- nread--;
- break;
- case SP_DROPS :
- cf->drops_known = TRUE;
- cf->drops = atoi(p);
- p = q + 1;
- q++;
- nread--;
- break;
- case SP_ERROR_MSG :
- msglen = atoi(p);
- p = q + 1;
- q++;
- nread--;
-
- /* Read the entire message.
- XXX - if the child hasn't sent it all yet, this could cause us
- to hang until they do. */
- msg = g_malloc(msglen + 1);
- r = msg;
- while (msglen != 0) {
- if (nread == 0) {
- /* Read more. */
- if ((nread = read(source, buffer, BUFSIZE)) <= 0)
- break;
- p = buffer;
- q = buffer;
- }
- chars_to_copy = MIN(msglen, nread);
- memcpy(r, q, chars_to_copy);
- r += chars_to_copy;
- q += chars_to_copy;
- nread -= chars_to_copy;
- msglen -= chars_to_copy;
- }
- *r = '\0';
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
- g_free(msg);
- break;
- default :
- q++;
- nread--;
- break;
- }
- }
-
- /* Read from the capture file the number of records the child told us
- it added.
- XXX - do something if this fails? */
- switch (cf_continue_tail(cf, to_read, &err)) {
-
- case READ_SUCCESS:
- case 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.
-
- XXX - abort on a read error? */
- break;
-
- case READ_ABORTED:
- /* Kill the child capture process; the user wants to exit, and we
- shouldn't just leave it running. */
- kill_capture_child();
- break;
- }
-
- return TRUE;
-}
-
-static void
-sync_pipe_wait_for_child(gboolean always_report)
-{
- int wstatus;
-
-#ifdef _WIN32
- /* XXX - analyze the wait status and display more information
- in the dialog box?
- XXX - set "fork_child" to -1 if we find it exited? */
- if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Child capture process stopped unexpectedly");
- }
-#else
- if (wait(&wstatus) != -1) {
- if (WIFEXITED(wstatus)) {
- /* The child exited; display its exit status, if it's not zero,
- and even if it's zero if "always_report" is true. */
- if (always_report || WEXITSTATUS(wstatus) != 0) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Child capture process exited: exit status %d",
- WEXITSTATUS(wstatus));
- }
- } else if (WIFSTOPPED(wstatus)) {
- /* It stopped, rather than exiting. "Should not happen." */
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Child capture process stopped: %s",
- sync_pipe_signame(WSTOPSIG(wstatus)));
- } else if (WIFSIGNALED(wstatus)) {
- /* It died with a signal. */
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Child capture process died: %s%s",
- sync_pipe_signame(WTERMSIG(wstatus)),
- WCOREDUMP(wstatus) ? " - core dumped" : "");
- } else {
- /* What? It had to either have exited, or stopped, or died with
- a signal; what happened here? */
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Child capture process died: wait status %#o", wstatus);
- }
- }
-
- /* No more child process. */
- fork_child = -1;
-#endif
-}
-
-static void
-sync_pipe_errmsg_to_parent(const char *errmsg)
-{
- int msglen = strlen(errmsg);
- char lenbuf[SP_DECISIZE+1+1];
-
- sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
- write(1, lenbuf, strlen(lenbuf));
- write(1, errmsg, msglen);
-}
-
-static void
-sync_pipe_drops_to_parent(int drops)
-{
- char tmp[SP_DECISIZE+1+1];
- sprintf(tmp, "%d%c", drops, SP_DROPS);
- write(1, tmp, strlen(tmp));
-}
-
-static void
-sync_pipe_packet_count_to_parent(int packet_count)
-{
- char tmp[SP_DECISIZE+1+1];
- sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
- write(1, tmp, strlen(tmp));
-}
-
-static void
-sync_pipe_capstart_to_parent(void)
-{
- static const char capstart_msg = SP_CAPSTART;
-
- write(1, &capstart_msg, 1);
-}
-
-#ifndef _WIN32
-static char *
-sync_pipe_signame(int sig)
-{
- char *sigmsg;
- static char sigmsg_buf[6+1+3+1];
-
- switch (sig) {
-
- case SIGHUP:
- sigmsg = "Hangup";
- break;
-
- case SIGINT:
- sigmsg = "Interrupted";
- break;
-
- case SIGQUIT:
- sigmsg = "Quit";
- break;
-
- case SIGILL:
- sigmsg = "Illegal instruction";
- break;
-
- case SIGTRAP:
- sigmsg = "Trace trap";
- break;
-
- case SIGABRT:
- sigmsg = "Abort";
- break;
-
- case SIGFPE:
- sigmsg = "Arithmetic exception";
- break;
-
- case SIGKILL:
- sigmsg = "Killed";
- break;
-
- case SIGBUS:
- sigmsg = "Bus error";
- break;
-
- case SIGSEGV:
- sigmsg = "Segmentation violation";
- break;
-
- /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
- Linux is POSIX compliant. These are not POSIX-defined signals ---
- ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
-
- ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
- were omitted from POSIX.1 because their behavior is
- implementation dependent and could not be adequately catego-
- rized. Conforming implementations may deliver these sig-
- nals, but must document the circumstances under which they
- are delivered and note any restrictions concerning their
- delivery.''
-
- So we only check for SIGSYS on those systems that happen to
- implement them (a system can be POSIX-compliant and implement
- them, it's just that POSIX doesn't *require* a POSIX-compliant
- system to implement them).
- */
-
-#ifdef SIGSYS
- case SIGSYS:
- sigmsg = "Bad system call";
- break;
-#endif
-
- case SIGPIPE:
- sigmsg = "Broken pipe";
- break;
-
- case SIGALRM:
- sigmsg = "Alarm clock";
- break;
-
- case SIGTERM:
- sigmsg = "Terminated";
- break;
-
- default:
- sprintf(sigmsg_buf, "Signal %d", sig);
- sigmsg = sigmsg_buf;
- break;
- }
- return sigmsg;
-}
-#endif
-
-
-
-
+/* start a normal capture session */
static gboolean
normal_do_capture(gboolean is_tempfile)
{
@@ -2213,24 +1534,9 @@ stop_capture_signal_handler(int signo _U_)
void
capture_stop(void)
{
- if (fork_child != -1) {
-#ifndef _WIN32
- kill(fork_child, SIGUSR1);
-#else
- /* XXX: this is not the preferred method of closing a process!
- * the clean way would be getting the process id of the child process,
- * then getting window handle hWnd of that process (using EnumChildWindows),
- * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
- *
- * Unfortunately, I don't know how to get the process id from the handle */
- /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
- *
- * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
- * running in the same console, I don't know if that is true for our case.
- * And this also will require to have the process id
- */
- TerminateProcess((HANDLE) fork_child, 0);
-#endif
+
+ if (capture_opts.sync_mode) {
+ sync_pipe_stop();
} else {
ld.go = FALSE;
}
@@ -2239,24 +1545,9 @@ capture_stop(void)
void
kill_capture_child(void)
{
- if (fork_child != -1)
-#ifndef _WIN32
- kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
-#else
- /* XXX: this is not the preferred method of closing a process!
- * the clean way would be getting the process id of the child process,
- * then getting window handle hWnd of that process (using EnumChildWindows),
- * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
- *
- * Unfortunately, I don't know how to get the process id from the handle */
- /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
- *
- * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
- * running in the same console, I don't know if that is true for our case.
- * And this also will require to have the process id
- */
- TerminateProcess((HANDLE) fork_child, 0);
-#endif
+ if (capture_opts.sync_mode) {
+ sync_pipe_kill();
+ }
}
/* one packet was captured, process it */
diff --git a/capture_sync.c b/capture_sync.c
new file mode 100644
index 0000000000..11d8007177
--- /dev/null
+++ b/capture_sync.c
@@ -0,0 +1,796 @@
+/* capture_sync.c
+ * Synchronisation between Ethereal capture parent and child instances
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * 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
+
+#ifdef HAVE_LIBPCAP
+
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+
+#include "globals.h"
+
+#include "capture.h"
+#include "capture_sync.h"
+#include "simple_dialog.h"
+
+#ifdef _WIN32
+#include "capture-wpcap.h"
+#endif
+#include "ui_util.h"
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+int fork_child = -1; /* If not -1, in parent, process ID of child */
+
+#ifdef _WIN32
+#include <process.h> /* For spawning child process */
+#endif
+
+/* Win32 needs the O_BINARY flag for open() */
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+
+#ifndef _WIN32
+static char *sync_pipe_signame(int);
+#endif
+
+
+static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
+static void sync_pipe_wait_for_child(gboolean always_report);
+
+/* Size of buffer to hold decimal representation of
+ signed/unsigned 64-bit int */
+#define SP_DECISIZE 20
+
+/*
+ * Indications sent out on the sync pipe.
+ */
+#define SP_CAPSTART ';' /* capture start message */
+#define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */
+#define SP_ERROR_MSG '!' /* followed by length of error message that follows */
+#define SP_DROPS '#' /* followed by count of packets dropped in capture */
+
+
+
+/* Add a string pointer to a NULL-terminated array of string pointers. */
+static char **
+sync_pipe_add_arg(char **args, int *argc, char *arg)
+{
+ /* Grow the array; "*argc" currently contains the number of string
+ pointers, *not* counting the NULL pointer at the end, so we have
+ to add 2 in order to get the new size of the array, including the
+ new pointer and the terminating NULL pointer. */
+ args = g_realloc(args, (*argc + 2) * sizeof (char *));
+
+ /* Stuff the pointer into the penultimate element of the array, which
+ is the one at the index specified by "*argc". */
+ args[*argc] = arg;
+
+ /* Now bump the count. */
+ (*argc)++;
+
+ /* We overwrite the NULL pointer; put it back right after the
+ element we added. */
+ args[*argc] = NULL;
+
+ return args;
+}
+
+#ifdef _WIN32
+/* Given a string, return a pointer to a quote-encapsulated version of
+ the string, so we can pass it as an argument with "spawnvp" even
+ if it contains blanks. */
+char *
+sync_pipe_quote_encapsulate(const char *string)
+{
+ char *encapsulated_string;
+
+ encapsulated_string = g_new(char, strlen(string) + 3);
+ sprintf(encapsulated_string, "\"%s\"", string);
+ return encapsulated_string;
+}
+#endif
+
+
+
+gboolean
+sync_pipe_do_capture(gboolean is_tempfile) {
+ guint byte_count;
+ int i;
+ guchar c;
+ char *msg;
+ int err;
+ char ssnap[24];
+ char scount[24]; /* need a constant for len of numbers */
+ char sautostop_filesize[24]; /* need a constant for len of numbers */
+ char sautostop_duration[24]; /* need a constant for len of numbers */
+ char save_file_fd[24];
+#ifndef _WIN32
+ char errmsg[1024+1];
+#endif
+ int error;
+ int argc;
+ char **argv;
+#ifdef _WIN32
+ char sync_pipe_fd[24];
+ char *fontstring;
+ char *filterstring;
+#endif
+ enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
+ int sync_pipe[2]; /* pipes used to sync between instances */
+
+
+ fork_child = -1;
+
+ /* Allocate the string pointer array with enough space for the
+ terminating NULL pointer. */
+ argc = 0;
+ argv = g_malloc(sizeof (char *));
+ *argv = NULL;
+
+ /* Now add those arguments used on all platforms. */
+ argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
+
+ argv = sync_pipe_add_arg(argv, &argc, "-i");
+ argv = sync_pipe_add_arg(argv, &argc, cfile.iface);
+
+ argv = sync_pipe_add_arg(argv, &argc, "-w");
+ argv = sync_pipe_add_arg(argv, &argc, cfile.save_file);
+
+ argv = sync_pipe_add_arg(argv, &argc, "-W");
+ sprintf(save_file_fd,"%d",cfile.save_file_fd); /* in lieu of itoa */
+ argv = sync_pipe_add_arg(argv, &argc, save_file_fd);
+
+ if (capture_opts.has_autostop_packets) {
+ argv = sync_pipe_add_arg(argv, &argc, "-c");
+ sprintf(scount,"%d",capture_opts.autostop_packets);
+ argv = sync_pipe_add_arg(argv, &argc, scount);
+ }
+
+ if (capture_opts.has_snaplen) {
+ argv = sync_pipe_add_arg(argv, &argc, "-s");
+ sprintf(ssnap,"%d",capture_opts.snaplen);
+ argv = sync_pipe_add_arg(argv, &argc, ssnap);
+ }
+
+ if (capture_opts.linktype != -1) {
+ argv = sync_pipe_add_arg(argv, &argc, "-y");
+#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
+ sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts.linktype));
+#else
+ /* XXX - just treat it as a number */
+ sprintf(ssnap,"%d",capture_opts.linktype);
+#endif
+ argv = sync_pipe_add_arg(argv, &argc, ssnap);
+ }
+
+ if (capture_opts.has_autostop_filesize) {
+ argv = sync_pipe_add_arg(argv, &argc, "-a");
+ sprintf(sautostop_filesize,"filesize:%d",capture_opts.autostop_filesize);
+ argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
+ }
+
+ if (capture_opts.has_autostop_duration) {
+ argv = sync_pipe_add_arg(argv, &argc, "-a");
+ sprintf(sautostop_duration,"duration:%d",capture_opts.autostop_duration);
+ argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
+ }
+
+ if (!capture_opts.show_info) {
+ argv = sync_pipe_add_arg(argv, &argc, "-H");
+ }
+
+ if (!capture_opts.promisc_mode)
+ argv = sync_pipe_add_arg(argv, &argc, "-p");
+
+#ifdef _WIN32
+ /* Create a pipe for the child process */
+
+ if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
+ /* Couldn't create the pipe between parent and child. */
+ error = errno;
+ unlink(cfile.save_file);
+ g_free(cfile.save_file);
+ cfile.save_file = NULL;
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
+ strerror(error));
+ return FALSE;
+ }
+
+ /* Convert font name to a quote-encapsulated string and pass to child */
+ argv = sync_pipe_add_arg(argv, &argc, "-m");
+ fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
+ argv = sync_pipe_add_arg(argv, &argc, fontstring);
+
+ /* Convert pipe write handle to a string and pass to child */
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+ itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
+ argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
+
+ /* Convert filter string to a quote delimited string and pass to child */
+ filterstring = NULL;
+ if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
+ argv = sync_pipe_add_arg(argv, &argc, "-f");
+ filterstring = sync_pipe_quote_encapsulate(cfile.cfilter);
+ argv = sync_pipe_add_arg(argv, &argc, filterstring);
+ }
+
+ /* Spawn process */
+ fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
+ g_free(fontstring);
+ if (filterstring) {
+ g_free(filterstring);
+ }
+#else
+ if (pipe(sync_pipe) < 0) {
+ /* Couldn't create the pipe between parent and child. */
+ error = errno;
+ unlink(cfile.save_file);
+ g_free(cfile.save_file);
+ cfile.save_file = NULL;
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
+ strerror(error));
+ return FALSE;
+ }
+
+ argv = sync_pipe_add_arg(argv, &argc, "-m");
+ argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
+
+ if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
+ argv = sync_pipe_add_arg(argv, &argc, "-f");
+ argv = sync_pipe_add_arg(argv, &argc, cfile.cfilter);
+ }
+
+ if ((fork_child = fork()) == 0) {
+ /*
+ * Child process - run Ethereal with the right arguments to make
+ * it just pop up the live capture dialog box and capture with
+ * the specified capture parameters, writing to the specified file.
+ *
+ * args: -i interface specification
+ * -w file to write
+ * -W file descriptor to write
+ * -c count to capture
+ * -s snaplen
+ * -m / -b fonts
+ * -f "filter expression"
+ */
+ close(1);
+ dup(sync_pipe[PIPE_WRITE]);
+ close(sync_pipe[PIPE_READ]);
+ execvp(ethereal_path, argv);
+ snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
+ ethereal_path, strerror(errno));
+ sync_pipe_errmsg_to_parent(errmsg);
+
+ /* Exit with "_exit()", so that we don't close the connection
+ to the X server (and cause stuff buffered up by our parent but
+ not yet sent to be sent, as that stuff should only be sent by
+ our parent). */
+ _exit(2);
+ }
+#endif
+
+ /* Parent process - read messages from the child process over the
+ sync pipe. */
+ g_free(argv); /* free up arg array */
+
+ /* Close the write side of the pipe, so that only the child has it
+ open, and thus it completely closes, and thus returns to us
+ an EOF indication, if the child closes it (either deliberately
+ or by exiting abnormally). */
+ close(sync_pipe[PIPE_WRITE]);
+
+ /* Close the save file FD, as we won't be using it - we'll be opening
+ it and reading the save file through Wiretap. */
+ close(cfile.save_file_fd);
+
+ if (fork_child == -1) {
+ /* We couldn't even create the child process. */
+ error = errno;
+ close(sync_pipe[PIPE_READ]);
+ unlink(cfile.save_file);
+ g_free(cfile.save_file);
+ cfile.save_file = NULL;
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Couldn't create child process: %s", strerror(error));
+ return FALSE;
+ }
+
+ /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
+ colon; if the count is 0, the child process created the
+ capture file and we should start reading from it, otherwise
+ the capture couldn't start and the count is a count of bytes
+ of error message, and we should display the message. */
+ byte_count = 0;
+ for (;;) {
+ i = read(sync_pipe[PIPE_READ], &c, 1);
+ if (i == 0) {
+ /* EOF - the child process died.
+ Close the read side of the sync pipe, remove the capture file,
+ and report the failure. */
+ close(sync_pipe[PIPE_READ]);
+ unlink(cfile.save_file);
+ g_free(cfile.save_file);
+ cfile.save_file = NULL;
+ sync_pipe_wait_for_child(TRUE);
+ return FALSE;
+ }
+ if (c == SP_CAPSTART || c == SP_ERROR_MSG)
+ break;
+ if (!isdigit(c)) {
+ /* Child process handed us crap.
+ Close the read side of the sync pipe, remove the capture file,
+ and report the failure. */
+ close(sync_pipe[PIPE_READ]);
+ unlink(cfile.save_file);
+ g_free(cfile.save_file);
+ cfile.save_file = NULL;
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Capture child process sent us a bad message");
+ return FALSE;
+ }
+ byte_count = byte_count*10 + c - '0';
+ }
+ if (c != SP_CAPSTART) {
+ /* Failure - the child process sent us a message indicating
+ what the problem was. */
+ if (byte_count == 0) {
+ /* Zero-length message? */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Capture child process failed, but its error message was empty.");
+ } else {
+ msg = g_malloc(byte_count + 1);
+ if (msg == NULL) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Capture child process failed, but its error message was too big.");
+ } else {
+ i = read(sync_pipe[PIPE_READ], msg, byte_count);
+ msg[byte_count] = '\0';
+ if (i < 0) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Capture child process failed: Error %s reading its error message.",
+ strerror(errno));
+ } else if (i == 0) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Capture child process failed: EOF reading its error message.");
+ sync_pipe_wait_for_child(FALSE);
+ } else
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
+ g_free(msg);
+ }
+
+ /* Close the sync pipe. */
+ close(sync_pipe[PIPE_READ]);
+
+ /* Get rid of the save file - the capture never started. */
+ unlink(cfile.save_file);
+ g_free(cfile.save_file);
+ cfile.save_file = NULL;
+ }
+ return FALSE;
+ }
+
+ /* The child process started a capture.
+ Attempt to open the capture file and set up to read it. */
+ err = cf_start_tail(cfile.save_file, is_tempfile, &cfile);
+ if (err != 0) {
+ /* We weren't able to open the capture file; user has been
+ alerted. Close the sync pipe. */
+
+ close(sync_pipe[PIPE_READ]);
+
+ /* Don't unlink the save file - leave it around, for debugging
+ purposes. */
+ g_free(cfile.save_file);
+ cfile.save_file = NULL;
+ return FALSE;
+ }
+ /* We were able to open and set up to read the capture file;
+ arrange that our callback be called whenever it's possible
+ to read from the sync pipe, so that it's called when
+ the child process wants to tell us something. */
+ pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) &cfile, &fork_child, sync_pipe_input_cb);
+
+ return TRUE;
+}
+
+
+/* There's stuff to read from the sync pipe, meaning the child has sent
+ us a message, or the sync pipe has closed, meaning the child has
+ closed it (perhaps because it exited). */
+static gboolean
+sync_pipe_input_cb(gint source, gpointer user_data)
+{
+ capture_file *cf = (capture_file *)user_data;
+#define BUFSIZE 4096
+ char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
+ int nread, msglen, chars_to_copy;
+ int to_read = 0;
+ int err;
+
+
+ if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
+ /* The child has closed the sync pipe, meaning it's not going to be
+ capturing any more packets. Pick up its exit status, and
+ complain if it did anything other than exit with status 0. */
+ sync_pipe_wait_for_child(FALSE);
+
+ /* Read what remains of the capture file, and finish the capture.
+ XXX - do something if this fails? */
+ switch (cf_finish_tail(cf, &err)) {
+
+ case READ_SUCCESS:
+ if(cf->count == 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(),
+ (cf->is_tempfile) ? "temporary " : "");
+ cf_close(cf);
+ }
+ break;
+ case 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:
+ /* Exit by leaving the main loop, so that any quit functions
+ we registered get called. */
+ main_window_quit();
+ return FALSE;
+ }
+
+ /* We're not doing a capture any more, so we don't have a save
+ file. */
+ g_free(cf->save_file);
+ cf->save_file = NULL;
+
+ return FALSE;
+ }
+
+ buffer[nread] = '\0';
+
+ while (nread != 0) {
+ /* look for (possibly multiple) indications */
+ switch (*q) {
+ case SP_PACKET_COUNT :
+ to_read += atoi(p);
+ p = q + 1;
+ q++;
+ nread--;
+ break;
+ case SP_DROPS :
+ cf->drops_known = TRUE;
+ cf->drops = atoi(p);
+ p = q + 1;
+ q++;
+ nread--;
+ break;
+ case SP_ERROR_MSG :
+ msglen = atoi(p);
+ p = q + 1;
+ q++;
+ nread--;
+
+ /* Read the entire message.
+ XXX - if the child hasn't sent it all yet, this could cause us
+ to hang until they do. */
+ msg = g_malloc(msglen + 1);
+ r = msg;
+ while (msglen != 0) {
+ if (nread == 0) {
+ /* Read more. */
+ if ((nread = read(source, buffer, BUFSIZE)) <= 0)
+ break;
+ p = buffer;
+ q = buffer;
+ }
+ chars_to_copy = MIN(msglen, nread);
+ memcpy(r, q, chars_to_copy);
+ r += chars_to_copy;
+ q += chars_to_copy;
+ nread -= chars_to_copy;
+ msglen -= chars_to_copy;
+ }
+ *r = '\0';
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
+ g_free(msg);
+ break;
+ default :
+ q++;
+ nread--;
+ break;
+ }
+ }
+
+ /* Read from the capture file the number of records the child told us
+ it added.
+ XXX - do something if this fails? */
+ switch (cf_continue_tail(cf, to_read, &err)) {
+
+ case READ_SUCCESS:
+ case 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.
+
+ XXX - abort on a read error? */
+ break;
+
+ case READ_ABORTED:
+ /* Kill the child capture process; the user wants to exit, and we
+ shouldn't just leave it running. */
+ kill_capture_child();
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+sync_pipe_wait_for_child(gboolean always_report)
+{
+ int wstatus;
+
+#ifdef _WIN32
+ /* XXX - analyze the wait status and display more information
+ in the dialog box?
+ XXX - set "fork_child" to -1 if we find it exited? */
+ if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Child capture process stopped unexpectedly");
+ }
+#else
+ if (wait(&wstatus) != -1) {
+ if (WIFEXITED(wstatus)) {
+ /* The child exited; display its exit status, if it's not zero,
+ and even if it's zero if "always_report" is true. */
+ if (always_report || WEXITSTATUS(wstatus) != 0) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Child capture process exited: exit status %d",
+ WEXITSTATUS(wstatus));
+ }
+ } else if (WIFSTOPPED(wstatus)) {
+ /* It stopped, rather than exiting. "Should not happen." */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Child capture process stopped: %s",
+ sync_pipe_signame(WSTOPSIG(wstatus)));
+ } else if (WIFSIGNALED(wstatus)) {
+ /* It died with a signal. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Child capture process died: %s%s",
+ sync_pipe_signame(WTERMSIG(wstatus)),
+ WCOREDUMP(wstatus) ? " - core dumped" : "");
+ } else {
+ /* What? It had to either have exited, or stopped, or died with
+ a signal; what happened here? */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Child capture process died: wait status %#o", wstatus);
+ }
+ }
+
+ /* No more child process. */
+ fork_child = -1;
+#endif
+}
+
+void
+sync_pipe_errmsg_to_parent(const char *errmsg)
+{
+ int msglen = strlen(errmsg);
+ char lenbuf[SP_DECISIZE+1+1];
+
+ sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
+ write(1, lenbuf, strlen(lenbuf));
+ write(1, errmsg, msglen);
+}
+
+void
+sync_pipe_drops_to_parent(int drops)
+{
+ char tmp[SP_DECISIZE+1+1];
+ sprintf(tmp, "%d%c", drops, SP_DROPS);
+ write(1, tmp, strlen(tmp));
+}
+
+void
+sync_pipe_packet_count_to_parent(int packet_count)
+{
+ char tmp[SP_DECISIZE+1+1];
+ sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
+ write(1, tmp, strlen(tmp));
+}
+
+void
+sync_pipe_capstart_to_parent(void)
+{
+ static const char capstart_msg = SP_CAPSTART;
+
+ write(1, &capstart_msg, 1);
+}
+
+#ifndef _WIN32
+static char *
+sync_pipe_signame(int sig)
+{
+ char *sigmsg;
+ static char sigmsg_buf[6+1+3+1];
+
+ switch (sig) {
+
+ case SIGHUP:
+ sigmsg = "Hangup";
+ break;
+
+ case SIGINT:
+ sigmsg = "Interrupted";
+ break;
+
+ case SIGQUIT:
+ sigmsg = "Quit";
+ break;
+
+ case SIGILL:
+ sigmsg = "Illegal instruction";
+ break;
+
+ case SIGTRAP:
+ sigmsg = "Trace trap";
+ break;
+
+ case SIGABRT:
+ sigmsg = "Abort";
+ break;
+
+ case SIGFPE:
+ sigmsg = "Arithmetic exception";
+ break;
+
+ case SIGKILL:
+ sigmsg = "Killed";
+ break;
+
+ case SIGBUS:
+ sigmsg = "Bus error";
+ break;
+
+ case SIGSEGV:
+ sigmsg = "Segmentation violation";
+ break;
+
+ /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
+ Linux is POSIX compliant. These are not POSIX-defined signals ---
+ ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
+
+ ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
+ were omitted from POSIX.1 because their behavior is
+ implementation dependent and could not be adequately catego-
+ rized. Conforming implementations may deliver these sig-
+ nals, but must document the circumstances under which they
+ are delivered and note any restrictions concerning their
+ delivery.''
+
+ So we only check for SIGSYS on those systems that happen to
+ implement them (a system can be POSIX-compliant and implement
+ them, it's just that POSIX doesn't *require* a POSIX-compliant
+ system to implement them).
+ */
+
+#ifdef SIGSYS
+ case SIGSYS:
+ sigmsg = "Bad system call";
+ break;
+#endif
+
+ case SIGPIPE:
+ sigmsg = "Broken pipe";
+ break;
+
+ case SIGALRM:
+ sigmsg = "Alarm clock";
+ break;
+
+ case SIGTERM:
+ sigmsg = "Terminated";
+ break;
+
+ default:
+ sprintf(sigmsg_buf, "Signal %d", sig);
+ sigmsg = sigmsg_buf;
+ break;
+ }
+ return sigmsg;
+}
+#endif
+
+
+void
+sync_pipe_stop(void)
+{
+ if (fork_child != -1) {
+#ifndef _WIN32
+ kill(fork_child, SIGUSR1);
+#else
+ /* XXX: this is not the preferred method of closing a process!
+ * the clean way would be getting the process id of the child process,
+ * then getting window handle hWnd of that process (using EnumChildWindows),
+ * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
+ *
+ * Unfortunately, I don't know how to get the process id from the handle */
+ /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
+ *
+ * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
+ * running in the same console, I don't know if that is true for our case.
+ * And this also will require to have the process id
+ */
+ TerminateProcess((HANDLE) fork_child, 0);
+#endif
+ }
+}
+
+
+void
+sync_pipe_kill(void)
+{
+ if (fork_child != -1)
+#ifndef _WIN32
+ kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
+#else
+ /* XXX: this is not the preferred method of closing a process!
+ * the clean way would be getting the process id of the child process,
+ * then getting window handle hWnd of that process (using EnumChildWindows),
+ * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
+ *
+ * Unfortunately, I don't know how to get the process id from the handle */
+ /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
+ *
+ * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
+ * running in the same console, I don't know if that is true for our case.
+ * And this also will require to have the process id
+ */
+ TerminateProcess((HANDLE) fork_child, 0);
+#endif
+}
+
+
+#endif /* HAVE_LIBPCAP */
diff --git a/capture_sync.h b/capture_sync.h
new file mode 100644
index 0000000000..b82fcd4b4b
--- /dev/null
+++ b/capture_sync.h
@@ -0,0 +1,76 @@
+/* capture_sync.h
+ * Synchronisation between Ethereal capture parent and child instances
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+/** @file
+ *
+ * Sync mode capture (internal interface).
+ *
+ * Will start a new Ethereal instance which will do the actual capture work.
+ * This is only used, if the "Update list of packets in real time" option is
+ * used.
+ */
+
+#ifndef __CAPTURE_SYNC_H__
+#define __CAPTURE_SYNC_H__
+
+/**
+ * Start a new synced capture session.
+ * Create a capture child which is doing the real capture work.
+ *
+ * Most of the parameters are passed through the global capture_opts.
+ *
+ * @param is_tempfile TRUE if the current cfile is a tempfile
+ * @return TRUE if a capture could be started, FALSE if not
+ */
+extern gboolean
+sync_pipe_do_capture(gboolean is_tempfile);
+
+/** User wants to stop capturing, gracefully close the capture child */
+extern void
+sync_pipe_stop(void);
+
+/** We want to stop the program, just kill the child as soon as possible */
+extern void
+sync_pipe_kill(void);
+
+
+/** the child will immediately start capturing, notify the parent */
+extern void
+sync_pipe_capstart_to_parent(void);
+
+/** the child captured some new packets, notify the parent */
+extern void
+sync_pipe_packet_count_to_parent(int packet_count);
+
+/** the child stopped capturing, notify the parent */
+extern void
+sync_pipe_drops_to_parent(int drops);
+
+/** the child encountered an error, notify the parent */
+extern void
+sync_pipe_errmsg_to_parent(const char *errmsg);
+
+
+#endif /* capture_sync.h */