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>
This commit is contained in:
parent
bf4c2fd82b
commit
1a0987904f
|
@ -1577,7 +1577,6 @@ set(SHARK_COMMON_SRC
|
|||
version_info.c
|
||||
extcap.c
|
||||
extcap_parser.c
|
||||
extcap_spawn.c
|
||||
)
|
||||
|
||||
set(TSHARK_TAP_SRC
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
71
extcap.c
71
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;
|
||||
|
|
381
extcap_spawn.c
381
extcap_spawn.c
|
@ -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:
|
||||
*/
|
|
@ -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:
|
||||
*/
|
352
wsutil/ws_pipe.c
352
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)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,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>
|
||||
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue