forked from osmocom/wireshark
extcap: Read stdout and stderr during capture
Read extcap stdout/stderr data when available to prevent extcap hang on stdout/stderr write. Discard stdout data as it was not used earlier. Store up to 1024 bytes of stderr and display it to user after capture stops. Fixes #17827
This commit is contained in:
parent
ac4e1b86b8
commit
7316b16e1d
|
@ -182,12 +182,13 @@ void capture_process_finished(capture_session *cap_session)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interface_opts->extcap_stderr != NULL) {
|
if ((interface_opts->extcap_stderr != NULL) &&
|
||||||
|
(interface_opts->extcap_stderr->len > 0)) {
|
||||||
if (message->len > 0) {
|
if (message->len > 0) {
|
||||||
g_string_append(message, "\n");
|
g_string_append(message, "\n");
|
||||||
}
|
}
|
||||||
g_string_append(message, "Error by extcap pipe: ");
|
g_string_append(message, "Error by extcap pipe: ");
|
||||||
g_string_append(message, interface_opts->extcap_stderr);
|
g_string_append(message, interface_opts->extcap_stderr->str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,8 @@ capture_opts_init(capture_options *capture_opts)
|
||||||
capture_opts->default_options.extcap_pipedata = NULL;
|
capture_opts->default_options.extcap_pipedata = NULL;
|
||||||
capture_opts->default_options.extcap_stderr = NULL;
|
capture_opts->default_options.extcap_stderr = NULL;
|
||||||
capture_opts->default_options.extcap_child_watch = 0;
|
capture_opts->default_options.extcap_child_watch = 0;
|
||||||
|
capture_opts->default_options.extcap_stdout_watch = 0;
|
||||||
|
capture_opts->default_options.extcap_stderr_watch = 0;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
capture_opts->default_options.extcap_pipe_h = INVALID_HANDLE_VALUE;
|
capture_opts->default_options.extcap_pipe_h = INVALID_HANDLE_VALUE;
|
||||||
capture_opts->default_options.extcap_control_in_h = INVALID_HANDLE_VALUE;
|
capture_opts->default_options.extcap_control_in_h = INVALID_HANDLE_VALUE;
|
||||||
|
@ -788,6 +790,8 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str
|
||||||
interface_opts.extcap_pipedata = NULL;
|
interface_opts.extcap_pipedata = NULL;
|
||||||
interface_opts.extcap_stderr = NULL;
|
interface_opts.extcap_stderr = NULL;
|
||||||
interface_opts.extcap_child_watch = 0;
|
interface_opts.extcap_child_watch = 0;
|
||||||
|
interface_opts.extcap_stdout_watch = 0;
|
||||||
|
interface_opts.extcap_stderr_watch = 0;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE;
|
interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE;
|
||||||
interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE;
|
interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE;
|
||||||
|
@ -1289,7 +1293,8 @@ capture_opts_del_iface(capture_options *capture_opts, guint if_index)
|
||||||
if (interface_opts->extcap_pid != WS_INVALID_PID)
|
if (interface_opts->extcap_pid != WS_INVALID_PID)
|
||||||
ws_pipe_close((ws_pipe_t *) interface_opts->extcap_pipedata);
|
ws_pipe_close((ws_pipe_t *) interface_opts->extcap_pipedata);
|
||||||
g_free(interface_opts->extcap_pipedata);
|
g_free(interface_opts->extcap_pipedata);
|
||||||
g_free(interface_opts->extcap_stderr);
|
if (interface_opts->extcap_stderr)
|
||||||
|
g_string_free(interface_opts->extcap_stderr, TRUE);
|
||||||
g_free(interface_opts->extcap_control_in);
|
g_free(interface_opts->extcap_control_in);
|
||||||
g_free(interface_opts->extcap_control_out);
|
g_free(interface_opts->extcap_control_out);
|
||||||
#ifdef HAVE_PCAP_REMOTE
|
#ifdef HAVE_PCAP_REMOTE
|
||||||
|
|
|
@ -210,8 +210,10 @@ typedef struct interface_options_tag {
|
||||||
GHashTable *extcap_args;
|
GHashTable *extcap_args;
|
||||||
GPid extcap_pid; /* pid of running process or WS_INVALID_PID */
|
GPid extcap_pid; /* pid of running process or WS_INVALID_PID */
|
||||||
gpointer extcap_pipedata;
|
gpointer extcap_pipedata;
|
||||||
gchar *extcap_stderr;
|
GString *extcap_stderr;
|
||||||
guint extcap_child_watch;
|
guint extcap_child_watch;
|
||||||
|
guint extcap_stdout_watch;
|
||||||
|
guint extcap_stderr_watch;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE extcap_pipe_h;
|
HANDLE extcap_pipe_h;
|
||||||
HANDLE extcap_control_in_h;
|
HANDLE extcap_control_in_h;
|
||||||
|
|
82
extcap.c
82
extcap.c
|
@ -1299,6 +1299,55 @@ extcap_add_arg_and_remove_cb(gpointer key, gpointer value, gpointer data)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
extcap_stdout_cb(GIOChannel *source, GIOCondition condition _U_, gpointer data)
|
||||||
|
{
|
||||||
|
interface_options *interface_opts = (interface_options *)data;
|
||||||
|
char buf[128];
|
||||||
|
gsize bytes_read;
|
||||||
|
|
||||||
|
/* Discard data to prevent child process hanging on stdout write */
|
||||||
|
g_io_channel_read_chars(source, buf, sizeof(buf), &bytes_read, NULL);
|
||||||
|
if (bytes_read == 0)
|
||||||
|
{
|
||||||
|
interface_opts->extcap_stdout_watch = 0;
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
extcap_stderr_cb(GIOChannel *source, GIOCondition condition _U_, gpointer data)
|
||||||
|
{
|
||||||
|
interface_options *interface_opts = (interface_options *)data;
|
||||||
|
char buf[128];
|
||||||
|
gsize bytes_read;
|
||||||
|
|
||||||
|
g_io_channel_read_chars(source, buf, sizeof(buf), &bytes_read, NULL);
|
||||||
|
if (bytes_read == 0)
|
||||||
|
{
|
||||||
|
interface_opts->extcap_stderr_watch = 0;
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STDERR_BUFFER_SIZE 1024
|
||||||
|
if (interface_opts->extcap_stderr == NULL)
|
||||||
|
{
|
||||||
|
interface_opts->extcap_stderr = g_string_new_len(buf, bytes_read);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gssize remaining = STDERR_BUFFER_SIZE - interface_opts->extcap_stderr->len;
|
||||||
|
if (remaining > 0)
|
||||||
|
{
|
||||||
|
gssize bytes = bytes_read;
|
||||||
|
bytes = MIN(bytes, remaining);
|
||||||
|
g_string_append_len(interface_opts->extcap_stderr, buf, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void extcap_child_watch_cb(GPid pid, gint status _U_, gpointer user_data)
|
static void extcap_child_watch_cb(GPid pid, gint status _U_, gpointer user_data)
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
|
@ -1320,23 +1369,30 @@ static void extcap_child_watch_cb(GPid pid, gint status _U_, gpointer user_data)
|
||||||
interface_opts->extcap_pid);
|
interface_opts->extcap_pid);
|
||||||
interface_opts->extcap_pid = WS_INVALID_PID;
|
interface_opts->extcap_pid = WS_INVALID_PID;
|
||||||
|
|
||||||
|
if (interface_opts->extcap_stdout_watch > 0)
|
||||||
|
{
|
||||||
|
g_source_remove(interface_opts->extcap_stdout_watch);
|
||||||
|
interface_opts->extcap_stdout_watch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interface_opts->extcap_stderr_watch > 0)
|
||||||
|
{
|
||||||
|
g_source_remove(interface_opts->extcap_stderr_watch);
|
||||||
|
interface_opts->extcap_stderr_watch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
pipedata = (ws_pipe_t *)interface_opts->extcap_pipedata;
|
pipedata = (ws_pipe_t *)interface_opts->extcap_pipedata;
|
||||||
if (pipedata != NULL)
|
if (pipedata != NULL)
|
||||||
{
|
{
|
||||||
g_io_channel_unref(pipedata->stdout_io);
|
g_io_channel_unref(pipedata->stdout_io);
|
||||||
|
|
||||||
if (pipedata->stderr_io)
|
while (extcap_stderr_cb(pipedata->stderr_io,
|
||||||
|
g_io_channel_get_buffer_condition(pipedata->stderr_io),
|
||||||
|
(gpointer)interface_opts) != G_SOURCE_REMOVE)
|
||||||
{
|
{
|
||||||
#define STDERR_BUFFER_SIZE 1024
|
/* Keep reading until there's nothing left */
|
||||||
gchar *buffer = (gchar *)g_malloc0(STDERR_BUFFER_SIZE + 1);
|
|
||||||
g_io_channel_read_chars(pipedata->stderr_io, buffer, STDERR_BUFFER_SIZE, NULL, NULL);
|
|
||||||
if (strlen(buffer) > 0)
|
|
||||||
{
|
|
||||||
interface_opts->extcap_stderr = g_strdup(buffer);
|
|
||||||
}
|
|
||||||
g_free(buffer);
|
|
||||||
g_io_channel_unref(pipedata->stderr_io);
|
|
||||||
}
|
}
|
||||||
|
g_io_channel_unref(pipedata->stderr_io);
|
||||||
|
|
||||||
g_free(pipedata);
|
g_free(pipedata);
|
||||||
interface_opts->extcap_pipedata = NULL;
|
interface_opts->extcap_pipedata = NULL;
|
||||||
|
@ -1618,6 +1674,12 @@ extcap_init_interfaces(capture_session *cap_session)
|
||||||
interface_opts->extcap_child_watch =
|
interface_opts->extcap_child_watch =
|
||||||
g_child_watch_add_full(G_PRIORITY_HIGH, pid, extcap_child_watch_cb,
|
g_child_watch_add_full(G_PRIORITY_HIGH, pid, extcap_child_watch_cb,
|
||||||
(gpointer)cap_session, NULL);
|
(gpointer)cap_session, NULL);
|
||||||
|
interface_opts->extcap_stdout_watch =
|
||||||
|
g_io_add_watch(pipedata->stdout_io, G_IO_IN | G_IO_HUP,
|
||||||
|
extcap_stdout_cb, (gpointer)interface_opts);
|
||||||
|
interface_opts->extcap_stderr_watch =
|
||||||
|
g_io_add_watch(pipedata->stderr_io, G_IO_IN | G_IO_HUP,
|
||||||
|
extcap_stderr_cb, (gpointer)interface_opts);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* On Windows, wait for extcap to connect to named pipe.
|
/* On Windows, wait for extcap to connect to named pipe.
|
||||||
|
|
Loading…
Reference in New Issue