forked from osmocom/wireshark
extcap: Interface Toolbar support on Windows
Add support for extcap control pipes on Windows. Improved read loop in InterfaceToolbarReader. Delay opening control pipes until extcap has opened the fifo pipe. Make extcap_example.py work on Windows. Bug: 13833 Change-Id: I4b47d25452637759b8a3be53be48eee5365bc0e4 Reviewed-on: https://code.wireshark.org/review/23211 Petri-Dish: Stig Bjørlykke <stig@bjorlykke.org> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
7aeff4fb90
commit
018f6bff18
|
@ -3955,6 +3955,7 @@ James Lynch <lynch007[AT]gmail.com>
|
||||||
Chidambaram Arunachalam <carunach[AT]cisco.com>
|
Chidambaram Arunachalam <carunach[AT]cisco.com>
|
||||||
João Valverde <joao.valverde[AT]tecnico.ulisboa.pt>
|
João Valverde <joao.valverde[AT]tecnico.ulisboa.pt>
|
||||||
Benoît Canet <benoit[AT]scylladb.com>
|
Benoît Canet <benoit[AT]scylladb.com>
|
||||||
|
Håkon Øye Amundsen <haakon.amundsen[AT]nordicsemi.no>
|
||||||
|
|
||||||
Acknowledgements
|
Acknowledgements
|
||||||
------------
|
------------
|
||||||
|
|
|
@ -70,6 +70,8 @@ capture_opts_init(capture_options *capture_opts)
|
||||||
capture_opts->default_options.extcap_pid = INVALID_EXTCAP_PID;
|
capture_opts->default_options.extcap_pid = INVALID_EXTCAP_PID;
|
||||||
#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_out_h = INVALID_HANDLE_VALUE;
|
||||||
#endif
|
#endif
|
||||||
capture_opts->default_options.extcap_control_in = NULL;
|
capture_opts->default_options.extcap_control_in = NULL;
|
||||||
capture_opts->default_options.extcap_control_out = NULL;
|
capture_opts->default_options.extcap_control_out = NULL;
|
||||||
|
@ -718,6 +720,8 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str
|
||||||
interface_opts.extcap_userdata = NULL;
|
interface_opts.extcap_userdata = NULL;
|
||||||
#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_out_h = INVALID_HANDLE_VALUE;
|
||||||
#endif
|
#endif
|
||||||
interface_opts.extcap_control_in = g_strdup(capture_opts->default_options.extcap_control_in);
|
interface_opts.extcap_control_in = g_strdup(capture_opts->default_options.extcap_control_in);
|
||||||
interface_opts.extcap_control_out = g_strdup(capture_opts->default_options.extcap_control_out);
|
interface_opts.extcap_control_out = g_strdup(capture_opts->default_options.extcap_control_out);
|
||||||
|
@ -1234,6 +1238,8 @@ collect_ifaces(capture_options *capture_opts)
|
||||||
interface_opts.extcap_userdata = NULL;
|
interface_opts.extcap_userdata = NULL;
|
||||||
#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_out_h = INVALID_HANDLE_VALUE;
|
||||||
#endif
|
#endif
|
||||||
interface_opts.extcap_control_in = NULL;
|
interface_opts.extcap_control_in = NULL;
|
||||||
interface_opts.extcap_control_out = NULL;
|
interface_opts.extcap_control_out = NULL;
|
||||||
|
|
|
@ -238,6 +238,8 @@ typedef struct interface_options_tag {
|
||||||
guint extcap_child_watch;
|
guint extcap_child_watch;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE extcap_pipe_h;
|
HANDLE extcap_pipe_h;
|
||||||
|
HANDLE extcap_control_in_h;
|
||||||
|
HANDLE extcap_control_out_h;
|
||||||
#endif
|
#endif
|
||||||
gchar *extcap_control_in;
|
gchar *extcap_control_in;
|
||||||
gchar *extcap_control_out;
|
gchar *extcap_control_out;
|
||||||
|
|
|
@ -356,7 +356,7 @@ Control packet:
|
||||||
The common sync pipe indication. This protocol uses the value 'T'.
|
The common sync pipe indication. This protocol uses the value 'T'.
|
||||||
|
|
||||||
Message Length:
|
Message Length:
|
||||||
Payload length + 2 bytes for argument number and command.
|
Payload length + 2 bytes for control number and command.
|
||||||
|
|
||||||
Control Number:
|
Control Number:
|
||||||
Unique number to identify the control. This number also gives the order of
|
Unique number to identify the control. This number also gives the order of
|
||||||
|
|
|
@ -340,29 +340,23 @@ def extcap_capture(interface, fifo, control_in, control_out, in_delay, in_verify
|
||||||
message = in_message
|
message = in_message
|
||||||
verify = in_verify
|
verify = in_verify
|
||||||
counter = 1
|
counter = 1
|
||||||
|
|
||||||
if not os.path.exists(fifo):
|
|
||||||
print ( "Fifo does not exist, exiting!", file=sys.stderr )
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
fn_out = None
|
fn_out = None
|
||||||
if control_out != None:
|
|
||||||
fn_out = open(control_out, 'wb', 0)
|
|
||||||
control_write(fn_out, CTRL_ARG_LOGGER, CTRL_CMD_SET, "Log started at " + time.strftime("%c") + "\n")
|
|
||||||
|
|
||||||
|
|
||||||
if control_in != None:
|
|
||||||
# Start reading thread
|
|
||||||
thread = Thread(target = control_read_thread, args = (control_in, fn_out))
|
|
||||||
thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
if fn_out != None:
|
|
||||||
control_write_defaults(fn_out)
|
|
||||||
|
|
||||||
with open(fifo, 'wb', 0 ) as fh:
|
with open(fifo, 'wb', 0 ) as fh:
|
||||||
fh.write (pcap_fake_header())
|
fh.write (pcap_fake_header())
|
||||||
|
|
||||||
|
if control_out != None:
|
||||||
|
fn_out = open(control_out, 'wb', 0)
|
||||||
|
control_write(fn_out, CTRL_ARG_LOGGER, CTRL_CMD_SET, "Log started at " + time.strftime("%c") + "\n")
|
||||||
|
|
||||||
|
if control_in != None:
|
||||||
|
# Start reading thread
|
||||||
|
thread = Thread(target = control_read_thread, args = (control_in, fn_out))
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
if fn_out != None:
|
||||||
|
control_write_defaults(fn_out)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if fn_out != None:
|
if fn_out != None:
|
||||||
log = "Received packet #" + str(counter) + "\n"
|
log = "Received packet #" + str(counter) + "\n"
|
||||||
|
@ -383,10 +377,6 @@ def extcap_capture(interface, fifo, control_in, control_out, in_delay, in_verify
|
||||||
fn_out.close()
|
fn_out.close()
|
||||||
|
|
||||||
def extcap_close_fifo(fifo):
|
def extcap_close_fifo(fifo):
|
||||||
if not os.path.exists(fifo):
|
|
||||||
print ( "Fifo does not exist!", file=sys.stderr )
|
|
||||||
return
|
|
||||||
|
|
||||||
# This is apparently needed to workaround an issue on Windows/macOS
|
# This is apparently needed to workaround an issue on Windows/macOS
|
||||||
# where the message cannot be read. (really?)
|
# where the message cannot be read. (really?)
|
||||||
fh = open(fifo, 'wb', 0 )
|
fh = open(fifo, 'wb', 0 )
|
||||||
|
|
55
extcap.c
55
extcap.c
|
@ -1041,6 +1041,24 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
|
||||||
CloseHandle(interface_opts.extcap_pipe_h);
|
CloseHandle(interface_opts.extcap_pipe_h);
|
||||||
interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE;
|
interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
if (interface_opts.extcap_control_in_h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
||||||
|
"Extcap [%s] - Closing control_in pipe", interface_opts.name);
|
||||||
|
FlushFileBuffers(interface_opts.extcap_control_in_h);
|
||||||
|
DisconnectNamedPipe(interface_opts.extcap_control_in_h);
|
||||||
|
CloseHandle(interface_opts.extcap_control_in_h);
|
||||||
|
interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
if (interface_opts.extcap_control_out_h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
||||||
|
"Extcap [%s] - Closing control_out pipe", interface_opts.name);
|
||||||
|
FlushFileBuffers(interface_opts.extcap_control_out_h);
|
||||||
|
DisconnectNamedPipe(interface_opts.extcap_control_out_h);
|
||||||
|
CloseHandle(interface_opts.extcap_control_out_h);
|
||||||
|
interface_opts.extcap_control_out_h = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (interface_opts.extcap_fifo != NULL && file_exists(interface_opts.extcap_fifo))
|
if (interface_opts.extcap_fifo != NULL && file_exists(interface_opts.extcap_fifo))
|
||||||
{
|
{
|
||||||
|
@ -1355,14 +1373,20 @@ extcap_init_interfaces(capture_options *capture_opts)
|
||||||
if (extcap_has_toolbar(interface_opts.name))
|
if (extcap_has_toolbar(interface_opts.name))
|
||||||
{
|
{
|
||||||
extcap_create_pipe(interface_opts.name, &interface_opts.extcap_control_in,
|
extcap_create_pipe(interface_opts.name, &interface_opts.extcap_control_in,
|
||||||
EXTCAP_CONTROL_IN_PREFIX);
|
EXTCAP_CONTROL_IN_PREFIX, FALSE);
|
||||||
|
#ifdef _WIN32
|
||||||
|
interface_opts.extcap_control_in_h = pipe_h;
|
||||||
|
#endif
|
||||||
extcap_create_pipe(interface_opts.name, &interface_opts.extcap_control_out,
|
extcap_create_pipe(interface_opts.name, &interface_opts.extcap_control_out,
|
||||||
EXTCAP_CONTROL_OUT_PREFIX);
|
EXTCAP_CONTROL_OUT_PREFIX, FALSE);
|
||||||
|
#ifdef _WIN32
|
||||||
|
interface_opts.extcap_control_out_h = pipe_h;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create pipe for fifo */
|
/* create pipe for fifo */
|
||||||
if (!extcap_create_pipe(interface_opts.name, &interface_opts.extcap_fifo,
|
if (!extcap_create_pipe(interface_opts.name, &interface_opts.extcap_fifo,
|
||||||
EXTCAP_PIPE_PREFIX))
|
EXTCAP_PIPE_PREFIX, TRUE))
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1403,7 +1427,18 @@ extcap_init_interfaces(capture_options *capture_opts)
|
||||||
*/
|
*/
|
||||||
if (pid != INVALID_EXTCAP_PID)
|
if (pid != INVALID_EXTCAP_PID)
|
||||||
{
|
{
|
||||||
extcap_wait_for_pipe(interface_opts.extcap_pipe_h, pid);
|
HANDLE pipe_handles[3];
|
||||||
|
int num_pipe_handles = 1;
|
||||||
|
pipe_handles[0] = interface_opts.extcap_pipe_h;
|
||||||
|
|
||||||
|
if (extcap_has_toolbar(interface_opts.name))
|
||||||
|
{
|
||||||
|
pipe_handles[1] = interface_opts.extcap_control_in_h;
|
||||||
|
pipe_handles[2] = interface_opts.extcap_control_out_h;
|
||||||
|
num_pipe_handles += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
extcap_wait_for_pipe(pipe_handles, num_pipe_handles, pid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1416,15 +1451,14 @@ extcap_init_interfaces(capture_options *capture_opts)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe_prefix)
|
gboolean extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe_prefix, gboolean byte_mode _U_)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
gchar timestr[ 14 + 1 ];
|
gchar timestr[ 14 + 1 ];
|
||||||
time_t current_time;
|
time_t current_time;
|
||||||
|
|
||||||
gchar *pipename = NULL;
|
gchar *pipename = NULL;
|
||||||
|
|
||||||
SECURITY_ATTRIBUTES security;
|
SECURITY_ATTRIBUTES security;
|
||||||
|
|
||||||
/* create pipename */
|
/* create pipename */
|
||||||
current_time = time(NULL);
|
current_time = time(NULL);
|
||||||
/*
|
/*
|
||||||
|
@ -1440,18 +1474,19 @@ gboolean extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe
|
||||||
security.bInheritHandle = TRUE;
|
security.bInheritHandle = TRUE;
|
||||||
security.lpSecurityDescriptor = NULL;
|
security.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
/* create a namedPipe*/
|
/* create a namedPipe */
|
||||||
pipe_h = CreateNamedPipe(
|
pipe_h = CreateNamedPipe(
|
||||||
utf_8to16(pipename),
|
utf_8to16(pipename),
|
||||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
byte_mode ? PIPE_TYPE_BYTE : PIPE_TYPE_MESSAGE | byte_mode ? PIPE_READMODE_BYTE : PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
||||||
5, 65536, 65536,
|
1, 65536, 65536,
|
||||||
300,
|
300,
|
||||||
&security);
|
&security);
|
||||||
|
|
||||||
if (pipe_h == INVALID_HANDLE_VALUE)
|
if (pipe_h == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nError creating pipe => (%d)", GetLastError());
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nError creating pipe => (%d)", GetLastError());
|
||||||
|
g_free (pipename);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
8
extcap.h
8
extcap.h
|
@ -40,8 +40,8 @@
|
||||||
|
|
||||||
/* Prefix for the pipe interfaces */
|
/* Prefix for the pipe interfaces */
|
||||||
#define EXTCAP_PIPE_PREFIX "wireshark_extcap"
|
#define EXTCAP_PIPE_PREFIX "wireshark_extcap"
|
||||||
#define EXTCAP_CONTROL_IN_PREFIX "wireshark_control_in"
|
#define EXTCAP_CONTROL_IN_PREFIX "wireshark_control_ext_to_ws"
|
||||||
#define EXTCAP_CONTROL_OUT_PREFIX "wireshark_control_out"
|
#define EXTCAP_CONTROL_OUT_PREFIX "wireshark_control_ws_to_ext"
|
||||||
|
|
||||||
#define EXTCAP_ARGUMENT_CONFIG "--extcap-config"
|
#define EXTCAP_ARGUMENT_CONFIG "--extcap-config"
|
||||||
#define EXTCAP_ARGUMENT_LIST_INTERFACES "--extcap-interfaces"
|
#define EXTCAP_ARGUMENT_LIST_INTERFACES "--extcap-interfaces"
|
||||||
|
@ -143,11 +143,11 @@ gboolean
|
||||||
extcap_init_interfaces(capture_options * capture_opts);
|
extcap_init_interfaces(capture_options * capture_opts);
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe_prefix);
|
extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe_prefix, gboolean byte_mode);
|
||||||
|
|
||||||
/* Clean up all if related stuff */
|
/* Clean up all if related stuff */
|
||||||
void
|
void
|
||||||
extcap_if_cleanup(capture_options * capture_opts _U_, gchar ** errormsg);
|
extcap_if_cleanup(capture_options * capture_opts, gchar ** errormsg);
|
||||||
|
|
||||||
struct preference *
|
struct preference *
|
||||||
extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg * arg);
|
extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg * arg);
|
||||||
|
|
132
extcap_spawn.c
132
extcap_spawn.c
|
@ -287,67 +287,117 @@ GPid extcap_spawn_async(extcap_userdata *userdata, GPtrArray *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
gboolean
|
|
||||||
extcap_wait_for_pipe(HANDLE pipe_h, HANDLE pid)
|
typedef struct
|
||||||
{
|
{
|
||||||
DWORD dw;
|
HANDLE pipeHandle;
|
||||||
HANDLE handles[2];
|
OVERLAPPED ol;
|
||||||
OVERLAPPED ov;
|
BOOL pendingIO;
|
||||||
gboolean success = FALSE;
|
} PIPEINTS;
|
||||||
ov.Pointer = 0;
|
|
||||||
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
|
|
||||||
ConnectNamedPipe(pipe_h, &ov);
|
gboolean
|
||||||
handles[0] = ov.hEvent;
|
extcap_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
|
||||||
handles[1] = 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 (GetLastError() == ERROR_PIPE_CONNECTED)
|
if (num_pipe_handles == 0 || num_pipe_handles > 3)
|
||||||
{
|
{
|
||||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap connected to pipe");
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Invalid number of pipes given as argument.");
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
for (int i = 0; i < num_pipe_handles; ++i)
|
||||||
{
|
{
|
||||||
dw = WaitForMultipleObjects(2, handles, FALSE, 30000);
|
pipeinsts[i].pipeHandle = pipe_handles[i];
|
||||||
if (dw == WAIT_OBJECT_0)
|
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)
|
||||||
{
|
{
|
||||||
/* ConnectNamedPipe finished. */
|
error_code = GetLastError();
|
||||||
DWORD code;
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
code = GetLastError();
|
switch (GetLastError())
|
||||||
if (code == ERROR_IO_PENDING)
|
{
|
||||||
|
case ERROR_IO_PENDING:
|
||||||
|
num_waiting_to_connect++;
|
||||||
|
pipeinsts[i].pendingIO = TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_PIPE_CONNECTED:
|
||||||
|
if (SetEvent(pipeinsts[i].ol.hEvent))
|
||||||
{
|
{
|
||||||
DWORD dummy;
|
break;
|
||||||
if (!GetOverlappedResult(ov.hEvent, &ov, &dummy, TRUE))
|
} // Fallthrough if this fails.
|
||||||
{
|
|
||||||
code = GetLastError();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
code = ERROR_SUCCESS;
|
|
||||||
success = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe code: %d", code);
|
default:
|
||||||
|
error_code = GetLastError();
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
else if (dw == (WAIT_OBJECT_0 + 1))
|
}
|
||||||
{
|
|
||||||
/* extcap process terminated. */
|
// Store pid of extcap process so it can be monitored in case it fails before the pipes has connceted.
|
||||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe.");
|
handles[num_pipe_handles] = pid;
|
||||||
}
|
|
||||||
else if (dw == WAIT_TIMEOUT)
|
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.");
|
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;
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(ov.hEvent);
|
return TRUE;
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ gboolean extcap_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar
|
||||||
GPid extcap_spawn_async ( extcap_userdata * userdata, GPtrArray * args );
|
GPid extcap_spawn_async ( extcap_userdata * userdata, GPtrArray * args );
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
gboolean extcap_wait_for_pipe(HANDLE pipe_h, HANDLE pid);
|
gboolean extcap_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid);
|
||||||
void win32_readfrompipe(HANDLE read_pipe, gint32 max_buffer, gchar * buffer);
|
void win32_readfrompipe(HANDLE read_pipe, gint32 max_buffer, gchar * buffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -710,7 +710,8 @@ void InterfaceToolbar::closeLog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfaceToolbar::startReaderThread(QString ifname, QString control_in)
|
|
||||||
|
void InterfaceToolbar::startReaderThread(QString ifname, void *control_in)
|
||||||
{
|
{
|
||||||
QThread *thread = new QThread;
|
QThread *thread = new QThread;
|
||||||
InterfaceToolbarReader *reader = new InterfaceToolbarReader(ifname, control_in);
|
InterfaceToolbarReader *reader = new InterfaceToolbarReader(ifname, control_in);
|
||||||
|
@ -757,12 +758,14 @@ void InterfaceToolbar::startCapture(GArray *ifaces)
|
||||||
// Already have control channels for this interface
|
// Already have control channels for this interface
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// The reader thread will open control in channel
|
|
||||||
startReaderThread(ifname, interface_opts.extcap_control_in);
|
|
||||||
|
|
||||||
// Open control out channel
|
// Open control out channel
|
||||||
|
#ifdef _WIN32
|
||||||
|
startReaderThread(ifname, interface_opts.extcap_control_in_h);
|
||||||
|
interface_[ifname].out_fd = _open_osfhandle((intptr_t)interface_opts.extcap_control_out_h, O_APPEND | O_BINARY);
|
||||||
|
#else
|
||||||
|
startReaderThread(ifname, interface_opts.extcap_control_in);
|
||||||
interface_[ifname].out_fd = ws_open(interface_opts.extcap_control_out, O_WRONLY | O_BINARY, 0);
|
interface_[ifname].out_fd = ws_open(interface_opts.extcap_control_out, O_WRONLY | O_BINARY, 0);
|
||||||
|
#endif
|
||||||
sendChangedValues(ifname);
|
sendChangedValues(ifname);
|
||||||
controlSend(ifname, 0, commandControlInitialized);
|
controlSend(ifname, 0, commandControlInitialized);
|
||||||
}
|
}
|
||||||
|
@ -800,7 +803,9 @@ void InterfaceToolbar::stopCapture()
|
||||||
|
|
||||||
if (interface_[ifname].out_fd != -1)
|
if (interface_[ifname].out_fd != -1)
|
||||||
{
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
ws_close (interface_[ifname].out_fd);
|
ws_close (interface_[ifname].out_fd);
|
||||||
|
#endif
|
||||||
interface_[ifname].out_fd = -1;
|
interface_[ifname].out_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ signals:
|
||||||
void closeReader();
|
void closeReader();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void startReaderThread(QString ifname, QString control_in);
|
void startReaderThread(QString ifname, void *control_in);
|
||||||
void updateWidgets();
|
void updateWidgets();
|
||||||
|
|
||||||
void onControlButtonPressed();
|
void onControlButtonPressed();
|
||||||
|
|
|
@ -39,37 +39,125 @@
|
||||||
|
|
||||||
const int header_size = 6;
|
const int header_size = 6;
|
||||||
|
|
||||||
// To do:
|
#ifdef _WIN32
|
||||||
// - Add support for WIN32
|
int InterfaceToolbarReader::async_pipe_read(void *data, int nbyte)
|
||||||
|
{
|
||||||
|
BOOL success;
|
||||||
|
DWORD nof_bytes_read, last_err;
|
||||||
|
OVERLAPPED overlap;
|
||||||
|
|
||||||
|
overlap.Pointer = 0;
|
||||||
|
overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (overlap.hEvent == NULL)
|
||||||
|
{
|
||||||
|
// CreateEvent failed with error code GetLastError()
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
success = ReadFile(control_in_, data, nbyte, &nof_bytes_read, &overlap);
|
||||||
|
|
||||||
|
if (success && nof_bytes_read != 0)
|
||||||
|
{
|
||||||
|
// The read operation completed successfully.
|
||||||
|
return nof_bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_err = GetLastError();
|
||||||
|
|
||||||
|
if (!success && last_err == ERROR_IO_PENDING)
|
||||||
|
{
|
||||||
|
// The operation is still pending, wait for a signal.
|
||||||
|
DWORD wait = WaitForMultipleObjects(1, &overlap.hEvent, TRUE, INFINITE);
|
||||||
|
|
||||||
|
if (wait - WAIT_OBJECT_0 == 0)
|
||||||
|
{
|
||||||
|
// The wait operation has completed.
|
||||||
|
success = GetOverlappedResult(control_in_, &overlap, &nof_bytes_read, FALSE);
|
||||||
|
|
||||||
|
if (success && nof_bytes_read != 0)
|
||||||
|
{
|
||||||
|
// The get result operation completed successfully.
|
||||||
|
return nof_bytes_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pipe is closed or an unknown error occured.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int InterfaceToolbarReader::pipe_read(char *data, int nbyte)
|
||||||
|
{
|
||||||
|
int total_len = 0;
|
||||||
|
|
||||||
|
while (total_len < nbyte)
|
||||||
|
{
|
||||||
|
char *data_ptr = data + total_len;
|
||||||
|
int data_len = nbyte - total_len;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
int read_len = async_pipe_read(data_ptr, data_len);
|
||||||
|
#else
|
||||||
|
int read_len = (int)ws_read(fd_in_, data_ptr, data_len);
|
||||||
|
#endif
|
||||||
|
if (read_len == -1)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
total_len += read_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
|
||||||
|
if (QThread::currentThread()->isInterruptionRequested())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_len;
|
||||||
|
}
|
||||||
|
|
||||||
void InterfaceToolbarReader::loop()
|
void InterfaceToolbarReader::loop()
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
|
||||||
struct timeval timeout;
|
|
||||||
QByteArray header;
|
QByteArray header;
|
||||||
QByteArray payload;
|
QByteArray payload;
|
||||||
fd_set readfds;
|
|
||||||
|
|
||||||
int fd = ws_open(control_in_.toUtf8(), O_RDONLY | O_BINARY | O_NONBLOCK, 0);
|
#ifndef _WIN32
|
||||||
if (fd == -1)
|
struct timeval timeout;
|
||||||
|
fd_set readfds;
|
||||||
|
fd_in_ = ws_open(control_in_.toUtf8(), O_RDONLY | O_BINARY | O_NONBLOCK, 0);
|
||||||
|
|
||||||
|
if (fd_in_ == -1)
|
||||||
{
|
{
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
header.resize(header_size);
|
||||||
|
|
||||||
forever
|
forever
|
||||||
{
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
FD_SET(fd, &readfds);
|
FD_SET(fd_in_, &readfds);
|
||||||
|
|
||||||
timeout.tv_sec = 2;
|
timeout.tv_sec = 2;
|
||||||
timeout.tv_usec = 0;
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
int ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
|
int ret = select(fd_in_ + 1, &readfds, NULL, NULL, &timeout);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
|
||||||
if (QThread::currentThread()->isInterruptionRequested())
|
if (QThread::currentThread()->isInterruptionRequested())
|
||||||
{
|
{
|
||||||
|
@ -77,52 +165,40 @@ void InterfaceToolbarReader::loop()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ret > 0 && FD_ISSET(fd, &readfds))
|
if (ret == 0 || !FD_ISSET(fd_in_, &readfds))
|
||||||
{
|
{
|
||||||
header.resize(header_size);
|
continue;
|
||||||
if (ws_read(fd, header.data(), header_size) != header_size)
|
}
|
||||||
{
|
#endif
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char high_nibble = header[1] & 0xFF;
|
// Read the header from the pipe.
|
||||||
unsigned char mid_nibble = header[2] & 0xFF;
|
if (pipe_read(header.data(), header_size) != header_size)
|
||||||
unsigned char low_nibble = header[3] & 0xFF;
|
{
|
||||||
ssize_t payload_len = (ssize_t)((high_nibble << 16) + (mid_nibble << 8) + low_nibble) - 2;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
payload.resize((int)payload_len);
|
unsigned char high_nibble = header[1] & 0xFF;
|
||||||
if (payload_len > 0)
|
unsigned char mid_nibble = header[2] & 0xFF;
|
||||||
{
|
unsigned char low_nibble = header[3] & 0xFF;
|
||||||
ssize_t total_len = 0;
|
int payload_len = (int)((high_nibble << 16) + (mid_nibble << 8) + low_nibble) - 2;
|
||||||
while (total_len < payload_len)
|
|
||||||
{
|
payload.resize(payload_len);
|
||||||
ssize_t read_len = ws_read(fd, payload.data() + total_len, payload_len - total_len);
|
// Read the payload from the pipe.
|
||||||
if (read_len == -1)
|
if (pipe_read(payload.data(), payload_len) != payload_len)
|
||||||
{
|
{
|
||||||
if (errno != EAGAIN)
|
break;
|
||||||
{
|
}
|
||||||
break;
|
|
||||||
}
|
if (header[0] == SP_TOOLBAR_CTRL)
|
||||||
}
|
{
|
||||||
else
|
emit received(ifname_, (unsigned char)header[4], (unsigned char)header[5], payload);
|
||||||
{
|
|
||||||
total_len += read_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (total_len != payload_len)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (header[0] == SP_TOOLBAR_CTRL)
|
|
||||||
{
|
|
||||||
emit received(ifname_, (unsigned char)header[4], (unsigned char)header[5], payload);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_close(fd);
|
#ifndef _WIN32
|
||||||
|
ws_close(fd_in_);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
emit finished();
|
emit finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class InterfaceToolbarReader;
|
class InterfaceToolbarReader;
|
||||||
}
|
}
|
||||||
|
@ -34,8 +38,16 @@ class InterfaceToolbarReader : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InterfaceToolbarReader(QString ifname, QString control_in, QObject *parent = 0) :
|
InterfaceToolbarReader(QString ifname, void *control_in, QObject *parent = 0) :
|
||||||
QObject(parent), ifname_(ifname), control_in_(control_in) {}
|
QObject(parent), ifname_(ifname)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
control_in_ = (HANDLE)control_in;
|
||||||
|
#else
|
||||||
|
control_in_ = (char *)control_in;
|
||||||
|
fd_in_ = -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loop();
|
void loop();
|
||||||
|
@ -45,8 +57,18 @@ signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#ifdef _WIN32
|
||||||
|
int async_pipe_read(void *data, int nbyte);
|
||||||
|
#endif
|
||||||
|
int pipe_read(char *data, int nbyte);
|
||||||
|
|
||||||
QString ifname_;
|
QString ifname_;
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE control_in_;
|
||||||
|
#else
|
||||||
QString control_in_;
|
QString control_in_;
|
||||||
|
int fd_in_;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INTERFACE_TOOLBAR_READER_H
|
#endif // INTERFACE_TOOLBAR_READER_H
|
||||||
|
|
|
@ -714,14 +714,12 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
#endif
|
#endif
|
||||||
plugin_if_register_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR, plugin_if_mainwindow_update_toolbars);
|
plugin_if_register_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR, plugin_if_mainwindow_update_toolbars);
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) && !defined(_WIN32)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
|
||||||
// Register Interface Toolbar callbacks
|
// Register Interface Toolbar callbacks
|
||||||
//
|
//
|
||||||
// Qt version must be 5.2 or higher because the use of
|
// Qt version must be 5.2 or higher because the use of
|
||||||
// QThread::requestInterruption() in interface_toolbar.cpp and
|
// QThread::requestInterruption() in interface_toolbar.cpp and
|
||||||
// QThread::isInterruptionRequested() in interface_toolbar_reader.cpp
|
// QThread::isInterruptionRequested() in interface_toolbar_reader.cpp
|
||||||
//
|
|
||||||
// The toolbar in/out control pipes are not supported on WIN32 yet.
|
|
||||||
iface_toolbar_register_cb(mainwindow_add_toolbar, mainwindow_remove_toolbar);
|
iface_toolbar_register_cb(mainwindow_add_toolbar, mainwindow_remove_toolbar);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -657,7 +657,7 @@ void MainWindow::queuedFilterAction(QString action_filter, FilterAction::Action
|
||||||
|
|
||||||
// Capture callbacks
|
// Capture callbacks
|
||||||
|
|
||||||
void MainWindow::captureCapturePrepared(capture_session *session) {
|
void MainWindow::captureCapturePrepared(capture_session *) {
|
||||||
#ifdef HAVE_LIBPCAP
|
#ifdef HAVE_LIBPCAP
|
||||||
setTitlebarForCaptureInProgress();
|
setTitlebarForCaptureInProgress();
|
||||||
|
|
||||||
|
@ -665,7 +665,7 @@ void MainWindow::captureCapturePrepared(capture_session *session) {
|
||||||
|
|
||||||
/* Disable menu items that make no sense if you're currently running
|
/* Disable menu items that make no sense if you're currently running
|
||||||
a capture. */
|
a capture. */
|
||||||
setForCaptureInProgress(true, session->capture_opts->ifaces);
|
setForCaptureInProgress(true);
|
||||||
// set_capture_if_dialog_for_capture_in_progress(TRUE);
|
// set_capture_if_dialog_for_capture_in_progress(TRUE);
|
||||||
|
|
||||||
// /* Don't set up main window for a capture file. */
|
// /* Don't set up main window for a capture file. */
|
||||||
|
|
Loading…
Reference in New Issue