aboutsummaryrefslogtreecommitdiffstats
path: root/capture/capture_sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'capture/capture_sync.c')
-rw-r--r--capture/capture_sync.c1665
1 files changed, 957 insertions, 708 deletions
diff --git a/capture/capture_sync.c b/capture/capture_sync.c
index 5ce1d479da..4734d0dcd3 100644
--- a/capture/capture_sync.c
+++ b/capture/capture_sync.c
@@ -11,23 +11,27 @@
#include "config.h"
#define WS_LOG_DOMAIN LOG_DOMAIN_CAPTURE
+#include <wireshark.h>
+
#ifdef HAVE_LIBPCAP
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <signal.h>
+#include <ws_exit_codes.h>
+
#include <wsutil/strtoi.h>
-#include <wsutil/wslog.h>
#include <wsutil/ws_assert.h>
#ifdef _WIN32
#include <wsutil/unicode-utils.h>
#include <wsutil/win32-utils.h>
#include <wsutil/ws_pipe.h>
+#else
+#include <glib-unix.h>
#endif
#ifdef HAVE_SYS_WAIT_H
@@ -92,30 +96,27 @@
#include <wsutil/ws_pipe.h>
#ifdef _WIN32
-static void create_dummy_signal_pipe();
+static int create_dummy_signal_pipe(char **msg);
static HANDLE dummy_signal_pipe; /* Dummy named pipe which lets the child check for a dropped connection */
-static gchar *dummy_control_id;
+static char *dummy_control_id;
#else
static const char *sync_pipe_signame(int);
#endif
+/* We use this pipe buffer size for both the sync message pipe and the
+ * data pipe. Ensure that it's large enough for the indicator and header
+ * plus maximum message size.
+ */
+#define PIPE_BUF_SIZE (SP_MAX_MSG_LEN+4)
-static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
-static int sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp);
-static void pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len);
-static ssize_t pipe_read_block(int pipe_fd, char *indicator, int len, char *msg,
+static gboolean sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session);
+static int sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp);
+static void pipe_convert_header(const unsigned char *header, int header_len, char *indicator, int *block_len);
+static ssize_t pipe_read_block(GIOChannel *pipe_io, char *indicator, int len, char *msg,
char **err_msg);
static void (*fetch_dumpcap_pid)(ws_process_id) = NULL;
-static void free_argv(char** argv, int argc)
-{
- int i;
- for (i = 0; i < argc; i++)
- g_free(argv[i]);
- g_free(argv);
-}
-
void
capture_session_init(capture_session *cap_session, capture_file *cf,
new_file_fn new_file, new_packets_fn new_packets,
@@ -124,6 +125,7 @@ capture_session_init(capture_session *cap_session, capture_file *cf,
{
cap_session->cf = cf;
cap_session->fork_child = WS_INVALID_PID; /* invalid process handle */
+ cap_session->pipe_input_id = 0;
#ifdef _WIN32
cap_session->signal_pipe_write_fd = -1;
#endif
@@ -133,7 +135,8 @@ capture_session_init(capture_session *cap_session, capture_file *cf,
cap_session->group = getgid();
#endif
cap_session->count = 0;
- cap_session->session_will_restart = FALSE;
+ cap_session->count_pending = 0;
+ cap_session->session_will_restart = false;
cap_session->new_file = new_file;
cap_session->new_packets = new_packets;
@@ -141,10 +144,60 @@ capture_session_init(capture_session *cap_session, capture_file *cf,
cap_session->error = error;
cap_session->cfilter_error = cfilter_error;
cap_session->closed = closed;
+ cap_session->frame_cksum = NULL;
+}
+
+void capture_process_finished(capture_session *cap_session)
+{
+ capture_options *capture_opts = cap_session->capture_opts;
+ interface_options *interface_opts;
+ GString *message;
+ unsigned i;
+
+ if (!extcap_session_stop(cap_session)) {
+ /* Atleast one extcap process did not fully finish yet, wait for it */
+ return;
+ }
+
+ if (cap_session->fork_child != WS_INVALID_PID) {
+ if (capture_opts->stop_after_extcaps) {
+ /* User has requested capture stop and all extcaps are gone now */
+ capture_opts->stop_after_extcaps = false;
+ sync_pipe_stop(cap_session);
+ }
+ /* Wait for child process to end, session is not closed yet */
+ return;
+ }
+
+ /* Construct message and close session */
+ message = g_string_new(capture_opts->closed_msg);
+ for (i = 0; i < capture_opts->ifaces->len; i++) {
+ interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
+ if (interface_opts->if_type != IF_EXTCAP) {
+ continue;
+ }
+
+ if ((interface_opts->extcap_stderr != NULL) &&
+ (interface_opts->extcap_stderr->len > 0)) {
+ if (message->len > 0) {
+ g_string_append(message, "\n");
+ }
+ g_string_append(message, "Error from extcap pipe: ");
+ g_string_append(message, interface_opts->extcap_stderr->str);
+ }
+ }
+
+ cap_session->closed(cap_session, message->str);
+ g_string_free(message, true);
+ g_free(capture_opts->closed_msg);
+ capture_opts->closed_msg = NULL;
+ capture_opts->stop_after_extcaps = false;
}
/* Append an arg (realloc) to an argc/argv array */
/* (add a string pointer to a NULL-terminated array of string pointers) */
+/* XXX: For glib >= 2.68 we could use a GStrvBuilder.
+ */
static char **
sync_pipe_add_arg(char **args, int *argc, const char *arg)
{
@@ -152,7 +205,7 @@ sync_pipe_add_arg(char **args, int *argc, const char *arg)
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 = (char **)g_realloc( (gpointer) args, (*argc + 2) * sizeof (char *));
+ args = (char **)g_realloc( (void *) 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". */
@@ -167,16 +220,33 @@ sync_pipe_add_arg(char **args, int *argc, const char *arg)
return args;
}
+/* Take a buffer from an SP_LOG_MSG from dumpcap and send it to our
+ * current logger. Keep this in sync with the format used in
+ * dumpcap_log_writer. (We might want to do more proper serialization
+ * of more than just the log level.)
+ */
+static void
+sync_pipe_handle_log_msg(const char *buffer) {
+ const char *log_msg = NULL;
+ const char* end;
+ uint32_t level = 0;
+
+ if (ws_strtou32(buffer, &end, &level) && end[0] == ':') {
+ log_msg = end + 1;
+ }
+ ws_log(LOG_DOMAIN_CAPCHILD, level, "%s", log_msg);
+}
+
/* Initialize an argument list and add dumpcap to it. */
static char **
init_pipe_args(int *argc) {
- char **argv;
- const char *progfile_dir;
char *exename;
+ char **argv;
- progfile_dir = get_progfile_dir();
- if (progfile_dir == NULL) {
- return NULL;
+ /* Find the absolute path of the dumpcap executable. */
+ exename = get_executable_path("dumpcap");
+ if (exename == NULL) {
+ return NULL;
}
/* Allocate the string pointer array with enough space for the
@@ -185,70 +255,455 @@ init_pipe_args(int *argc) {
argv = (char **)g_malloc(sizeof (char *));
*argv = NULL;
- /* take Wireshark's absolute program path and replace "Wireshark" with "dumpcap" */
-#ifdef _WIN32
- exename = g_strdup_printf("%s\\dumpcap.exe", progfile_dir);
-#else
- exename = g_strdup_printf("%s/dumpcap", progfile_dir);
-#endif
-
/* Make that the first argument in the argument list (argv[0]). */
argv = sync_pipe_add_arg(argv, argc, exename);
+ /* Tell dumpcap to log at the lowest level its domain (Capchild) is
+ * set to log in the main program. (It might be in the special noisy
+ * or debug filter, so we can't just check the overall level.)
+ */
+ for (enum ws_log_level level = LOG_LEVEL_NOISY; level != _LOG_LEVEL_LAST; level++) {
+ if (ws_log_msg_is_active(LOG_DOMAIN_CAPCHILD, level)) {
+ argv = sync_pipe_add_arg(argv, argc, "--log-level");
+ argv = sync_pipe_add_arg(argv, argc, ws_log_level_to_string(level));
+ break;
+ }
+ }
+
/* sync_pipe_add_arg strdupes exename, so we should free our copy */
g_free(exename);
return argv;
}
+static gboolean
+pipe_io_cb(GIOChannel *pipe_io, GIOCondition condition _U_, void * user_data)
+{
+ capture_session *cap_session = (capture_session *)user_data;
+ if (!sync_pipe_input_cb(pipe_io, cap_session)) {
+ cap_session->pipe_input_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+ return G_SOURCE_CONTINUE;
+}
+
+/*
+ * Open two pipes to dumpcap with the supplied arguments, one for its
+ * standard output and one for its standard error.
+ *
+ * On success, *msg is unchanged and 0 is returned; data_read_fd,
+ * message_read_fd, and fork_child point to the standard output pipe's
+ * file descriptor, the standard error pipe's file descriptor, and
+ * the child's PID/handle, respectively.
+ *
+ * On failure, *msg points to an error message for the failure, and -1 is
+ * returned, in which case *msg must be freed with g_free().
+ */
#define ARGV_NUMBER_LEN 24
-/* a new capture run: start a new dumpcap task and hand over parameters through command line */
-gboolean
-sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
- capture_session *cap_session, info_data_t* cap_data,
- void (*update_cb)(void))
+static int
+#ifdef _WIN32
+sync_pipe_open_command(char **argv, int *data_read_fd,
+ GIOChannel **message_read_io, int *signal_write_fd,
+ ws_process_id *fork_child, GArray *ifaces,
+ char **msg, void(*update_cb)(void))
+#else
+sync_pipe_open_command(char **argv, int *data_read_fd,
+ GIOChannel **message_read_io, int *signal_write_fd _U_,
+ ws_process_id *fork_child, GArray *ifaces _U_,
+ char **msg, void(*update_cb)(void))
+#endif
{
+ enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
+ int message_read_fd = -1;
+ char sync_id[ARGV_NUMBER_LEN];
#ifdef _WIN32
- HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */
- HANDLE sync_pipe_write; /* pipe used to send messages from child to parent */
- int signal_pipe_write_fd;
+ HANDLE sync_pipe[2]; /* pipe used to send messages from child to parent */
+ HANDLE data_pipe[2]; /* pipe used to send data from child to parent */
+ int signal_pipe_write_fd = -1;
HANDLE signal_pipe; /* named pipe used to send messages from parent to child (currently only stop) */
+ char control_id[ARGV_NUMBER_LEN];
+ char *signal_pipe_name;
+ size_t i_handles = 0;
+ HANDLE *handles;
GString *args = g_string_sized_new(200);
- gchar *quoted_arg;
+ char *quoted_arg;
SECURITY_ATTRIBUTES sa;
STARTUPINFO si;
PROCESS_INFORMATION pi;
- char control_id[ARGV_NUMBER_LEN];
- gchar *signal_pipe_name;
+ int i;
+ unsigned j;
+ interface_options *interface_opts;
#else
- char errmsg[1024+1];
int sync_pipe[2]; /* pipe used to send messages from child to parent */
- enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
+ int data_pipe[2]; /* pipe used to send data from child to parent */
+#endif
+ *fork_child = WS_INVALID_PID;
+ if (data_read_fd != NULL) {
+ *data_read_fd = -1;
+ }
+ *message_read_io = NULL;
+ ws_debug("sync_pipe_open_command");
+
+ if (!msg) {
+ /* We can't return anything */
+ g_strfreev(argv);
+#ifdef _WIN32
+ g_string_free(args, true);
+#endif
+ return -1;
+ }
+
+#ifdef _WIN32
+ /* init SECURITY_ATTRIBUTES */
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = false;
+ sa.lpSecurityDescriptor = NULL;
+
+ /* Create a pipe for the child process to send us messages */
+ /* (increase this value if you have trouble while fast capture file switches) */
+ if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, PIPE_BUF_SIZE)) {
+ /* Couldn't create the message pipe between parent and child. */
+ *msg = ws_strdup_printf("Couldn't create sync pipe: %s",
+ win32strerror(GetLastError()));
+ g_strfreev(argv);
+ return -1;
+ }
+
+ /*
+ * Associate a C run-time file handle with the Windows HANDLE for the
+ * read side of the message pipe.
+ *
+ * (See http://www.flounder.com/handles.htm for information on various
+ * types of file handle in C/C++ on Windows.)
+ */
+ message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
+ if (message_read_fd == -1) {
+ *msg = ws_strdup_printf("Couldn't get C file handle for message read pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
+ CloseHandle(sync_pipe[PIPE_READ]);
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+
+ if (data_read_fd != NULL) {
+ /* Create a pipe for the child process to send us data */
+ /* (increase this value if you have trouble while fast capture file switches) */
+ if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, PIPE_BUF_SIZE)) {
+ /* Couldn't create the message pipe between parent and child. */
+ *msg = ws_strdup_printf("Couldn't create data pipe: %s",
+ win32strerror(GetLastError()));
+ g_strfreev(argv);
+ ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+
+ /*
+ * Associate a C run-time file handle with the Windows HANDLE for the
+ * read side of the data pipe.
+ *
+ * (See http://www.flounder.com/handles.htm for information on various
+ * types of file handle in C/C++ on Windows.)
+ */
+ *data_read_fd = _open_osfhandle( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
+ if (*data_read_fd == -1) {
+ *msg = ws_strdup_printf("Couldn't get C file handle for data read pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
+ CloseHandle(data_pipe[PIPE_READ]);
+ CloseHandle(data_pipe[PIPE_WRITE]);
+ ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+ }
+
+ if (signal_write_fd != NULL) {
+ /* Create the signal pipe */
+ snprintf(control_id, ARGV_NUMBER_LEN, "%ld", GetCurrentProcessId());
+ signal_pipe_name = ws_strdup_printf(SIGNAL_PIPE_FORMAT, control_id);
+ signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name),
+ PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL);
+ g_free(signal_pipe_name);
+
+ if (signal_pipe == INVALID_HANDLE_VALUE) {
+ /* Couldn't create the signal pipe between parent and child. */
+ *msg = ws_strdup_printf("Couldn't create signal pipe: %s",
+ win32strerror(GetLastError()));
+ g_strfreev(argv);
+ ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+
+ /*
+ * Associate a C run-time file handle with the Windows HANDLE for the
+ * read side of the message pipe.
+ *
+ * (See http://www.flounder.com/handles.htm for information on various
+ * types of file handle in C/C++ on Windows.)
+ */
+ signal_pipe_write_fd = _open_osfhandle( (intptr_t) signal_pipe, _O_BINARY);
+ if (signal_pipe_write_fd == -1) {
+ /* Couldn't create the pipe between parent and child. */
+ *msg = ws_strdup_printf("Couldn't get C file handle for sync pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
+ ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ CloseHandle(signal_pipe);
+ return -1;
+ }
+ }
+
+ /* init STARTUPINFO & PROCESS_INFORMATION */
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ memset(&pi, 0, sizeof(pi));
+#ifdef DEBUG_CHILD
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOW;
+#else
+ si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE; /* this hides the console window */
+
+ if (data_read_fd == NULL) {
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ } else {
+ si.hStdInput = NULL; /* handle for named pipe*/
+ si.hStdOutput = data_pipe[PIPE_WRITE];
+ }
+ si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+ /* On Windows, "[a]n inherited handle refers to the same object in the child
+ * process as it does in the parent process. It also has the same value."
+ * https://learn.microsoft.com/en-us/windows/win32/procthread/inheritance
+ * When converted to a file descriptor (via _open_osfhandle), the fd
+ * value is not necessarily the same in the two processes, but the handle
+ * value can be shared.
+ * A HANDLE is a void* though "64-bit versions of Windows use 32-bit handles
+ * for interoperability... only the lower 32 bits are significant, so it is
+ * safe to truncate the handle... or sign-extend the handle"
+ * https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
+ * So it should be fine to call PtrToLong instead of casting to intptr_t.
+ * https://learn.microsoft.com/en-us/windows/win32/WinProg64/rules-for-using-pointers
+ */
+ int argc = g_strv_length(argv);
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+ snprintf(sync_id, ARGV_NUMBER_LEN, "%ld", PtrToLong(sync_pipe[PIPE_WRITE]));
+ argv = sync_pipe_add_arg(argv, &argc, sync_id);
+#endif
+
+ if (ifaces) {
+ for (j = 0; j < ifaces->len; j++) {
+ interface_opts = &g_array_index(ifaces, interface_options, j);
+ if (interface_opts->extcap_fifo != NULL) {
+ i_handles++;
+ }
+ }
+ }
+ handles = g_new(HANDLE, 3 + i_handles);
+ i_handles = 0;
+ if (si.hStdInput) {
+ handles[i_handles++] = si.hStdInput;
+ }
+ if (si.hStdOutput && (si.hStdOutput != si.hStdInput)) {
+ handles[i_handles++] = si.hStdOutput;
+ }
+ handles[i_handles++] = sync_pipe[PIPE_WRITE];
+ if (ifaces) {
+ for (j = 0; j < ifaces->len; j++) {
+ interface_opts = &g_array_index(ifaces, interface_options, j);
+ if (interface_opts->extcap_fifo != NULL) {
+ handles[i_handles++] = interface_opts->extcap_pipe_h;
+ }
+ }
+ }
+
+ /* convert args array into a single string */
+ /* XXX - could change sync_pipe_add_arg() instead */
+ /* there is a drawback here: the length is internally limited to 1024 bytes */
+ for(i=0; argv[i] != 0; i++) {
+ if(i != 0) g_string_append_c(args, ' '); /* don't prepend a space before the path!!! */
+ quoted_arg = protect_arg(argv[i]);
+ g_string_append(args, quoted_arg);
+ g_free(quoted_arg);
+ }
+
+ /* call dumpcap */
+ if(!win32_create_process(argv[0], args->str, NULL, NULL, i_handles, handles,
+ CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
+ *msg = ws_strdup_printf("Couldn't run %s in child process: %s",
+ args->str, win32strerror(GetLastError()));
+ if (data_read_fd) {
+ ws_close(*data_read_fd); /* Should close data_pipe[PIPE_READ] */
+ CloseHandle(data_pipe[PIPE_WRITE]);
+ } else {
+ ws_close(signal_pipe_write_fd);
+ }
+ ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ g_strfreev(argv);
+ g_string_free(args, true);
+ g_free(handles);
+ return -1;
+ }
+ *fork_child = pi.hProcess;
+ /* We may need to store this and close it later */
+ CloseHandle(pi.hThread);
+ g_strfreev(argv);
+ g_string_free(args, true);
+ g_free(handles);
+
+ if (signal_write_fd != NULL) {
+ *signal_write_fd = signal_pipe_write_fd;
+ }
+#else /* _WIN32 */
+ /* Create a pipe for the child process to send us messages */
+ if (pipe(sync_pipe) < 0) {
+ /* Couldn't create the message pipe between parent and child. */
+ *msg = ws_strdup_printf("Couldn't create sync pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
+ return -1;
+ }
+
+ if (data_read_fd != NULL) {
+ /* Create a pipe for the child process to send us data */
+ if (pipe(data_pipe) < 0) {
+ /* Couldn't create the data pipe between parent and child. */
+ *msg = ws_strdup_printf("Couldn't create data pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
+ ws_close(sync_pipe[PIPE_READ]);
+ ws_close(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+ }
+
+ if ((*fork_child = fork()) == 0) {
+ /*
+ * Child process - run dumpcap with the right arguments to make
+ * it just capture with the specified capture parameters
+ */
+ if (data_read_fd != NULL) {
+ dup2(data_pipe[PIPE_WRITE], 1);
+ ws_close(data_pipe[PIPE_READ]);
+ ws_close(data_pipe[PIPE_WRITE]);
+ }
+ ws_close(sync_pipe[PIPE_READ]);
+ /* dumpcap should be running in capture child mode (hidden feature) */
+#ifndef DEBUG_CHILD
+ int argc = g_strv_length(argv);
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+ snprintf(sync_id, ARGV_NUMBER_LEN, "%d", sync_pipe[PIPE_WRITE]);
+ argv = sync_pipe_add_arg(argv, &argc, sync_id);
+#endif
+ execv(argv[0], argv);
+ sync_pipe_write_int_msg(sync_pipe[PIPE_WRITE], SP_EXEC_FAILED, errno);
+
+ /* 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). We've sent an error message to the parent, so
+ we exit with an exit status of 1 (any exit status other than
+ 0 or 1 will cause an additional message to report that exit
+ status, over and above the error message we sent to the parent). */
+ _exit(1);
+ }
+
+ g_strfreev(argv);
+
+ if (fetch_dumpcap_pid && *fork_child > 0)
+ fetch_dumpcap_pid(*fork_child);
+
+ if (data_read_fd != NULL) {
+ *data_read_fd = data_pipe[PIPE_READ];
+ }
+ message_read_fd = sync_pipe[PIPE_READ];
+
+#endif
+
+ /* Parent process - read messages from the child process over the
+ sync pipe. */
+
+ /* Close the write sides of the pipes, so that only the child has them
+ open, and thus they completely close, and thus return to us
+ an EOF indication, if the child closes them (either deliberately
+ or by exiting abnormally). */
+#ifdef _WIN32
+ if (data_read_fd != NULL) {
+ CloseHandle(data_pipe[PIPE_WRITE]);
+ }
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+#else
+ if (data_read_fd != NULL) {
+ ws_close(data_pipe[PIPE_WRITE]);
+ }
+ ws_close(sync_pipe[PIPE_WRITE]);
#endif
- int sync_pipe_read_fd;
+
+ if (*fork_child == WS_INVALID_PID) {
+ /* We couldn't even create the child process. */
+ *msg = ws_strdup_printf("Couldn't create child process: %s", g_strerror(errno));
+ if (data_read_fd != NULL) {
+ ws_close(*data_read_fd);
+ }
+#ifdef _WIN32
+ if (signal_write_fd != NULL) {
+ ws_close(signal_pipe_write_fd);
+ }
+#endif
+ ws_close(message_read_fd);
+ return -1;
+ }
+
+#ifdef _WIN32
+ *message_read_io = g_io_channel_win32_new_fd(message_read_fd);
+#else
+ *message_read_io = g_io_channel_unix_new(message_read_fd);
+#endif
+ g_io_channel_set_encoding(*message_read_io, NULL, NULL);
+ g_io_channel_set_buffered(*message_read_io, false);
+ g_io_channel_set_close_on_unref(*message_read_io, true);
+
+ /* we might wait for a moment till child is ready, so update screen now */
+ if (update_cb) update_cb();
+ return 0;
+}
+
+/* a new capture run: start a new dumpcap task and hand over parameters through command line */
+bool
+sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
+ capture_session *cap_session, info_data_t* cap_data,
+ void (*update_cb)(void))
+{
+#ifdef _WIN32
+ size_t i_handles = 0;
+ char control_id[ARGV_NUMBER_LEN];
+#endif
+ GIOChannel *sync_pipe_read_io;
int argc;
char **argv;
int i;
- guint j;
+ unsigned j;
interface_options *interface_opts;
if (capture_opts->ifaces->len > 1)
- capture_opts->use_pcapng = TRUE;
+ capture_opts->use_pcapng = true;
ws_debug("sync_pipe_start");
capture_opts_log(LOG_DOMAIN_CAPTURE, LOG_LEVEL_DEBUG, capture_opts);
cap_session->fork_child = WS_INVALID_PID;
+ cap_session->capture_opts = capture_opts;
- if (!extcap_init_interfaces(capture_opts)) {
+ if (!extcap_init_interfaces(cap_session)) {
report_failure("Unable to init extcaps. (tmp fifo already exists?)");
- return FALSE;
+ return false;
}
argv = init_pipe_args(&argc);
if (!argv) {
/* We don't know where to find dumpcap. */
report_failure("We don't know where to find dumpcap.");
- return FALSE;
+ return false;
}
if (capture_opts->ifaces->len > 1)
@@ -266,60 +721,72 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
}
}
+ if (capture_opts->temp_dir) {
+ argv = sync_pipe_add_arg(argv, &argc, "--temp-dir");
+ argv = sync_pipe_add_arg(argv, &argc, capture_opts->temp_dir);
+ }
+
if (capture_opts->multi_files_on) {
if (capture_opts->has_autostop_filesize) {
char sfilesize[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
- g_snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
+ snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
argv = sync_pipe_add_arg(argv, &argc, sfilesize);
}
if (capture_opts->has_file_duration) {
char sfile_duration[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
- g_snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->file_duration);
+ snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->file_duration);
argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
}
if (capture_opts->has_file_interval) {
char sfile_interval[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
- g_snprintf(sfile_interval, ARGV_NUMBER_LEN, "interval:%d",capture_opts->file_interval);
+ snprintf(sfile_interval, ARGV_NUMBER_LEN, "interval:%d",capture_opts->file_interval);
argv = sync_pipe_add_arg(argv, &argc, sfile_interval);
}
if (capture_opts->has_file_packets) {
char sfile_packets[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
- g_snprintf(sfile_packets, ARGV_NUMBER_LEN, "packets:%d",capture_opts->file_packets);
+ snprintf(sfile_packets, ARGV_NUMBER_LEN, "packets:%d",capture_opts->file_packets);
argv = sync_pipe_add_arg(argv, &argc, sfile_packets);
}
if (capture_opts->has_ring_num_files) {
char sring_num_files[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
- g_snprintf(sring_num_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->ring_num_files);
+ snprintf(sring_num_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->ring_num_files);
argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
}
+ if (capture_opts->print_file_names) {
+ char *print_name = g_strdup_printf("printname:%s", capture_opts->print_name_to);
+ argv = sync_pipe_add_arg(argv, &argc, "-b");
+ argv = sync_pipe_add_arg(argv, &argc, print_name);
+ g_free(print_name);
+ }
+
if (capture_opts->has_nametimenum) {
char nametimenum[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
- g_snprintf(nametimenum, ARGV_NUMBER_LEN, "nametimenum:2");
+ snprintf(nametimenum, ARGV_NUMBER_LEN, "nametimenum:2");
argv = sync_pipe_add_arg(argv, &argc, nametimenum);
}
if (capture_opts->has_autostop_files) {
char sautostop_files[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a");
- g_snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files);
+ snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files);
argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
}
} else {
if (capture_opts->has_autostop_filesize) {
char sautostop_filesize[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a");
- g_snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
+ snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
}
}
@@ -327,21 +794,35 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
if (capture_opts->has_autostop_packets) {
char scount[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-c");
- g_snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets);
+ snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets);
argv = sync_pipe_add_arg(argv, &argc, scount);
}
if (capture_opts->has_autostop_duration) {
char sautostop_duration[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a");
- g_snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->autostop_duration);
+ snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->autostop_duration);
argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
}
+ if (capture_opts->has_autostop_written_packets) {
+ char scount[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-a");
+ snprintf(scount, ARGV_NUMBER_LEN, "packets:%d",capture_opts->autostop_written_packets);
+ argv = sync_pipe_add_arg(argv, &argc, scount);
+ }
+
if (capture_opts->group_read_access) {
argv = sync_pipe_add_arg(argv, &argc, "-g");
}
+ if (capture_opts->update_interval != DEFAULT_UPDATE_INTERVAL) {
+ char scount[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "--update-interval");
+ snprintf(scount, ARGV_NUMBER_LEN, "%d", capture_opts->update_interval);
+ argv = sync_pipe_add_arg(argv, &argc, scount);
+ }
+
for (j = 0; j < capture_opts->ifaces->len; j++) {
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, j);
@@ -349,9 +830,10 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
if (interface_opts->extcap_fifo != NULL)
{
#ifdef _WIN32
- char *pipe = g_strdup_printf("%s%" G_GUINTPTR_FORMAT, EXTCAP_PIPE_PREFIX, interface_opts->extcap_pipe_h);
+ char *pipe = ws_strdup_printf("%s%" PRIuMAX, EXTCAP_PIPE_PREFIX, (uintmax_t)interface_opts->extcap_pipe_h);
argv = sync_pipe_add_arg(argv, &argc, pipe);
g_free(pipe);
+ i_handles++;
#else
argv = sync_pipe_add_arg(argv, &argc, interface_opts->extcap_fifo);
#endif
@@ -375,7 +857,7 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
if (interface_opts->has_snaplen) {
char ssnap[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-s");
- g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d", interface_opts->snaplen);
+ snprintf(ssnap, ARGV_NUMBER_LEN, "%d", interface_opts->snaplen);
argv = sync_pipe_add_arg(argv, &argc, ssnap);
}
@@ -398,7 +880,7 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
argv = sync_pipe_add_arg(argv, &argc, "-B");
if(interface_opts->buffer_size == 0x00)
interface_opts->buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE;
- g_snprintf(buffer_size, ARGV_NUMBER_LEN, "%d", interface_opts->buffer_size);
+ snprintf(buffer_size, ARGV_NUMBER_LEN, "%d", interface_opts->buffer_size);
argv = sync_pipe_add_arg(argv, &argc, buffer_size);
}
#endif
@@ -419,7 +901,7 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
char sauth[256];
argv = sync_pipe_add_arg(argv, &argc, "-A");
- g_snprintf(sauth, sizeof(sauth), "%s:%s",
+ snprintf(sauth, sizeof(sauth), "%s:%s",
interface_opts->auth_username,
interface_opts->auth_password);
argv = sync_pipe_add_arg(argv, &argc, sauth);
@@ -430,7 +912,7 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) {
char ssampling[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-m");
- g_snprintf(ssampling, ARGV_NUMBER_LEN, "%s:%d",
+ snprintf(ssampling, ARGV_NUMBER_LEN, "%s:%d",
interface_opts->sampling_method == CAPTURE_SAMP_BY_COUNT ? "count" :
interface_opts->sampling_method == CAPTURE_SAMP_BY_TIMER ? "timer" :
"undef",
@@ -444,14 +926,12 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
}
}
- /* dumpcap should be running in capture child mode (hidden feature) */
#ifndef DEBUG_CHILD
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
#ifdef _WIN32
- g_snprintf(control_id, ARGV_NUMBER_LEN, "%d", GetCurrentProcessId());
+ /* pass process id to dumpcap for named signal pipe */
+ argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
+ snprintf(control_id, ARGV_NUMBER_LEN, "%ld", GetCurrentProcessId());
argv = sync_pipe_add_arg(argv, &argc, control_id);
-#else
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
#endif
#endif
@@ -467,420 +947,43 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
argv = sync_pipe_add_arg(argv, &argc, capture_opts->compress_type);
}
+ int ret;
+ char* msg;
#ifdef _WIN32
- /* init SECURITY_ATTRIBUTES */
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- /* Create a pipe for the child process */
- /* (increase this value if you have trouble while fast capture file switches) */
- if (! CreatePipe(&sync_pipe_read, &sync_pipe_write, &sa, 5120)) {
- /* Couldn't create the pipe between parent and child. */
- report_failure("Couldn't create sync pipe: %s",
- win32strerror(GetLastError()));
- free_argv(argv, argc);
- return FALSE;
- }
-
- /*
- * Associate a C run-time file handle with the Windows HANDLE for the
- * read side of the message pipe.
- *
- * (See http://www.flounder.com/handles.htm for information on various
- * types of file handle in C/C++ on Windows.)
- */
- sync_pipe_read_fd = _open_osfhandle( (intptr_t) sync_pipe_read, _O_BINARY);
- if (sync_pipe_read_fd == -1) {
- /* Couldn't create the pipe between parent and child. */
- report_failure("Couldn't get C file handle for sync pipe: %s", g_strerror(errno));
- CloseHandle(sync_pipe_read);
- CloseHandle(sync_pipe_write);
- free_argv(argv, argc);
- return FALSE;
- }
-
- /* Create the signal pipe */
- signal_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT, control_id);
- signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name),
- PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL);
- g_free(signal_pipe_name);
-
- if (signal_pipe == INVALID_HANDLE_VALUE) {
- /* Couldn't create the signal pipe between parent and child. */
- report_failure("Couldn't create signal pipe: %s",
- win32strerror(GetLastError()));
- ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
- CloseHandle(sync_pipe_write);
- free_argv(argv, argc);
- return FALSE;
- }
-
- /*
- * Associate a C run-time file handle with the Windows HANDLE for the
- * read side of the message pipe.
- *
- * (See http://www.flounder.com/handles.htm for information on various
- * types of file handle in C/C++ on Windows.)
- */
- signal_pipe_write_fd = _open_osfhandle( (intptr_t) signal_pipe, _O_BINARY);
- if (sync_pipe_read_fd == -1) {
- /* Couldn't create the pipe between parent and child. */
- report_failure("Couldn't get C file handle for sync pipe: %s", g_strerror(errno));
- ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
- CloseHandle(sync_pipe_write);
- CloseHandle(signal_pipe);
- free_argv(argv, argc);
- return FALSE;
- }
-
- /* init STARTUPINFO & PROCESS_INFORMATION */
- memset(&si, 0, sizeof(si));
- si.cb = sizeof(si);
- memset(&pi, 0, sizeof(pi));
-#ifdef DEBUG_CHILD
- si.dwFlags = STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_SHOW;
+ ret = sync_pipe_open_command(argv, NULL, &sync_pipe_read_io, &cap_session->signal_pipe_write_fd,
+ &cap_session->fork_child, capture_opts->ifaces, &msg, update_cb);
#else
- si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_HIDE; /* this hides the console window */
- si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
- si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- si.hStdError = sync_pipe_write;
- /*si.hStdError = (HANDLE) _get_osfhandle(2);*/
+ ret = sync_pipe_open_command(argv, NULL, &sync_pipe_read_io, NULL,
+ &cap_session->fork_child, NULL, &msg, update_cb);
#endif
- /* convert args array into a single string */
- /* XXX - could change sync_pipe_add_arg() instead */
- /* there is a drawback here: the length is internally limited to 1024 bytes */
- for(i=0; argv[i] != 0; i++) {
- if(i != 0) g_string_append_c(args, ' '); /* don't prepend a space before the path!!! */
- quoted_arg = protect_arg(argv[i]);
- g_string_append(args, quoted_arg);
- g_free(quoted_arg);
- }
-
- /* call dumpcap */
- if(!win32_create_process(argv[0], args->str, NULL, NULL, TRUE,
- CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
- report_failure("Couldn't run %s in child process: %s",
- args->str, win32strerror(GetLastError()));
- ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
- CloseHandle(sync_pipe_write);
- CloseHandle(signal_pipe);
- free_argv(argv, argc);
- g_string_free(args, TRUE);
- return FALSE;
- }
- cap_session->fork_child = pi.hProcess;
- /* We may need to store this and close it later */
- CloseHandle(pi.hThread);
- g_string_free(args, TRUE);
-
- cap_session->signal_pipe_write_fd = signal_pipe_write_fd;
-
-#else /* _WIN32 */
- if (pipe(sync_pipe) < 0) {
- /* Couldn't create the pipe between parent and child. */
- report_failure("Couldn't create sync pipe: %s", g_strerror(errno));
- free_argv(argv, argc);
- return FALSE;
- }
-
- if ((cap_session->fork_child = fork()) == 0) {
- /*
- * Child process - run dumpcap with the right arguments to make
- * it just capture with the specified capture parameters
- */
- dup2(sync_pipe[PIPE_WRITE], 2);
- ws_close(sync_pipe[PIPE_READ]);
- execv(argv[0], argv);
- g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
- argv[0], g_strerror(errno));
- sync_pipe_errmsg_to_parent(2, 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). We've sent an error message to the parent, so
- we exit with an exit status of 1 (any exit status other than
- 0 or 1 will cause an additional message to report that exit
- status, over and above the error message we sent to the parent). */
- _exit(1);
+ if (ret == -1) {
+ report_failure("%s", msg);
+ g_free(msg);
+ return false;
}
- if (fetch_dumpcap_pid && cap_session->fork_child > 0)
- fetch_dumpcap_pid(cap_session->fork_child);
-
- sync_pipe_read_fd = sync_pipe[PIPE_READ];
-#endif
-
/* Parent process - read messages from the child process over the
sync pipe. */
- free_argv(argv, argc);
-
- /* 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). */
-#ifdef _WIN32
- CloseHandle(sync_pipe_write);
-#else
- ws_close(sync_pipe[PIPE_WRITE]);
-#endif
-
- if (cap_session->fork_child == WS_INVALID_PID) {
- /* We couldn't even create the child process. */
- report_failure("Couldn't create child process: %s", g_strerror(errno));
- ws_close(sync_pipe_read_fd);
-#ifdef _WIN32
- ws_close(cap_session->signal_pipe_write_fd);
-#endif
- return FALSE;
- }
cap_session->fork_child_status = 0;
- cap_session->capture_opts = capture_opts;
cap_session->cap_data_info = cap_data;
- /* we might wait for a moment till child is ready, so update screen now */
- if (update_cb) update_cb();
-
/* We were able to 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. */
/* we have a running capture, now wait for the real capture filename */
- pipe_input_set_handler(sync_pipe_read_fd, (gpointer) cap_session,
- &cap_session->fork_child, sync_pipe_input_cb);
-
- return TRUE;
-}
-
-/*
- * Open two pipes to dumpcap with the supplied arguments, one for its
- * standard output and one for its standard error.
- *
- * On success, *msg is unchanged and 0 is returned; data_read_fd,
- * message_read_fd, and fork_child point to the standard output pipe's
- * file descriptor, the standard error pipe's file descriptor, and
- * the child's PID/handle, respectively.
- *
- * On failure, *msg points to an error message for the failure, and -1 is
- * returned, in which case *msg must be freed with g_free().
- */
-/* XXX - This duplicates a lot of code in sync_pipe_start() */
-/* XXX - assumes PIPE_BUF_SIZE > SP_MAX_MSG_LEN */
-#define PIPE_BUF_SIZE 5120
-static int
-sync_pipe_open_command(char* const argv[], int *data_read_fd,
- int *message_read_fd, ws_process_id *fork_child, gchar **msg, void(*update_cb)(void))
-{
- enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
-#ifdef _WIN32
- HANDLE sync_pipe[2]; /* pipe used to send messages from child to parent */
- HANDLE data_pipe[2]; /* pipe used to send data from child to parent */
- GString *args = g_string_sized_new(200);
- gchar *quoted_arg;
- SECURITY_ATTRIBUTES sa;
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- int i;
-#else
- char errmsg[1024+1];
- int sync_pipe[2]; /* pipe used to send messages from child to parent */
- int data_pipe[2]; /* pipe used to send data from child to parent */
-#endif
- *fork_child = WS_INVALID_PID;
- *data_read_fd = -1;
- *message_read_fd = -1;
- ws_debug("sync_pipe_open_command");
-
- if (!msg) {
- /* We can't return anything */
-#ifdef _WIN32
- g_string_free(args, TRUE);
-#endif
- return -1;
- }
-
-#ifdef _WIN32
- /* init SECURITY_ATTRIBUTES */
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- /* Create a pipe for the child process to send us messages */
- /* (increase this value if you have trouble while fast capture file switches) */
- if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, 5120)) {
- /* Couldn't create the message pipe between parent and child. */
- *msg = g_strdup_printf("Couldn't create sync pipe: %s",
- win32strerror(GetLastError()));
- return -1;
- }
-
- /*
- * Associate a C run-time file handle with the Windows HANDLE for the
- * read side of the message pipe.
- *
- * (See http://www.flounder.com/handles.htm for information on various
- * types of file handle in C/C++ on Windows.)
- */
- *message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
- if (*message_read_fd == -1) {
- *msg = g_strdup_printf("Couldn't get C file handle for message read pipe: %s", g_strerror(errno));
- CloseHandle(sync_pipe[PIPE_READ]);
- CloseHandle(sync_pipe[PIPE_WRITE]);
- return -1;
- }
-
- /* Create a pipe for the child process to send us data */
- /* (increase this value if you have trouble while fast capture file switches) */
- if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, 5120)) {
- /* Couldn't create the message pipe between parent and child. */
- *msg = g_strdup_printf("Couldn't create data pipe: %s",
- win32strerror(GetLastError()));
- ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
- CloseHandle(sync_pipe[PIPE_WRITE]);
- return -1;
- }
-
- /*
- * Associate a C run-time file handle with the Windows HANDLE for the
- * read side of the data pipe.
- *
- * (See http://www.flounder.com/handles.htm for information on various
- * types of file handle in C/C++ on Windows.)
- */
- *data_read_fd = _open_osfhandle( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
- if (*data_read_fd == -1) {
- *msg = g_strdup_printf("Couldn't get C file handle for data read pipe: %s", g_strerror(errno));
- CloseHandle(data_pipe[PIPE_READ]);
- CloseHandle(data_pipe[PIPE_WRITE]);
- ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
- CloseHandle(sync_pipe[PIPE_WRITE]);
- return -1;
- }
-
- /* init STARTUPINFO & PROCESS_INFORMATION */
- memset(&si, 0, sizeof(si));
- si.cb = sizeof(si);
- memset(&pi, 0, sizeof(pi));
-#ifdef DEBUG_CHILD
- si.dwFlags = STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_SHOW;
-#else
- si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_HIDE; /* this hides the console window */
- si.hStdInput = NULL; /* handle for named pipe*/
-
- si.hStdOutput = data_pipe[PIPE_WRITE];
- si.hStdError = sync_pipe[PIPE_WRITE];
-#endif
-
- /* convert args array into a single string */
- /* XXX - could change sync_pipe_add_arg() instead */
- /* there is a drawback here: the length is internally limited to 1024 bytes */
- for(i=0; argv[i] != 0; i++) {
- if(i != 0) g_string_append_c(args, ' '); /* don't prepend a space before the path!!! */
- quoted_arg = protect_arg(argv[i]);
- g_string_append(args, quoted_arg);
- g_free(quoted_arg);
- }
-
- /* call dumpcap */
- if(!win32_create_process(argv[0], args->str, NULL, NULL, TRUE,
- CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
- *msg = g_strdup_printf("Couldn't run %s in child process: %s",
- args->str, win32strerror(GetLastError()));
- ws_close(*data_read_fd); /* Should close data_pipe[PIPE_READ] */
- CloseHandle(data_pipe[PIPE_WRITE]);
- ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
- CloseHandle(sync_pipe[PIPE_WRITE]);
- g_string_free(args, TRUE);
- return -1;
- }
- *fork_child = pi.hProcess;
- /* We may need to store this and close it later */
- CloseHandle(pi.hThread);
- g_string_free(args, TRUE);
-#else /* _WIN32 */
- /* Create a pipe for the child process to send us messages */
- if (pipe(sync_pipe) < 0) {
- /* Couldn't create the message pipe between parent and child. */
- *msg = g_strdup_printf("Couldn't create sync pipe: %s", g_strerror(errno));
- return -1;
- }
-
- /* Create a pipe for the child process to send us data */
- if (pipe(data_pipe) < 0) {
- /* Couldn't create the data pipe between parent and child. */
- *msg = g_strdup_printf("Couldn't create data pipe: %s", g_strerror(errno));
- ws_close(sync_pipe[PIPE_READ]);
- ws_close(sync_pipe[PIPE_WRITE]);
- return -1;
- }
-
- if ((*fork_child = fork()) == 0) {
- /*
- * Child process - run dumpcap with the right arguments to make
- * it just capture with the specified capture parameters
- */
- dup2(data_pipe[PIPE_WRITE], 1);
- ws_close(data_pipe[PIPE_READ]);
- ws_close(data_pipe[PIPE_WRITE]);
- dup2(sync_pipe[PIPE_WRITE], 2);
- ws_close(sync_pipe[PIPE_READ]);
- ws_close(sync_pipe[PIPE_WRITE]);
- execv(argv[0], argv);
- g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
- argv[0], g_strerror(errno));
- sync_pipe_errmsg_to_parent(2, 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). We've sent an error message to the parent, so
- we exit with an exit status of 1 (any exit status other than
- 0 or 1 will cause an additional message to report that exit
- status, over and above the error message we sent to the parent). */
- _exit(1);
+ if (cap_session->pipe_input_id) {
+ g_source_remove(cap_session->pipe_input_id);
+ cap_session->pipe_input_id = 0;
}
+ cap_session->pipe_input_id = g_io_add_watch(sync_pipe_read_io, G_IO_IN | G_IO_HUP, pipe_io_cb, cap_session);
+ /* Pipe will be closed when watch is removed */
+ g_io_channel_unref(sync_pipe_read_io);
- if (fetch_dumpcap_pid && *fork_child > 0)
- fetch_dumpcap_pid(*fork_child);
-
- *data_read_fd = data_pipe[PIPE_READ];
- *message_read_fd = sync_pipe[PIPE_READ];
-#endif
-
- /* Parent process - read messages from the child process over the
- sync pipe. */
-
- /* Close the write sides of the pipes, so that only the child has them
- open, and thus they completely close, and thus return to us
- an EOF indication, if the child closes them (either deliberately
- or by exiting abnormally). */
-#ifdef _WIN32
- CloseHandle(data_pipe[PIPE_WRITE]);
- CloseHandle(sync_pipe[PIPE_WRITE]);
-#else
- ws_close(data_pipe[PIPE_WRITE]);
- ws_close(sync_pipe[PIPE_WRITE]);
-#endif
-
- if (*fork_child == WS_INVALID_PID) {
- /* We couldn't even create the child process. */
- *msg = g_strdup_printf("Couldn't create child process: %s", g_strerror(errno));
- ws_close(*data_read_fd);
- ws_close(*message_read_fd);
- return -1;
- }
-
- /* we might wait for a moment till child is ready, so update screen now */
- if (update_cb) update_cb();
- return 0;
+ return true;
}
/*
@@ -892,12 +995,12 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
* latter case, *msgp must be freed with g_free().
*/
static int
-sync_pipe_close_command(int *data_read_fd, int *message_read_fd,
- ws_process_id *fork_child, gchar **msgp)
+sync_pipe_close_command(int *data_read_fd, GIOChannel *message_read_io,
+ ws_process_id *fork_child, char **msgp)
{
ws_close(*data_read_fd);
- if (message_read_fd != NULL)
- ws_close(*message_read_fd);
+ if (message_read_io != NULL)
+ g_io_channel_unref(message_read_io);
#ifdef _WIN32
/* XXX - Should we signal the child somehow? */
@@ -919,20 +1022,19 @@ sync_pipe_close_command(int *data_read_fd, int *message_read_fd,
* NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
* must be freed with g_free().
*/
-/* XXX - This duplicates a lot of code in sync_pipe_start() */
-/* XXX - assumes PIPE_BUF_SIZE > SP_MAX_MSG_LEN */
-#define PIPE_BUF_SIZE 5120
static int
-sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_msg,
- gchar **secondary_msg, void(*update_cb)(void))
+sync_pipe_run_command_actual(char **argv, char **data, char **primary_msg,
+ char **secondary_msg, void(*update_cb)(void))
{
- gchar *msg;
- int data_pipe_read_fd, sync_pipe_read_fd, ret;
+ char *msg;
+ int data_pipe_read_fd, ret;
+ GIOChannel *sync_pipe_read_io;
ws_process_id fork_child;
char *wait_msg;
- gchar buffer[PIPE_BUF_SIZE+1] = {0};
+ char buffer[PIPE_BUF_SIZE+1] = {0};
ssize_t nread;
char indicator;
+ int32_t exec_errno = 0;
int primary_msg_len;
char *primary_msg_text;
int secondary_msg_len;
@@ -941,8 +1043,8 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
GString *data_buf = NULL;
ssize_t count;
- ret = sync_pipe_open_command(argv, &data_pipe_read_fd, &sync_pipe_read_fd,
- &fork_child, &msg, update_cb);
+ ret = sync_pipe_open_command(argv, &data_pipe_read_fd, &sync_pipe_read_io, NULL,
+ &fork_child, NULL, &msg, update_cb);
if (ret == -1) {
*primary_msg = msg;
*secondary_msg = NULL;
@@ -955,7 +1057,7 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
*
* First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
*/
- nread = pipe_read_block(sync_pipe_read_fd, &indicator, SP_MAX_MSG_LEN,
+ nread = pipe_read_block(sync_pipe_read_io, &indicator, SP_MAX_MSG_LEN,
buffer, primary_msg);
if(nread <= 0) {
/* We got a read error from the sync pipe, or we got no data at
@@ -982,7 +1084,7 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
/* We got an error from the sync pipe. If ret is -1, report
both the sync pipe I/O error and the wait error. */
if (ret == -1) {
- combined_msg = g_strdup_printf("%s\n\n%s", *primary_msg, wait_msg);
+ combined_msg = ws_strdup_printf("%s\n\n%s", *primary_msg, wait_msg);
g_free(*primary_msg);
g_free(wait_msg);
*primary_msg = combined_msg;
@@ -997,6 +1099,39 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
/* we got a valid message block from the child, process it */
switch(indicator) {
+ case SP_EXEC_FAILED:
+ /*
+ * Exec of dumpcap failed. Get the errno for the failure.
+ */
+ if (!ws_strtoi32(buffer, NULL, &exec_errno)) {
+ ws_warning("Invalid errno: %s", buffer);
+ }
+
+ /*
+ * Pick up the child status.
+ */
+ ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
+ &fork_child, &msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ } else {
+ /*
+ * Child process failed, but returned the expected exit status.
+ * Return the messages it gave us, and indicate failure.
+ */
+ *primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",
+ g_strerror(exec_errno));
+ *secondary_msg = NULL;
+ ret = -1;
+ }
+ *data = NULL;
+ break;
+
case SP_ERROR_MSG:
/*
* Error from dumpcap; there will be a primary message and a
@@ -1004,10 +1139,10 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
*/
/* convert primary message */
- pipe_convert_header((guchar*)buffer, 4, &indicator, &primary_msg_len);
+ pipe_convert_header((unsigned char*)buffer, 4, &indicator, &primary_msg_len);
primary_msg_text = buffer+4;
/* convert secondary message */
- pipe_convert_header((guchar*)primary_msg_text + primary_msg_len, 4, &indicator,
+ pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, 4, &indicator,
&secondary_msg_len);
secondary_msg_text = primary_msg_text + primary_msg_len + 4;
/* the capture child will close the sync_pipe, nothing to do */
@@ -1015,7 +1150,7 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
/*
* Pick up the child status.
*/
- ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+ ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
&fork_child, &msg);
if (ret == -1) {
/*
@@ -1036,6 +1171,13 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
*data = NULL;
break;
+ case SP_LOG_MSG:
+ /*
+ * Log from dumpcap; pass to our log
+ */
+ sync_pipe_handle_log_msg(buffer);
+ break;
+
case SP_SUCCESS:
/* read the output from the command */
data_buf = g_string_new("");
@@ -1047,7 +1189,7 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
/*
* Pick up the child status.
*/
- ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+ ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
&fork_child, &msg);
if (ret == -1) {
/*
@@ -1056,7 +1198,7 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
*/
*primary_msg = msg;
*secondary_msg = NULL;
- g_string_free(data_buf, TRUE);
+ g_string_free(data_buf, true);
*data = NULL;
} else {
/*
@@ -1064,7 +1206,7 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
*/
*primary_msg = NULL;
*secondary_msg = NULL;
- *data = g_string_free(data_buf, FALSE);
+ *data = g_string_free(data_buf, false);
}
break;
@@ -1072,7 +1214,7 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
/*
* Pick up the child status.
*/
- ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+ ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
&fork_child, &msg);
if (ret == -1) {
/*
@@ -1085,7 +1227,7 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
/*
* Child process returned an unknown status.
*/
- *primary_msg = g_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
+ *primary_msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
indicator);
*secondary_msg = NULL;
ret = -1;
@@ -1100,11 +1242,11 @@ sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_m
* redirects to sync_pipe_run_command_actual()
*/
static int
-sync_pipe_run_command(char* const argv[], gchar **data, gchar **primary_msg,
- gchar **secondary_msg, void (*update_cb)(void))
+sync_pipe_run_command(char **argv, char **data, char **primary_msg,
+ char **secondary_msg, void (*update_cb)(void))
{
int ret, i;
- gint64 start_time;
+ int64_t start_time;
double elapsed;
int logging_enabled;
@@ -1112,9 +1254,9 @@ sync_pipe_run_command(char* const argv[], gchar **data, gchar **primary_msg,
logging_enabled = ws_log_msg_is_active(WS_LOG_DOMAIN, LOG_LEVEL_INFO);
if (logging_enabled) {
start_time = g_get_monotonic_time();
- ws_info("sync_pipe_run_command() starts");
+ ws_debug("sync_pipe_run_command() starts");
for (i=0; argv[i] != 0; i++) {
- ws_debug(" argv[%d]: %s", i, argv[i]);
+ ws_noisy(" argv[%d]: %s", i, argv[i]);
}
}
/* do the actual sync pipe run command */
@@ -1123,7 +1265,7 @@ sync_pipe_run_command(char* const argv[], gchar **data, gchar **primary_msg,
if (logging_enabled) {
elapsed = (g_get_monotonic_time() - start_time) / 1e6;
- ws_info("sync_pipe_run_command() ends, taking %.3fs, result=%d", elapsed, ret);
+ ws_debug("sync_pipe_run_command() ends, taking %.3fs, result=%d", elapsed, ret);
}
return ret;
@@ -1131,14 +1273,14 @@ sync_pipe_run_command(char* const argv[], gchar **data, gchar **primary_msg,
int
-sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar *type,
- const gchar *center_freq1, const gchar *center_freq2,
- gchar **data, gchar **primary_msg,
- gchar **secondary_msg, void (*update_cb)(void))
+sync_interface_set_80211_chan(const char *iface, const char *freq, const char *type,
+ const char *center_freq1, const char *center_freq2,
+ char **data, char **primary_msg,
+ char **secondary_msg, void (*update_cb)(void))
{
int argc, ret;
char **argv;
- gchar *opt;
+ char *opt;
argv = init_pipe_args(&argc);
@@ -1153,11 +1295,11 @@ sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar
argv = sync_pipe_add_arg(argv, &argc, iface);
if (center_freq2)
- opt = g_strdup_printf("%s,%s,%s,%s", freq, type, center_freq1, center_freq2);
+ opt = ws_strdup_printf("%s,%s,%s,%s", freq, type, center_freq1, center_freq2);
else if (center_freq1)
- opt = g_strdup_printf("%s,%s,%s", freq, type, center_freq1);
+ opt = ws_strdup_printf("%s,%s,%s", freq, type, center_freq1);
else if (type)
- opt = g_strdup_printf("%s,%s", freq, type);
+ opt = ws_strdup_printf("%s,%s", freq, type);
else
opt = g_strdup(freq);
@@ -1165,22 +1307,14 @@ sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar
*primary_msg = g_strdup("Out of mem.");
*secondary_msg = NULL;
*data = NULL;
- free_argv(argv, argc);
return -1;
}
argv = sync_pipe_add_arg(argv, &argc, "-k");
argv = sync_pipe_add_arg(argv, &argc, opt);
-#ifndef DEBUG_CHILD
- /* Run dumpcap in capture child mode */
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
-#endif
-
ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
g_free(opt);
- free_argv(argv, argc);
return ret;
}
@@ -1197,8 +1331,8 @@ sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar
* must be freed with g_free().
*/
int
-sync_interface_list_open(gchar **data, gchar **primary_msg,
- gchar **secondary_msg, void (*update_cb)(void))
+sync_interface_list_open(char **data, char **primary_msg,
+ char **secondary_msg, void (*update_cb)(void))
{
int argc;
char **argv;
@@ -1218,13 +1352,7 @@ sync_interface_list_open(gchar **data, gchar **primary_msg,
/* Ask for the interface list */
argv = sync_pipe_add_arg(argv, &argc, "-D");
-#ifndef DEBUG_CHILD
- /* Run dumpcap in capture child mode */
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
-#endif
ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
- free_argv(argv, argc);
return ret;
}
@@ -1241,9 +1369,9 @@ sync_interface_list_open(gchar **data, gchar **primary_msg,
* must be freed with g_free().
*/
int
-sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode, const gchar* auth,
- gchar **data, gchar **primary_msg,
- gchar **secondary_msg, void (*update_cb)(void))
+sync_if_capabilities_open(const char *ifname, bool monitor_mode, const char* auth,
+ char **data, char **primary_msg,
+ char **secondary_msg, void (*update_cb)(void))
{
int argc;
char **argv;
@@ -1272,13 +1400,51 @@ sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode, const gcha
argv = sync_pipe_add_arg(argv, &argc, auth);
}
-#ifndef DEBUG_CHILD
- /* Run dumpcap in capture child mode */
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
-#endif
ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
- free_argv(argv, argc);
+ return ret;
+}
+
+int
+sync_if_list_capabilities_open(GList *if_queries,
+ char **data, char **primary_msg,
+ char **secondary_msg, void (*update_cb)(void))
+{
+ int argc;
+ char **argv;
+ int ret;
+ if_cap_query_t *if_cap_query;
+
+ ws_debug("sync_if_list_capabilities_open");
+
+ argv = init_pipe_args(&argc);
+
+ if (!argv) {
+ *primary_msg = g_strdup("We don't know where to find dumpcap.");
+ *secondary_msg = NULL;
+ *data = NULL;
+ return -1;
+ }
+
+ for (GList *li = if_queries; li != NULL; li = g_list_next(li)) {
+ if_cap_query = (if_cap_query_t*)li->data;
+ /* Ask for the interface capabilities */
+ argv = sync_pipe_add_arg(argv, &argc, "-i");
+ argv = sync_pipe_add_arg(argv, &argc, if_cap_query->name);
+ if (if_cap_query->monitor_mode)
+ argv = sync_pipe_add_arg(argv, &argc, "-I");
+ if (if_cap_query->auth_username && if_cap_query->auth_password) {
+ char sauth[256];
+ argv = sync_pipe_add_arg(argv, &argc, "-A");
+ snprintf(sauth, sizeof(sauth), "%s:%s",
+ if_cap_query->auth_username,
+ if_cap_query->auth_password);
+ argv = sync_pipe_add_arg(argv, &argc, sauth);
+ }
+ }
+ argv = sync_pipe_add_arg(argv, &argc, "-L");
+ argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
+
+ ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
return ret;
}
@@ -1287,17 +1453,21 @@ sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode, const gcha
* contains the file descriptor for the pipe's stdout, *msg is unchanged,
* and zero is returned. On failure, *msg will point to an error message
* that must be g_free()d, and -1 will be returned.
+ * If data is not NULL, then it will also be set to point to a JSON
+ * serialization of the list of local interfaces and their capabilities.
*/
int
-sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, gchar **msg, void (*update_cb)(void))
+sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, char **data, char **msg, void (*update_cb)(void))
{
int argc;
char **argv;
- int message_read_fd, ret;
+ int ret;
+ GIOChannel *message_read_io;
char *wait_msg;
- gchar buffer[PIPE_BUF_SIZE+1] = {0};
+ char buffer[PIPE_BUF_SIZE+1] = {0};
ssize_t nread;
char indicator;
+ int32_t exec_errno = 0;
int primary_msg_len;
char *primary_msg_text;
int secondary_msg_len;
@@ -1316,18 +1486,24 @@ sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, gchar **
/* Ask for the interface statistics */
argv = sync_pipe_add_arg(argv, &argc, "-S");
+ /* If requested, ask for the interface list and capabilities. */
+ if (data) {
+ argv = sync_pipe_add_arg(argv, &argc, "-D");
+ argv = sync_pipe_add_arg(argv, &argc, "-L");
+ }
+
#ifndef DEBUG_CHILD
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
#ifdef _WIN32
- create_dummy_signal_pipe();
+ argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
+ ret = create_dummy_signal_pipe(msg);
+ if (ret == -1) {
+ return -1;
+ }
argv = sync_pipe_add_arg(argv, &argc, dummy_control_id);
-#else
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
#endif
#endif
- ret = sync_pipe_open_command(argv, data_read_fd, &message_read_fd,
- fork_child, msg, update_cb);
- free_argv(argv, argc);
+ ret = sync_pipe_open_command(argv, data_read_fd, &message_read_io, NULL,
+ fork_child, NULL, msg, update_cb);
if (ret == -1) {
return -1;
}
@@ -1337,116 +1513,169 @@ sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, gchar **
*
* First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
*/
- nread = pipe_read_block(message_read_fd, &indicator, SP_MAX_MSG_LEN,
- buffer, msg);
- if(nread <= 0) {
- /* We got a read error from the sync pipe, or we got no data at
- all from the sync pipe, so we're not going to be getting any
- data or error message from the child process. Pick up its
- exit status, and complain.
-
- We don't have to worry about killing the child, if the sync pipe
- returned an error. Usually this error is caused as the child killed
- itself while going down. Even in the rare cases that this isn't the
- case, the child will get an error when writing to the broken pipe
- the next time, cleaning itself up then. */
- ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
- ws_close(message_read_fd);
- ws_close(*data_read_fd);
- if(nread == 0) {
- /* We got an EOF from the sync pipe. That means that it exited
- before giving us any data to read. If ret is -1, we report
- that as a bad exit (e.g., exiting due to a signal); otherwise,
- we report it as a premature exit. */
- if (ret == -1)
- *msg = wait_msg;
- else
- *msg = g_strdup("Child dumpcap closed sync pipe prematurely");
- } else {
- /* We got an error from the sync pipe. If ret is -1, report
- both the sync pipe I/O error and the wait error. */
- if (ret == -1) {
- combined_msg = g_strdup_printf("%s\n\n%s", *msg, wait_msg);
- g_free(*msg);
- g_free(wait_msg);
- *msg = combined_msg;
+ do {
+ nread = pipe_read_block(message_read_io, &indicator, SP_MAX_MSG_LEN,
+ buffer, msg);
+ if(nread <= 0) {
+ /* We got a read error from the sync pipe, or we got no data at
+ all from the sync pipe, so we're not going to be getting any
+ data or error message from the child process. Pick up its
+ exit status, and complain.
+
+ We don't have to worry about killing the child, if the sync pipe
+ returned an error. Usually this error is caused as the child killed
+ itself while going down. Even in the rare cases that this isn't the
+ case, the child will get an error when writing to the broken pipe
+ the next time, cleaning itself up then. */
+ ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
+ g_io_channel_unref(message_read_io);
+ ws_close(*data_read_fd);
+ if(nread == 0) {
+ /* We got an EOF from the sync pipe. That means that it exited
+ before giving us any data to read. If ret is -1, we report
+ that as a bad exit (e.g., exiting due to a signal); otherwise,
+ we report it as a premature exit. */
+ if (ret == -1)
+ *msg = wait_msg;
+ else
+ *msg = g_strdup("Child dumpcap closed sync pipe prematurely");
+ } else {
+ /* We got an error from the sync pipe. If ret is -1, report
+ both the sync pipe I/O error and the wait error. */
+ if (ret == -1) {
+ combined_msg = ws_strdup_printf("%s\n\n%s", *msg, wait_msg);
+ g_free(*msg);
+ g_free(wait_msg);
+ *msg = combined_msg;
+ }
}
+ return -1;
}
- return -1;
- }
- /* we got a valid message block from the child, process it */
- switch(indicator) {
+ /* we got a valid message block from the child, process it */
+ switch(indicator) {
- case SP_ERROR_MSG:
- /*
- * Error from dumpcap; there will be a primary message and a
- * secondary message.
- */
-
- /* convert primary message */
- pipe_convert_header((guchar*)buffer, 4, &indicator, &primary_msg_len);
- primary_msg_text = buffer+4;
- /* convert secondary message */
- pipe_convert_header((guchar*)primary_msg_text + primary_msg_len, 4, &indicator,
- &secondary_msg_len);
- /*secondary_msg_text = primary_msg_text + primary_msg_len + 4;*/
- /* the capture child will close the sync_pipe, nothing to do */
+ case SP_EXEC_FAILED:
+ /*
+ * Exec of dumpcap failed. Get the errno for the failure.
+ */
+ if (!ws_strtoi32(buffer, NULL, &exec_errno)) {
+ ws_warning("Invalid errno: %s", buffer);
+ }
+ *msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",
+ g_strerror(exec_errno));
- /*
- * Pick up the child status.
- */
- ret = sync_pipe_close_command(data_read_fd, &message_read_fd,
- fork_child, msg);
- if (ret == -1) {
/*
- * Child process failed unexpectedly, or wait failed; msg is the
- * error message.
+ * Pick up the child status.
*/
- } else {
+ char *close_msg = NULL;
+ sync_pipe_close_command(data_read_fd, message_read_io,
+ fork_child, &close_msg);
/*
- * Child process failed, but returned the expected exit status.
- * Return the messages it gave us, and indicate failure.
+ * Ignore the error from sync_pipe_close_command, presumably the one
+ * returned by the child is more pertinent to what went wrong.
*/
- *msg = g_strdup(primary_msg_text);
+ g_free(close_msg);
ret = -1;
- }
- break;
+ break;
- case SP_SUCCESS:
- /* Close the message pipe. */
- ws_close(message_read_fd);
- break;
+ case SP_ERROR_MSG:
+ /*
+ * Error from dumpcap; there will be a primary message and a
+ * secondary message.
+ */
+
+ /* convert primary message */
+ pipe_convert_header((unsigned char*)buffer, 4, &indicator, &primary_msg_len);
+ primary_msg_text = buffer+4;
+ /* convert secondary message */
+ pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, 4, &indicator,
+ &secondary_msg_len);
+ /*secondary_msg_text = primary_msg_text + primary_msg_len + 4;*/
+ /* the capture child will close the sync_pipe, nothing to do */
- default:
- /*
- * Pick up the child status.
- */
- ret = sync_pipe_close_command(data_read_fd, &message_read_fd,
- fork_child, msg);
- if (ret == -1) {
/*
- * Child process failed unexpectedly, or wait failed; msg is the
- * error message.
+ * Pick up the child status.
*/
- } else {
+ ret = sync_pipe_close_command(data_read_fd, message_read_io,
+ fork_child, msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ } else if (ret == WS_EXIT_NO_INTERFACES) {
+ /*
+ * No interfaces were found. If that's not the
+ * result of an error when fetching the local
+ * interfaces, let the user know.
+ */
+ *msg = g_strdup(primary_msg_text);
+ } else {
+ /*
+ * Child process failed, but returned the expected exit status.
+ * Return the messages it gave us, and indicate failure.
+ */
+ *msg = g_strdup(primary_msg_text);
+ ret = -1;
+ }
+ return ret;
+
+ case SP_LOG_MSG:
/*
- * Child process returned an unknown status.
+ * Log from dumpcap; pass to our log
*/
- *msg = g_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
- indicator);
- ret = -1;
+ sync_pipe_handle_log_msg(buffer);
+ break;
+
+ case SP_IFACE_LIST:
+ /*
+ * Dumpcap giving us the interface list
+ */
+
+ /* convert primary message */
+ *data = g_strdup(buffer);
+ break;
+
+ case SP_SUCCESS:
+ /* Close the message pipe. */
+ g_io_channel_unref(message_read_io);
+ break;
+
+ default:
+ /*
+ * Pick up the child status.
+ */
+ ret = sync_pipe_close_command(data_read_fd, message_read_io,
+ fork_child, msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ } else {
+ /*
+ * Child process returned an unknown status.
+ */
+ *msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
+ indicator);
+ ret = -1;
+ }
+ break;
}
- break;
- }
+ } while (indicator != SP_SUCCESS && ret != -1);
+
return ret;
}
/* Close down the stats process */
int
-sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, gchar **msg)
+sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, char **msg)
{
-#ifndef _WIN32
+#ifdef _WIN32
+ CloseHandle(dummy_signal_pipe);
+ dummy_signal_pipe = NULL;
+#else
/*
* Don't bother waiting for the child. sync_pipe_close_command
* does this for us on Windows.
@@ -1459,30 +1688,28 @@ sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, gchar **msg)
/* read a number of bytes from a pipe */
/* (blocks until enough bytes read or an error occurs) */
static ssize_t
-pipe_read_bytes(int pipe_fd, char *bytes, int required, char **msg)
+pipe_read_bytes(GIOChannel *pipe_io, char *bytes, size_t required, char **msg)
{
- ssize_t newly;
- ssize_t offset = 0;
- int error;
+ GError *err = NULL;
+ size_t newly;
+ size_t offset = 0;
while(required) {
- newly = ws_read(pipe_fd, &bytes[offset], required);
+ g_io_channel_read_chars(pipe_io, &bytes[offset], required, &newly, &err);
+ if (err != NULL) {
+ ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message);
+ *msg = ws_strdup_printf("Error reading from sync pipe: %s", err->message);
+ g_clear_error(&err);
+ return -1;
+ }
if (newly == 0) {
/* EOF */
- ws_debug("read from pipe %d: EOF (capture closed?)", pipe_fd);
+ ws_debug("read from pipe %p: EOF (capture closed?)", pipe_io);
*msg = 0;
return offset;
}
- if (newly < 0) {
- /* error */
- error = errno;
- ws_debug("read from pipe %d: error(%u): %s", pipe_fd, error, g_strerror(error));
- *msg = g_strdup_printf("Error reading from sync pipe: %s",
- g_strerror(error));
- return newly;
- }
- required -= (int)newly;
+ required -= newly;
offset += newly;
}
@@ -1527,7 +1754,7 @@ sync_pipe_gets_nonblock(int pipe_fd, char *bytes, int max) {
/* convert header values (indicator and 3-byte length) */
static void
-pipe_convert_header(const guchar *header, int header_len _U_, char *indicator, int *block_len) {
+pipe_convert_header(const unsigned char *header, int header_len _U_, char *indicator, int *block_len) {
ws_assert(header_len == 4);
@@ -1540,15 +1767,15 @@ pipe_convert_header(const guchar *header, int header_len _U_, char *indicator, i
(1-byte message indicator, 3-byte message length (excluding length
and indicator field), and the rest is the message) */
static ssize_t
-pipe_read_block(int pipe_fd, char *indicator, int len, char *msg,
+pipe_read_block(GIOChannel *pipe_io, char *indicator, int len, char *msg,
char **err_msg)
{
int required;
ssize_t newly;
- gchar header[4];
+ char header[4];
/* read header (indicator and 3-byte length) */
- newly = pipe_read_bytes(pipe_fd, header, 4, err_msg);
+ newly = pipe_read_bytes(pipe_io, header, 4, err_msg);
if(newly != 4) {
if (newly == 0) {
/*
@@ -1556,59 +1783,62 @@ pipe_read_block(int pipe_fd, char *indicator, int len, char *msg,
* is an "I'm done" indication, so don't report it as an
* error.
*/
- ws_debug("read %d got an EOF", pipe_fd);
+ ws_debug("read %p got an EOF", pipe_io);
return 0;
}
- ws_debug("read %d failed to read header: %lu", pipe_fd, (long)newly);
+ ws_debug("read %p failed to read header: %lu", pipe_io, (long)newly);
if (newly != -1) {
/*
* Short read, but not an immediate EOF.
*/
- *err_msg = g_strdup_printf("Premature EOF reading from sync pipe: got only %ld bytes",
+ *err_msg = ws_strdup_printf("Premature EOF reading from sync pipe: got only %ld bytes",
(long)newly);
}
return -1;
}
/* convert header values */
- pipe_convert_header((guchar*)header, 4, indicator, &required);
+ pipe_convert_header((unsigned char*)header, 4, indicator, &required);
/* only indicator with no value? */
if(required == 0) {
- ws_debug("read %d indicator: %c empty value", pipe_fd, *indicator);
+ ws_debug("read %p indicator: %c empty value", pipe_io, *indicator);
return 4;
}
/* does the data fit into the given buffer? */
if(required > len) {
- ws_debug("read %d length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x",
- pipe_fd, required, len,
+ size_t bytes_read;
+ GError *err = NULL;
+ ws_debug("read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x",
+ pipe_io, required, len,
header[0], header[1], header[2], header[3]);
/* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */
memcpy(msg, header, sizeof(header));
- newly = ws_read(pipe_fd, &msg[sizeof(header)], len-sizeof(header));
- if (newly < 0) { /* error */
- ws_debug("read from pipe %d: error(%u): %s", pipe_fd, errno, g_strerror(errno));
+ g_io_channel_read_chars(pipe_io, &msg[sizeof(header)], len-sizeof(header), &bytes_read, &err);
+ if (err != NULL) { /* error */
+ ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message);
+ g_clear_error(&err);
}
- *err_msg = g_strdup_printf("Unknown message from dumpcap reading header, try to show it as a string: %s",
+ *err_msg = ws_strdup_printf("Unknown message from dumpcap reading header, try to show it as a string: %s",
msg);
return -1;
}
len = required;
/* read the actual block data */
- newly = pipe_read_bytes(pipe_fd, msg, required, err_msg);
+ newly = pipe_read_bytes(pipe_io, msg, required, err_msg);
if(newly != required) {
if (newly != -1) {
- *err_msg = g_strdup_printf("Unknown message from dumpcap reading data, try to show it as a string: %s",
+ *err_msg = ws_strdup_printf("Unknown message from dumpcap reading data, try to show it as a string: %s",
msg);
}
return -1;
}
/* XXX If message is "2part", the msg probably won't be sent to debug log correctly */
- ws_debug("read %d ok indicator: %c len: %u msg: %s", pipe_fd, *indicator, len, msg);
+ ws_debug("read %p ok indicator: %c len: %u msg: %s", pipe_io, *indicator, len, msg);
*err_msg = NULL;
return newly + 4;
}
@@ -1618,21 +1848,21 @@ pipe_read_block(int pipe_fd, char *indicator, int len, char *msg,
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)
+sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
{
- capture_session *cap_session = (capture_session *)user_data;
int ret;
char buffer[SP_MAX_MSG_LEN+1] = {0};
ssize_t nread;
char indicator;
+ int32_t exec_errno = 0;
int primary_len;
char *primary_msg;
int secondary_len;
char *secondary_msg;
char *wait_msg, *combined_msg;
- guint32 npackets = 0;
+ uint32_t npackets = 0;
- nread = pipe_read_block(source, &indicator, SP_MAX_MSG_LEN, buffer,
+ nread = pipe_read_block(pipe_io, &indicator, SP_MAX_MSG_LEN, buffer,
&primary_msg);
if(nread <= 0) {
/* We got a read error, or a bad message, or an EOF, from the sync pipe.
@@ -1660,7 +1890,7 @@ sync_pipe_input_cb(gint source, gpointer user_data)
/* We got an error from the sync pipe. If ret is -1, report
both the sync pipe I/O error and the wait error. */
if (ret == -1) {
- combined_msg = g_strdup_printf("%s\n\n%s", primary_msg, wait_msg);
+ combined_msg = ws_strdup_printf("%s\n\n%s", primary_msg, wait_msg);
g_free(primary_msg);
g_free(wait_msg);
primary_msg = combined_msg;
@@ -1674,11 +1904,13 @@ sync_pipe_input_cb(gint source, gpointer user_data)
#ifdef _WIN32
ws_close(cap_session->signal_pipe_write_fd);
#endif
- ws_debug("cleaning extcap pipe");
- extcap_if_cleanup(cap_session->capture_opts, &primary_msg);
- cap_session->closed(cap_session, primary_msg);
- g_free(primary_msg);
- return FALSE;
+ cap_session->capture_opts->closed_msg = primary_msg;
+ if (extcap_session_stop(cap_session)) {
+ capture_process_finished(cap_session);
+ } else {
+ extcap_request_stop(cap_session);
+ }
+ return false;
}
/* we got a valid message block from the child, process it */
@@ -1688,8 +1920,7 @@ sync_pipe_input_cb(gint source, gpointer user_data)
ws_debug("file failed, closing capture");
/* We weren't able to open the new capture file; user has been
- alerted. Close the sync pipe. */
- ws_close(source);
+ alerted. The sync pipe will close after we return false. */
/* The child has sent us a filename which we couldn't open.
@@ -1705,7 +1936,7 @@ sync_pipe_input_cb(gint source, gpointer user_data)
"standard output", as the capture file. */
sync_pipe_stop(cap_session);
cap_session->closed(cap_session, NULL);
- return FALSE;
+ return false;
}
break;
case SP_PACKET_COUNT:
@@ -1716,22 +1947,41 @@ sync_pipe_input_cb(gint source, gpointer user_data)
cap_session->count += npackets;
cap_session->new_packets(cap_session, npackets);
break;
+ case SP_EXEC_FAILED:
+ /*
+ * Exec of dumpcap failed. Get the errno for the failure.
+ */
+ if (!ws_strtoi32(buffer, NULL, &exec_errno)) {
+ ws_warning("Invalid errno: %s", buffer);
+ }
+ primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",
+ g_strerror(exec_errno));
+ cap_session->error(cap_session, primary_msg, NULL);
+ /* the capture child will close the sync_pipe, nothing to do for now */
+ /* (an error message doesn't mean we have to stop capturing) */
+ break;
case SP_ERROR_MSG:
/* convert primary message */
- pipe_convert_header((guchar*)buffer, 4, &indicator, &primary_len);
+ pipe_convert_header((unsigned char*)buffer, 4, &indicator, &primary_len);
primary_msg = buffer+4;
/* convert secondary message */
- pipe_convert_header((guchar*)primary_msg + primary_len, 4, &indicator, &secondary_len);
+ pipe_convert_header((unsigned char*)primary_msg + primary_len, 4, &indicator, &secondary_len);
secondary_msg = primary_msg + primary_len + 4;
/* message output */
cap_session->error(cap_session, primary_msg, secondary_msg);
/* the capture child will close the sync_pipe, nothing to do for now */
/* (an error message doesn't mean we have to stop capturing) */
break;
+ case SP_LOG_MSG:
+ /*
+ * Log from dumpcap; pass to our log
+ */
+ sync_pipe_handle_log_msg(buffer);
+ break;
case SP_BAD_FILTER: {
const char *message=NULL;
- guint32 indx = 0;
- const gchar* end;
+ uint32_t indx = 0;
+ const char* end;
if (ws_strtou32(buffer, &end, &indx) && end[0] == ':') {
message = end + 1;
@@ -1743,8 +1993,8 @@ sync_pipe_input_cb(gint source, gpointer user_data)
}
case SP_DROPS: {
const char *name = NULL;
- const gchar* end;
- guint32 num = 0;
+ const char* end;
+ uint32_t num = 0;
if (ws_strtou32(buffer, &end, &num) && end[0] == ':') {
name = end + 1;
@@ -1754,10 +2004,14 @@ sync_pipe_input_cb(gint source, gpointer user_data)
break;
}
default:
- ws_assert_not_reached();
+ if (g_ascii_isprint(indicator))
+ ws_warning("Unknown indicator '%c'", indicator);
+ else
+ ws_warning("Unknown indicator '\\x%02x", indicator);
+ break;
}
- return TRUE;
+ return true;
}
@@ -1771,14 +2025,14 @@ sync_pipe_input_cb(gint source, gpointer user_data)
* must be freed with g_free().
*/
static int
-sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
+sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp)
{
int fork_child_status;
#ifndef _WIN32
int retry_waitpid = 3;
#endif
int ret = -1;
- gint64 start_time;
+ int64_t start_time;
double elapsed;
start_time = g_get_monotonic_time();
@@ -1789,7 +2043,7 @@ sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
*msgp = NULL; /* assume no error */
#ifdef _WIN32
if (_cwait(&fork_child_status, (intptr_t) fork_child, _WAIT_CHILD) == -1) {
- *msgp = g_strdup_printf("Error from cwait(): %s", g_strerror(errno));
+ *msgp = ws_strdup_printf("Error from cwait(): %s", g_strerror(errno));
ret = -1;
} else {
/*
@@ -1799,7 +2053,7 @@ sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
ret = fork_child_status;
if ((fork_child_status & 0xC0000000) == ERROR_SEVERITY_ERROR) {
/* Probably an exception code */
- *msgp = g_strdup_printf("Child dumpcap process died: %s",
+ *msgp = ws_strdup_printf("Child dumpcap process died: %s",
win32strexception(fork_child_status));
ret = -1;
}
@@ -1816,19 +2070,19 @@ sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
ret = WEXITSTATUS(fork_child_status);
} else if (WIFSTOPPED(fork_child_status)) {
/* It stopped, rather than exiting. "Should not happen." */
- *msgp = g_strdup_printf("Child dumpcap process stopped: %s",
+ *msgp = ws_strdup_printf("Child dumpcap process stopped: %s",
sync_pipe_signame(WSTOPSIG(fork_child_status)));
ret = -1;
} else if (WIFSIGNALED(fork_child_status)) {
/* It died with a signal. */
- *msgp = g_strdup_printf("Child dumpcap process died: %s%s",
+ *msgp = ws_strdup_printf("Child dumpcap process died: %s%s",
sync_pipe_signame(WTERMSIG(fork_child_status)),
WCOREDUMP(fork_child_status) ? " - core dumped" : "");
ret = -1;
} else {
/* What? It had to either have exited, or stopped, or died with
a signal; what happened here? */
- *msgp = g_strdup_printf("Bad status from waitpid(): %#o",
+ *msgp = ws_strdup_printf("Bad status from waitpid(): %#o",
fork_child_status);
ret = -1;
}
@@ -1863,7 +2117,7 @@ sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
ret = fetch_dumpcap_pid ? 0 : -1;
} else {
/* Unknown error. */
- *msgp = g_strdup_printf("Error from waitpid(): %s", g_strerror(errno));
+ *msgp = ws_strdup_printf("Error from waitpid(): %s", g_strerror(errno));
ret = -1;
}
}
@@ -1965,7 +2219,7 @@ sync_pipe_signame(int sig)
default:
/* Returning a static buffer is ok in the context we use it here */
- g_snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
+ snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
sigmsg = sigmsg_buf;
break;
}
@@ -1976,20 +2230,26 @@ sync_pipe_signame(int sig)
#ifdef _WIN32
-static void create_dummy_signal_pipe() {
- gchar *dummy_signal_pipe_name;
+static int create_dummy_signal_pipe(char **msg) {
+ char *dummy_signal_pipe_name;
- if (dummy_signal_pipe != NULL) return;
+ if (dummy_signal_pipe != NULL) return 0;
if (!dummy_control_id) {
- dummy_control_id = g_strdup_printf("%d.dummy", GetCurrentProcessId());
+ dummy_control_id = ws_strdup_printf("%ld.dummy", GetCurrentProcessId());
}
/* Create the signal pipe */
- dummy_signal_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT, dummy_control_id);
+ dummy_signal_pipe_name = ws_strdup_printf(SIGNAL_PIPE_FORMAT, dummy_control_id);
dummy_signal_pipe = CreateNamedPipe(utf_8to16(dummy_signal_pipe_name),
PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL);
g_free(dummy_signal_pipe_name);
+ if (dummy_signal_pipe == INVALID_HANDLE_VALUE) {
+ *msg = ws_strdup_printf("Couldn't create signal pipe: %s",
+ win32strerror(GetLastError()));
+ return -1;
+ }
+ return 0;
}
/* tell the child through the signal pipe that we want to quit the capture */
@@ -2003,10 +2263,10 @@ signal_pipe_capquit_to_child(capture_session *cap_session)
/* it doesn't matter *what* we send here, the first byte will stop the capture */
/* simply sending a "QUIT" string */
- /*pipe_write_block(cap_session->signal_pipe_write_fd, SP_QUIT, quit_msg);*/
+ /*sync_pipe_write_string_msg(cap_session->signal_pipe_write_fd, SP_QUIT, quit_msg);*/
ret = ws_write(cap_session->signal_pipe_write_fd, quit_msg, sizeof quit_msg);
if(ret == -1) {
- ws_warning("%d header: error %s", cap_session->signal_pipe_write_fd, g_strerror(errno));
+ ws_warning("%d header: error %s", cap_session->signal_pipe_write_fd, win32strerror(GetLastError()));
}
}
#endif
@@ -2016,11 +2276,6 @@ signal_pipe_capquit_to_child(capture_session *cap_session)
void
sync_pipe_stop(capture_session *cap_session)
{
-#ifdef _WIN32
- int count;
- DWORD childstatus;
- gboolean terminate = TRUE;
-#endif
if (cap_session->fork_child != WS_INVALID_PID) {
#ifndef _WIN32
/* send the SIGINT signal to close the capture child gracefully. */
@@ -2030,24 +2285,18 @@ sync_pipe_stop(capture_session *cap_session)
}
#else
#define STOP_SLEEP_TIME 500 /* ms */
-#define STOP_CHECK_TIME 50
+ DWORD status;
+
/* First, use the special signal pipe to try to close the capture child
* gracefully.
*/
signal_pipe_capquit_to_child(cap_session);
/* Next, wait for the process to exit on its own */
- for (count = 0; count < STOP_SLEEP_TIME / STOP_CHECK_TIME; count++) {
- if (GetExitCodeProcess((HANDLE) cap_session->fork_child, &childstatus) &&
- childstatus != STILL_ACTIVE) {
- terminate = FALSE;
- break;
- }
- Sleep(STOP_CHECK_TIME);
- }
+ status = WaitForSingleObject((HANDLE) cap_session->fork_child, STOP_SLEEP_TIME);
/* Force the issue. */
- if (terminate) {
+ if (status != WAIT_OBJECT_0) {
ws_warning("sync_pipe_stop: forcing child to exit");
sync_pipe_kill(cap_session->fork_child);
}