aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2018-03-01 15:31:45 -0800
committerAnders Broman <a.broman58@gmail.com>2018-03-02 05:22:20 +0000
commit1a0987904fa571dc5abce03726e4ca3e17793574 (patch)
tree59b7bfe30517005b046bddb9fcae2315f48570fa
parentbf4c2fd82b30d8b088fcb1235263dce9173d4cd7 (diff)
Generalize our process spawning code.
Move the contents of extcap_spawn to ws_pipe. Rename various extcap_* prefixes to ws_pipe_*. Open stdin when we spawn processes. Change-Id: I9286295443ee955bb6328b0ed6f945ee0bb2a798 Reviewed-on: https://code.wireshark.org/review/26216 Reviewed-by: Gerald Combs <gerald@wireshark.org> Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--CMakeLists.txt1
-rw-r--r--Makefile.am4
-rw-r--r--capture_opts.c11
-rw-r--r--capture_opts.h8
-rw-r--r--extcap.c71
-rw-r--r--extcap_spawn.c381
-rw-r--r--extcap_spawn.h54
-rw-r--r--wsutil/ws_pipe.c352
-rw-r--r--wsutil/ws_pipe.h26
9 files changed, 420 insertions, 488 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0a4824a601..406b34e388 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1577,7 +1577,6 @@ set(SHARK_COMMON_SRC
version_info.c
extcap.c
extcap_parser.c
- extcap_spawn.c
)
set(TSHARK_TAP_SRC
diff --git a/Makefile.am b/Makefile.am
index f93cad4c15..7d9ca8de47 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -380,8 +380,7 @@ SHARK_COMMON_SRC = \
frame_tvbuff.c \
sync_pipe_write.c \
extcap.c \
- extcap_parser.c \
- extcap_spawn.c
+ extcap_parser.c
# wireshark specifics
WIRESHARK_COMMON_SRC = \
@@ -722,7 +721,6 @@ noinst_HEADERS = \
conditions.h \
extcap.h \
extcap_parser.h \
- extcap_spawn.h \
fileset.h \
frame_tvbuff.h \
ringbuffer.h \
diff --git a/capture_opts.c b/capture_opts.c
index 5d6e84d641..a8bddee36f 100644
--- a/capture_opts.c
+++ b/capture_opts.c
@@ -27,6 +27,7 @@
#include <wsutil/clopts_common.h>
#include <wsutil/cmdarg_err.h>
#include <wsutil/file_util.h>
+#include <wsutil/ws_pipe.h>
#include "caputils/capture_ifinfo.h"
#include "caputils/capture-pcap-util.h"
@@ -53,7 +54,7 @@ capture_opts_init(capture_options *capture_opts)
capture_opts->default_options.extcap = NULL;
capture_opts->default_options.extcap_fifo = NULL;
capture_opts->default_options.extcap_args = NULL;
- capture_opts->default_options.extcap_userdata = NULL;
+ capture_opts->default_options.extcap_pipedata = NULL;
capture_opts->default_options.extcap_pid = INVALID_EXTCAP_PID;
#ifdef _WIN32
capture_opts->default_options.extcap_pipe_h = INVALID_HANDLE_VALUE;
@@ -684,7 +685,7 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str
interface_opts.extcap_fifo = g_strdup(capture_opts->default_options.extcap_fifo);
interface_opts.extcap_args = NULL;
interface_opts.extcap_pid = INVALID_EXTCAP_PID;
- interface_opts.extcap_userdata = NULL;
+ interface_opts.extcap_pipedata = NULL;
#ifdef _WIN32
interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE;
interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE;
@@ -1127,7 +1128,7 @@ capture_opts_del_iface(capture_options *capture_opts, guint if_index)
g_hash_table_unref(interface_opts->extcap_args);
if (interface_opts->extcap_pid != INVALID_EXTCAP_PID)
g_spawn_close_pid(interface_opts->extcap_pid);
- g_free(interface_opts->extcap_userdata);
+ g_free(interface_opts->extcap_pipedata);
g_free(interface_opts->extcap_control_in);
g_free(interface_opts->extcap_control_out);
#ifdef HAVE_PCAP_REMOTE
@@ -1174,12 +1175,12 @@ collect_ifaces(capture_options *capture_opts)
interface_opts.if_type = device->if_info.type;
interface_opts.extcap = g_strdup(device->if_info.extcap);
interface_opts.extcap_fifo = NULL;
- interface_opts.extcap_userdata = NULL;
+ interface_opts.extcap_pipedata = NULL;
interface_opts.extcap_args = device->external_cap_args_settings;
interface_opts.extcap_pid = INVALID_EXTCAP_PID;
if (interface_opts.extcap_args)
g_hash_table_ref(interface_opts.extcap_args);
- interface_opts.extcap_userdata = NULL;
+ interface_opts.extcap_pipedata = NULL;
#ifdef _WIN32
interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE;
interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE;
diff --git a/capture_opts.h b/capture_opts.h
index 715a3bee90..7c344e31a7 100644
--- a/capture_opts.h
+++ b/capture_opts.h
@@ -198,12 +198,6 @@ typedef struct link_row_tag {
gint dlt;
} link_row;
-#ifdef _WIN32
-#define INVALID_EXTCAP_PID INVALID_HANDLE_VALUE
-#else
-#define INVALID_EXTCAP_PID (GPid)-1
-#endif
-
typedef struct interface_options_tag {
gchar *name; /* the name of the interface provided to winpcap/libpcap to specify the interface */
gchar *descr;
@@ -218,7 +212,7 @@ typedef struct interface_options_tag {
gchar *extcap_fifo;
GHashTable *extcap_args;
GPid extcap_pid; /* pid of running process or INVALID_EXTCAP_PID */
- gpointer extcap_userdata;
+ gpointer extcap_pipedata;
guint extcap_child_watch;
#ifdef _WIN32
HANDLE extcap_pipe_h;
diff --git a/extcap.c b/extcap.c
index 25932affd7..d83fd9c27e 100644
--- a/extcap.c
+++ b/extcap.c
@@ -49,7 +49,6 @@
#include "extcap.h"
#include "extcap_parser.h"
-#include "extcap_spawn.h"
#ifdef _WIN32
static HANDLE pipe_h = INVALID_HANDLE_VALUE;
@@ -319,7 +318,7 @@ static gboolean extcap_foreach(gint argc, gchar **args,
continue;
}
- if (extcap_spawn_sync((gchar *) dirname, extcap_path->str, argc, args, &command_output))
+ if (ws_pipe_spawn_sync((gchar *) dirname, extcap_path->str, argc, args, &command_output))
{
cb_info.output = command_output;
cb_info.extcap = extcap_path->str;
@@ -957,7 +956,7 @@ extcap_has_toolbar(const char *ifname)
void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
{
interface_options *interface_opts;
- extcap_userdata *userdata;
+ ws_pipe_t *pipedata;
guint icnt = 0;
gboolean overwrite_exitcode;
gchar *buffer;
@@ -1031,17 +1030,17 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
"Extcap [%s] - Closing spawned PID: %d", interface_opts->name,
interface_opts->extcap_pid);
- userdata = (extcap_userdata *) interface_opts->extcap_userdata;
- if (userdata)
+ pipedata = (ws_pipe_t *) interface_opts->extcap_pipedata;
+ if (pipedata)
{
- if (userdata->extcap_stderr_rd > 0 && ws_pipe_data_available(userdata->extcap_stderr_rd))
+ if (pipedata->stderr_fd > 0 && ws_pipe_data_available(pipedata->stderr_fd))
{
buffer = (gchar *)g_malloc0(STDERR_BUFFER_SIZE + 1);
- ws_read_string_from_pipe(ws_get_pipe_handle(userdata->extcap_stderr_rd), buffer, STDERR_BUFFER_SIZE + 1);
+ ws_read_string_from_pipe(ws_get_pipe_handle(pipedata->stderr_fd), buffer, STDERR_BUFFER_SIZE + 1);
if (strlen(buffer) > 0)
{
- userdata->extcap_stderr = g_strdup_printf("%s", buffer);
- userdata->exitcode = 1;
+ pipedata->stderr_msg = g_strdup_printf("%s", buffer);
+ pipedata->exitcode = 1;
}
g_free(buffer);
}
@@ -1050,37 +1049,37 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
/* Final child watch may not have been called */
if (interface_opts->extcap_child_watch != 0)
{
- extcap_child_watch_cb(userdata->pid, 0, capture_opts);
+ extcap_child_watch_cb(pipedata->pid, 0, capture_opts);
/* it will have changed in extcap_child_watch_cb */
interface_opts = &g_array_index(capture_opts->ifaces, interface_options,
icnt);
}
#endif
- if (userdata->extcap_stderr != NULL)
+ if (pipedata->stderr_msg != NULL)
{
overwrite_exitcode = TRUE;
}
- if (overwrite_exitcode || userdata->exitcode != 0)
+ if (overwrite_exitcode || pipedata->exitcode != 0)
{
- if (userdata->extcap_stderr != 0)
+ if (pipedata->stderr_msg != 0)
{
if (*errormsg == NULL)
{
- *errormsg = g_strdup_printf("Error by extcap pipe: %s", userdata->extcap_stderr);
+ *errormsg = g_strdup_printf("Error by extcap pipe: %s", pipedata->stderr_msg);
}
else
{
- gchar *temp = g_strconcat(*errormsg, "\nError by extcap pipe: " , userdata->extcap_stderr, NULL);
+ gchar *temp = g_strconcat(*errormsg, "\nError by extcap pipe: " , pipedata->stderr_msg, NULL);
g_free(*errormsg);
*errormsg = temp;
}
- g_free(userdata->extcap_stderr);
+ g_free(pipedata->stderr_msg);
}
- userdata->extcap_stderr = NULL;
- userdata->exitcode = 0;
+ pipedata->stderr_msg = NULL;
+ pipedata->exitcode = 0;
}
}
@@ -1098,8 +1097,8 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
g_spawn_close_pid(interface_opts->extcap_pid);
interface_opts->extcap_pid = INVALID_EXTCAP_PID;
- g_free(interface_opts->extcap_userdata);
- interface_opts->extcap_userdata = NULL;
+ g_free(interface_opts->extcap_pipedata);
+ interface_opts->extcap_pipedata = NULL;
}
}
}
@@ -1128,7 +1127,7 @@ void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data)
{
guint i;
interface_options *interface_opts;
- extcap_userdata *userdata = NULL;
+ ws_pipe_t *pipedata = NULL;
capture_options *capture_opts = (capture_options *)(user_data);
if (capture_opts == NULL || capture_opts->ifaces == NULL || capture_opts->ifaces->len == 0)
@@ -1145,32 +1144,32 @@ void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data)
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
if (interface_opts->extcap_pid == pid)
{
- userdata = (extcap_userdata *)interface_opts->extcap_userdata;
- if (userdata != NULL)
+ pipedata = (ws_pipe_t *)interface_opts->extcap_pipedata;
+ if (pipedata != NULL)
{
interface_opts->extcap_pid = INVALID_EXTCAP_PID;
- userdata->exitcode = 0;
+ pipedata->exitcode = 0;
#ifndef _WIN32
if (WIFEXITED(status))
{
if (WEXITSTATUS(status) != 0)
{
- userdata->exitcode = WEXITSTATUS(status);
+ pipedata->exitcode = WEXITSTATUS(status);
}
}
else
{
- userdata->exitcode = G_SPAWN_ERROR_FAILED;
+ pipedata->exitcode = G_SPAWN_ERROR_FAILED;
}
#else
if (status != 0)
{
- userdata->exitcode = status;
+ pipedata->exitcode = status;
}
#endif
- if (status == 0 && userdata->extcap_stderr != NULL)
+ if (status == 0 && pipedata->stderr_msg != NULL)
{
- userdata->exitcode = 1;
+ pipedata->exitcode = 1;
}
}
g_source_remove(interface_opts->extcap_child_watch);
@@ -1288,7 +1287,7 @@ extcap_init_interfaces(capture_options *capture_opts)
{
guint i;
interface_options *interface_opts;
- extcap_userdata *userdata;
+ ws_pipe_t *pipedata;
for (i = 0; i < capture_opts->ifaces->len; i++)
{
@@ -1331,16 +1330,16 @@ extcap_init_interfaces(capture_options *capture_opts)
/* Create extcap call */
args = extcap_prepare_arguments(interface_opts);
- userdata = g_new0(extcap_userdata, 1);
+ pipedata = g_new0(ws_pipe_t, 1);
- pid = extcap_spawn_async(userdata, args);
+ pid = ws_pipe_spawn_async(pipedata, args);
g_ptr_array_foreach(args, (GFunc)g_free, NULL);
g_ptr_array_free(args, TRUE);
if (pid == INVALID_EXTCAP_PID)
{
- g_free(userdata);
+ g_free(pipedata);
continue;
}
@@ -1356,8 +1355,6 @@ extcap_init_interfaces(capture_options *capture_opts)
* connect to named pipe (including user interaction).
* Wait on multiple object in case of extcap termination
* without opening pipe.
- *
- * Minimum supported version of Windows: XP / Server 2003.
*/
if (pid != INVALID_EXTCAP_PID)
{
@@ -1372,11 +1369,11 @@ extcap_init_interfaces(capture_options *capture_opts)
num_pipe_handles += 2;
}
- extcap_wait_for_pipe(pipe_handles, num_pipe_handles, pid);
+ ws_pipe_wait_for_pipe(pipe_handles, num_pipe_handles, pid);
}
#endif
- interface_opts->extcap_userdata = (gpointer) userdata;
+ interface_opts->extcap_pipedata = (gpointer) pipedata;
}
return TRUE;
diff --git a/extcap_spawn.c b/extcap_spawn.c
deleted file mode 100644
index 816e0e3a5f..0000000000
--- a/extcap_spawn.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/* extcap_spawn.c
- *
- * Routines to spawn extcap external capture programs
- * Copyright 2016, Roland Knall <rknall@gmail.com>
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 1998 Gerald Combs
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <glib.h>
-#include <string.h>
-
-#include <wsutil/file_util.h>
-#include <wsutil/filesystem.h>
-#include <wsutil/ws_pipe.h>
-#ifdef _WIN32
-#include <wsutil/win32-utils.h>
-#endif
-
-#include <log.h>
-
-#include "extcap.h"
-#include "extcap_spawn.h"
-
-gboolean extcap_spawn_sync(gchar *dirname, gchar *command, gint argc, gchar **args, gchar **command_output)
-{
- gboolean status = FALSE;
- gboolean result = FALSE;
- gchar **argv = NULL;
- gint cnt = 0;
- gchar *local_output = NULL;
-#ifdef _WIN32
-
-#define BUFFER_SIZE 16384
-
- GString *winargs = g_string_sized_new(200);
- gchar *quoted_arg;
- gunichar2 *wcommandline;
-
- STARTUPINFO info;
- PROCESS_INFORMATION processInfo;
-
- SECURITY_ATTRIBUTES sa;
- HANDLE child_stdout_rd = NULL;
- HANDLE child_stdout_wr = NULL;
- HANDLE child_stderr_rd = NULL;
- HANDLE child_stderr_wr = NULL;
-
- const gchar *oldpath = g_getenv("PATH");
- gchar *newpath = NULL;
-#else
- gint exit_status = 0;
-#endif
-
- argv = (gchar **) g_malloc0(sizeof(gchar *) * (argc + 2));
-
-#ifdef _WIN32
- newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
- g_setenv("PATH", newpath, TRUE);
-
- argv[0] = g_strescape(command, NULL);
-#else
- argv[0] = g_strdup(command);
-#endif
-
- for (cnt = 0; cnt < argc; cnt++)
- argv[cnt + 1] = args[cnt];
- argv[argc + 1] = NULL;
-
-#ifdef _WIN32
-
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
- {
- g_free(argv[0]);
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
- return FALSE;
- }
-
- if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
- {
- CloseHandle(child_stdout_rd);
- CloseHandle(child_stdout_wr);
- g_free(argv[0]);
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
- return FALSE;
- }
-
- /* 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 (cnt = 0; argv[cnt] != 0; cnt++) {
- if (cnt != 0) g_string_append_c(winargs, ' '); /* don't prepend a space before the path!!! */
- quoted_arg = protect_arg(argv[cnt]);
- g_string_append(winargs, quoted_arg);
- g_free(quoted_arg);
- }
-
- wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
-
- memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
- memset(&info, 0, sizeof(STARTUPINFO));
-
- info.cb = sizeof(STARTUPINFO);
- info.hStdError = child_stderr_wr;
- info.hStdOutput = child_stdout_wr;
- info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- info.wShowWindow = SW_HIDE;
-
- if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
- {
- gchar* buffer;
-
- WaitForSingleObject(processInfo.hProcess, INFINITE);
- buffer = (gchar*)g_malloc(BUFFER_SIZE);
- status = ws_read_string_from_pipe(child_stdout_rd, buffer, BUFFER_SIZE);
- if (status)
- {
- local_output = g_strdup_printf("%s", buffer);
- }
- g_free(buffer);
-
- CloseHandle(child_stdout_rd);
- CloseHandle(child_stdout_wr);
- CloseHandle(child_stderr_rd);
- CloseHandle(child_stderr_wr);
-
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
- }
- else
- status = FALSE;
-
- g_setenv("PATH", oldpath, TRUE);
-#else
-
- status = g_spawn_sync(dirname, argv, NULL,
- (GSpawnFlags) 0, NULL, NULL, &local_output, NULL, &exit_status, NULL);
-
- if (status && exit_status != 0)
- status = FALSE;
-#endif
-
- if (status)
- {
- if (command_output != NULL && local_output != NULL)
- *command_output = g_strdup(local_output);
-
- result = TRUE;
- }
-
- g_free(local_output);
- g_free(argv[0]);
- g_free(argv);
-
- return result;
-}
-
-GPid extcap_spawn_async(extcap_userdata *userdata, GPtrArray *args)
-{
- GPid pid = INVALID_EXTCAP_PID;
-
-#ifdef _WIN32
- gint cnt = 0;
- gchar **tmp = NULL;
-
- GString *winargs = g_string_sized_new(200);
- gchar *quoted_arg;
- gunichar2 *wcommandline;
-
- STARTUPINFO info;
- PROCESS_INFORMATION processInfo;
-
- SECURITY_ATTRIBUTES sa;
- HANDLE child_stdout_rd = NULL;
- HANDLE child_stdout_wr = NULL;
- HANDLE child_stderr_rd = NULL;
- HANDLE child_stderr_wr = NULL;
-
- const gchar *oldpath = g_getenv("PATH");
- gchar *newpath = NULL;
-
- newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
- g_setenv("PATH", newpath, TRUE);
-
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
- {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
- return FALSE;
- }
-
- if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
- {
- CloseHandle(child_stdout_rd);
- CloseHandle(child_stdout_wr);
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
- return FALSE;
- }
-
- /* 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 (tmp = (gchar **)args->pdata, cnt = 0; *tmp && **tmp; ++cnt, ++tmp) {
- if (cnt != 0) g_string_append_c(winargs, ' '); /* don't prepend a space before the path!!! */
- quoted_arg = protect_arg(*tmp);
- g_string_append(winargs, quoted_arg);
- g_free(quoted_arg);
- }
-
- wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
-
- memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
- memset(&info, 0, sizeof(STARTUPINFO));
-
- info.cb = sizeof(STARTUPINFO);
- info.hStdError = child_stderr_wr;
- info.hStdOutput = child_stdout_wr;
- info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- info.wShowWindow = SW_HIDE;
-
- if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
- {
- userdata->extcap_stderr_rd = _open_osfhandle((intptr_t)(child_stderr_rd), _O_BINARY);
- userdata->extcap_stdout_rd = _open_osfhandle((intptr_t)(child_stdout_rd), _O_BINARY);
- userdata->threadId = processInfo.hThread;
- pid = processInfo.hProcess;
- }
-
- g_setenv("PATH", oldpath, TRUE);
-#else
- g_spawn_async_with_pipes(NULL, (gchar **)args->pdata, NULL,
- (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
- &pid, NULL, &userdata->extcap_stdout_rd, &userdata->extcap_stderr_rd, NULL);
-#endif
-
- userdata->pid = pid;
-
- return pid;
-}
-
-#ifdef _WIN32
-
-typedef struct
-{
- HANDLE pipeHandle;
- OVERLAPPED ol;
- BOOL pendingIO;
-} PIPEINTS;
-
-gboolean
-extcap_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
-{
- PIPEINTS pipeinsts[3];
- DWORD dw, cbRet;
- HANDLE handles[4];
- int error_code;
- int num_waiting_to_connect = 0;
- int num_handles = num_pipe_handles + 1; // PID handle is also added to list of handles.
-
- if (num_pipe_handles == 0 || num_pipe_handles > 3)
- {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Invalid number of pipes given as argument.");
- return FALSE;
- }
-
- for (int i = 0; i < num_pipe_handles; ++i)
- {
- pipeinsts[i].pipeHandle = pipe_handles[i];
- pipeinsts[i].ol.Pointer = 0;
- pipeinsts[i].ol.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- pipeinsts[i].pendingIO = FALSE;
- handles[i] = pipeinsts[i].ol.hEvent;
- BOOL connected = ConnectNamedPipe(pipeinsts[i].pipeHandle, &pipeinsts[i].ol);
- if (connected)
- {
- error_code = GetLastError();
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
- return FALSE;
- }
-
- switch (GetLastError())
- {
- case ERROR_IO_PENDING:
- num_waiting_to_connect++;
- pipeinsts[i].pendingIO = TRUE;
- break;
-
- case ERROR_PIPE_CONNECTED:
- if (SetEvent(pipeinsts[i].ol.hEvent))
- {
- break;
- } // Fallthrough if this fails.
-
- default:
- error_code = GetLastError();
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
- return FALSE;
- }
- }
-
- // Store pid of extcap process so it can be monitored in case it fails before the pipes has connceted.
- handles[num_pipe_handles] = pid;
-
- while(num_waiting_to_connect > 0)
- {
- dw = WaitForMultipleObjects(num_handles, handles, FALSE, 30000);
- int idx = dw - WAIT_OBJECT_0;
- if (dw == WAIT_TIMEOUT)
- {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds.");
- return FALSE;
- }
- // If index points to our handles array
- else if (idx >= 0 && idx < num_handles)
- {
- if (idx < num_pipe_handles) // Index of pipe handle
- {
- if (pipeinsts[idx].pendingIO)
- {
- BOOL success = GetOverlappedResult(
- pipeinsts[idx].pipeHandle, // handle to pipe
- &pipeinsts[idx].ol, // OVERLAPPED structure
- &cbRet, // bytes transferred
- FALSE); // do not wait
-
- if (!success)
- {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Error %d \n.", GetLastError());
- return FALSE;
- }
- else
- {
- pipeinsts[idx].pendingIO = FALSE;
- CloseHandle(pipeinsts[idx].ol.hEvent);
- num_waiting_to_connect--;
- }
- }
- }
- else // Index of PID
- {
- // Fail since index of 'pid' indicates that the pid of the extcap process has terminated.
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe.");
- return FALSE;
- }
- }
- else
- {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
- return FALSE;
- }
- }
-
- return TRUE;
-}
-#endif
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/extcap_spawn.h b/extcap_spawn.h
deleted file mode 100644
index 0557a6f352..0000000000
--- a/extcap_spawn.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* extcap_spawn.h
- * Helper routines for executing extcap utilities
- *
- * Copyright 2016, Roland Knall <rknall@gmail.com>
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 1998 Gerald Combs
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef __EXTCAP_SPAWN_H__
-#define __EXTCAP_SPAWN_H__
-
-#include <config.h>
-
-#include <glib.h>
-
-#include <extcap.h>
-
-typedef struct _extcap_userdata {
- GPid pid;
- gchar * extcap_stderr;
- gint exitcode;
- gint extcap_stderr_rd;
- gint extcap_stdout_rd;
-#ifdef _WIN32
- HANDLE threadId;
-#endif
-} extcap_userdata;
-
-gboolean extcap_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar ** argv, gchar ** command_output );
-
-GPid extcap_spawn_async ( extcap_userdata * userdata, GPtrArray * args );
-
-#ifdef _WIN32
-gboolean extcap_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid);
-#endif
-
-#endif
-
-/*
- * Editor modelines - http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/wsutil/ws_pipe.c b/wsutil/ws_pipe.c
index 2c0f28b89e..3649276864 100644
--- a/wsutil/ws_pipe.c
+++ b/wsutil/ws_pipe.c
@@ -18,6 +18,8 @@
#ifdef _WIN32
#include <windows.h>
#include <io.h>
+#include <fcntl.h> /* for _O_BINARY */
+#include <wsutil/win32-utils.h>
#else
#include <unistd.h>
#ifdef HAVE_SYS_SELECT_H
@@ -28,8 +30,358 @@
#include <glib.h>
#include <log.h>
+#include <wsutil/filesystem.h>
#include "wsutil/ws_pipe.h"
+gboolean ws_pipe_spawn_sync(gchar *dirname, gchar *command, gint argc, gchar **args, gchar **command_output)
+{
+ gboolean status = FALSE;
+ gboolean result = FALSE;
+ gchar **argv = NULL;
+ gint cnt = 0;
+ gchar *local_output = NULL;
+#ifdef _WIN32
+
+#define BUFFER_SIZE 16384
+
+ GString *winargs = g_string_sized_new(200);
+ gchar *quoted_arg;
+ gunichar2 *wcommandline;
+
+ STARTUPINFO info;
+ PROCESS_INFORMATION processInfo;
+
+ SECURITY_ATTRIBUTES sa;
+ HANDLE child_stdout_rd = NULL;
+ HANDLE child_stdout_wr = NULL;
+ HANDLE child_stderr_rd = NULL;
+ HANDLE child_stderr_wr = NULL;
+
+ const gchar *oldpath = g_getenv("PATH");
+ gchar *newpath = NULL;
+#else
+ gint exit_status = 0;
+#endif
+
+ argv = (gchar **) g_malloc0(sizeof(gchar *) * (argc + 2));
+
+#ifdef _WIN32
+ newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
+ g_setenv("PATH", newpath, TRUE);
+
+ argv[0] = g_strescape(command, NULL);
+#else
+ argv[0] = g_strdup(command);
+#endif
+
+ for (cnt = 0; cnt < argc; cnt++)
+ argv[cnt + 1] = args[cnt];
+ argv[argc + 1] = NULL;
+
+#ifdef _WIN32
+
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
+ {
+ g_free(argv[0]);
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
+ return FALSE;
+ }
+
+ if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
+ {
+ CloseHandle(child_stdout_rd);
+ CloseHandle(child_stdout_wr);
+ g_free(argv[0]);
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
+ return FALSE;
+ }
+
+ /* 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 (cnt = 0; argv[cnt] != 0; cnt++) {
+ if (cnt != 0) g_string_append_c(winargs, ' '); /* don't prepend a space before the path!!! */
+ quoted_arg = protect_arg(argv[cnt]);
+ g_string_append(winargs, quoted_arg);
+ g_free(quoted_arg);
+ }
+
+ wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
+
+ memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
+ memset(&info, 0, sizeof(STARTUPINFO));
+
+ info.cb = sizeof(STARTUPINFO);
+ info.hStdError = child_stderr_wr;
+ info.hStdOutput = child_stdout_wr;
+ info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ info.wShowWindow = SW_HIDE;
+
+ if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
+ {
+ gchar* buffer;
+
+ WaitForSingleObject(processInfo.hProcess, INFINITE);
+ buffer = (gchar*)g_malloc(BUFFER_SIZE);
+ status = ws_read_string_from_pipe(child_stdout_rd, buffer, BUFFER_SIZE);
+ if (status)
+ {
+ local_output = g_strdup_printf("%s", buffer);
+ }
+ g_free(buffer);
+
+ CloseHandle(child_stdout_rd);
+ CloseHandle(child_stdout_wr);
+ CloseHandle(child_stderr_rd);
+ CloseHandle(child_stderr_wr);
+
+ CloseHandle(processInfo.hProcess);
+ CloseHandle(processInfo.hThread);
+ }
+ else
+ status = FALSE;
+
+ g_setenv("PATH", oldpath, TRUE);
+#else
+
+ status = g_spawn_sync(dirname, argv, NULL,
+ (GSpawnFlags) 0, NULL, NULL, &local_output, NULL, &exit_status, NULL);
+
+ if (status && exit_status != 0)
+ status = FALSE;
+#endif
+
+ if (status)
+ {
+ if (command_output != NULL && local_output != NULL)
+ *command_output = g_strdup(local_output);
+
+ result = TRUE;
+ }
+
+ g_free(local_output);
+ g_free(argv[0]);
+ g_free(argv);
+
+ return result;
+}
+
+GPid ws_pipe_spawn_async(ws_pipe_t *ws_pipe, GPtrArray *args)
+{
+ GPid pid = INVALID_EXTCAP_PID;
+
+#ifdef _WIN32
+ gint cnt = 0;
+ gchar **tmp = NULL;
+
+ GString *winargs = g_string_sized_new(200);
+ gchar *quoted_arg;
+ gunichar2 *wcommandline;
+
+ STARTUPINFO info;
+ PROCESS_INFORMATION processInfo;
+
+ SECURITY_ATTRIBUTES sa;
+ HANDLE child_stdin_rd = NULL;
+ HANDLE child_stdin_wr = NULL;
+ HANDLE child_stdout_rd = NULL;
+ HANDLE child_stdout_wr = NULL;
+ HANDLE child_stderr_rd = NULL;
+ HANDLE child_stderr_wr = NULL;
+
+ const gchar *oldpath = g_getenv("PATH");
+ gchar *newpath = NULL;
+
+ newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
+ g_setenv("PATH", newpath, TRUE);
+
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe(&child_stdin_rd, &child_stdin_wr, &sa, 0))
+ {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdin handle");
+ return FALSE;
+ }
+
+ if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
+ {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
+ return FALSE;
+ }
+
+ if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
+ {
+ CloseHandle(child_stdout_rd);
+ CloseHandle(child_stdout_wr);
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
+ return FALSE;
+ }
+
+ /* 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 (tmp = (gchar **)args->pdata, cnt = 0; *tmp && **tmp; ++cnt, ++tmp) {
+ if (cnt != 0) g_string_append_c(winargs, ' '); /* don't prepend a space before the path!!! */
+ quoted_arg = protect_arg(*tmp);
+ g_string_append(winargs, quoted_arg);
+ g_free(quoted_arg);
+ }
+
+ wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
+
+ memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
+ memset(&info, 0, sizeof(STARTUPINFO));
+
+ info.cb = sizeof(STARTUPINFO);
+ info.hStdInput = child_stdin_rd;
+ info.hStdError = child_stderr_wr;
+ info.hStdOutput = child_stdout_wr;
+ info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ info.wShowWindow = SW_HIDE;
+
+ if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
+ {
+ ws_pipe->stdin_fd = _open_osfhandle((intptr_t)(child_stdin_wr), _O_BINARY);
+ ws_pipe->stdout_fd = _open_osfhandle((intptr_t)(child_stdout_rd), _O_BINARY);
+ ws_pipe->stderr_fd = _open_osfhandle((intptr_t)(child_stderr_rd), _O_BINARY);
+ ws_pipe->threadId = processInfo.hThread;
+ pid = processInfo.hProcess;
+ }
+
+ g_setenv("PATH", oldpath, TRUE);
+#else
+ g_spawn_async_with_pipes(NULL, (gchar **)args->pdata, NULL,
+ (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
+ &pid, &ws_pipe->stdin_fd, &ws_pipe->stdout_fd, &ws_pipe->stderr_fd, NULL);
+#endif
+
+ ws_pipe->pid = pid;
+
+ return pid;
+}
+
+#ifdef _WIN32
+
+typedef struct
+{
+ HANDLE pipeHandle;
+ OVERLAPPED ol;
+ BOOL pendingIO;
+} PIPEINTS;
+
+gboolean
+ws_pipe_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
+{
+ PIPEINTS pipeinsts[3];
+ DWORD dw, cbRet;
+ HANDLE handles[4];
+ int error_code;
+ int num_waiting_to_connect = 0;
+ int num_handles = num_pipe_handles + 1; // PID handle is also added to list of handles.
+
+ if (num_pipe_handles == 0 || num_pipe_handles > 3)
+ {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Invalid number of pipes given as argument.");
+ return FALSE;
+ }
+
+ for (int i = 0; i < num_pipe_handles; ++i)
+ {
+ pipeinsts[i].pipeHandle = pipe_handles[i];
+ pipeinsts[i].ol.Pointer = 0;
+ pipeinsts[i].ol.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ pipeinsts[i].pendingIO = FALSE;
+ handles[i] = pipeinsts[i].ol.hEvent;
+ BOOL connected = ConnectNamedPipe(pipeinsts[i].pipeHandle, &pipeinsts[i].ol);
+ if (connected)
+ {
+ error_code = GetLastError();
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
+ return FALSE;
+ }
+
+ switch (GetLastError())
+ {
+ case ERROR_IO_PENDING:
+ num_waiting_to_connect++;
+ pipeinsts[i].pendingIO = TRUE;
+ break;
+
+ case ERROR_PIPE_CONNECTED:
+ if (SetEvent(pipeinsts[i].ol.hEvent))
+ {
+ break;
+ } // Fallthrough if this fails.
+
+ default:
+ error_code = GetLastError();
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
+ return FALSE;
+ }
+ }
+
+ // Store pid of extcap process so it can be monitored in case it fails before the pipes has connceted.
+ handles[num_pipe_handles] = pid;
+
+ while(num_waiting_to_connect > 0)
+ {
+ dw = WaitForMultipleObjects(num_handles, handles, FALSE, 30000);
+ int idx = dw - WAIT_OBJECT_0;
+ if (dw == WAIT_TIMEOUT)
+ {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds.");
+ return FALSE;
+ }
+ // If index points to our handles array
+ else if (idx >= 0 && idx < num_handles)
+ {
+ if (idx < num_pipe_handles) // Index of pipe handle
+ {
+ if (pipeinsts[idx].pendingIO)
+ {
+ BOOL success = GetOverlappedResult(
+ pipeinsts[idx].pipeHandle, // handle to pipe
+ &pipeinsts[idx].ol, // OVERLAPPED structure
+ &cbRet, // bytes transferred
+ FALSE); // do not wait
+
+ if (!success)
+ {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Error %d \n.", GetLastError());
+ return FALSE;
+ }
+ else
+ {
+ pipeinsts[idx].pendingIO = FALSE;
+ CloseHandle(pipeinsts[idx].ol.hEvent);
+ num_waiting_to_connect--;
+ }
+ }
+ }
+ else // Index of PID
+ {
+ // Fail since index of 'pid' indicates that the pid of the extcap process has terminated.
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe.");
+ return FALSE;
+ }
+ }
+ else
+ {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+#endif
+
gboolean
ws_pipe_data_available(int pipe_fd)
{
diff --git a/wsutil/ws_pipe.h b/wsutil/ws_pipe.h
index 8a4870f2cc..e69873c449 100644
--- a/wsutil/ws_pipe.h
+++ b/wsutil/ws_pipe.h
@@ -17,6 +17,12 @@
#include <glib.h>
#ifdef _WIN32
+#define INVALID_EXTCAP_PID INVALID_HANDLE_VALUE
+#else
+#define INVALID_EXTCAP_PID (GPid)-1
+#endif
+
+#ifdef _WIN32
#include <windows.h>
#include <io.h>
#define ws_pipe_handle HANDLE
@@ -26,6 +32,26 @@
#define ws_get_pipe_handle(pipe_fd) (pipe_fd)
#endif
+typedef struct _ws_pipe_t {
+ GPid pid;
+ gchar *stderr_msg;
+ gint exitcode;
+ gint stdin_fd;
+ gint stdout_fd;
+ gint stderr_fd;
+#ifdef _WIN32
+ HANDLE threadId;
+#endif
+} ws_pipe_t;
+
+WS_DLL_PUBLIC gboolean ws_pipe_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar ** argv, gchar ** command_output );
+
+WS_DLL_PUBLIC GPid ws_pipe_spawn_async (ws_pipe_t * ws_pipe, GPtrArray * args );
+
+#ifdef _WIN32
+WS_DLL_PUBLIC gboolean ws_pipe_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid);
+#endif
+
WS_DLL_PUBLIC gboolean ws_pipe_data_available(int pipe_fd);
WS_DLL_PUBLIC gboolean ws_read_string_from_pipe(ws_pipe_handle read_pipe,