From 018f6bff18785a1c3971a1ccfe3b1b5243d4d154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20=C3=98ye=20Amundsen?= Date: Fri, 25 Aug 2017 11:28:34 +0200 Subject: extcap: Interface Toolbar support on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- ui/qt/interface_toolbar.cpp | 15 ++-- ui/qt/interface_toolbar.h | 2 +- ui/qt/interface_toolbar_reader.cpp | 170 +++++++++++++++++++++++++++---------- ui/qt/interface_toolbar_reader.h | 26 +++++- ui/qt/main_window.cpp | 4 +- ui/qt/main_window_slots.cpp | 4 +- 6 files changed, 161 insertions(+), 60 deletions(-) (limited to 'ui') diff --git a/ui/qt/interface_toolbar.cpp b/ui/qt/interface_toolbar.cpp index b28fee9abe..ffddf28f50 100644 --- a/ui/qt/interface_toolbar.cpp +++ b/ui/qt/interface_toolbar.cpp @@ -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; InterfaceToolbarReader *reader = new InterfaceToolbarReader(ifname, control_in); @@ -757,12 +758,14 @@ void InterfaceToolbar::startCapture(GArray *ifaces) // Already have control channels for this interface continue; - // The reader thread will open control in channel - startReaderThread(ifname, interface_opts.extcap_control_in); - // 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); - +#endif sendChangedValues(ifname); controlSend(ifname, 0, commandControlInitialized); } @@ -800,7 +803,9 @@ void InterfaceToolbar::stopCapture() if (interface_[ifname].out_fd != -1) { +#ifndef _WIN32 ws_close (interface_[ifname].out_fd); +#endif interface_[ifname].out_fd = -1; } diff --git a/ui/qt/interface_toolbar.h b/ui/qt/interface_toolbar.h index cdbfb57906..404dc1ccdb 100644 --- a/ui/qt/interface_toolbar.h +++ b/ui/qt/interface_toolbar.h @@ -70,7 +70,7 @@ signals: void closeReader(); private slots: - void startReaderThread(QString ifname, QString control_in); + void startReaderThread(QString ifname, void *control_in); void updateWidgets(); void onControlButtonPressed(); diff --git a/ui/qt/interface_toolbar_reader.cpp b/ui/qt/interface_toolbar_reader.cpp index f4565fe6c3..99b15a47b3 100644 --- a/ui/qt/interface_toolbar_reader.cpp +++ b/ui/qt/interface_toolbar_reader.cpp @@ -39,37 +39,125 @@ const int header_size = 6; -// To do: -// - Add support for WIN32 +#ifdef _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() { -#ifndef _WIN32 - struct timeval timeout; QByteArray header; QByteArray payload; + +#ifndef _WIN32 + struct timeval timeout; fd_set readfds; + fd_in_ = ws_open(control_in_.toUtf8(), O_RDONLY | O_BINARY | O_NONBLOCK, 0); - int fd = ws_open(control_in_.toUtf8(), O_RDONLY | O_BINARY | O_NONBLOCK, 0); - if (fd == -1) + if (fd_in_ == -1) { emit finished(); return; } +#endif + + header.resize(header_size); forever { +#ifndef _WIN32 FD_ZERO(&readfds); - FD_SET(fd, &readfds); + FD_SET(fd_in_, &readfds); timeout.tv_sec = 2; 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) { break; } + #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) if (QThread::currentThread()->isInterruptionRequested()) { @@ -77,52 +165,40 @@ void InterfaceToolbarReader::loop() } #endif - if (ret > 0 && FD_ISSET(fd, &readfds)) + if (ret == 0 || !FD_ISSET(fd_in_, &readfds)) { - header.resize(header_size); - if (ws_read(fd, header.data(), header_size) != header_size) - { - break; - } + continue; + } +#endif - unsigned char high_nibble = header[1] & 0xFF; - unsigned char mid_nibble = header[2] & 0xFF; - unsigned char low_nibble = header[3] & 0xFF; - ssize_t payload_len = (ssize_t)((high_nibble << 16) + (mid_nibble << 8) + low_nibble) - 2; + // Read the header from the pipe. + if (pipe_read(header.data(), header_size) != header_size) + { + break; + } - payload.resize((int)payload_len); - if (payload_len > 0) - { - ssize_t total_len = 0; - while (total_len < payload_len) - { - ssize_t read_len = ws_read(fd, payload.data() + total_len, payload_len - total_len); - if (read_len == -1) - { - if (errno != EAGAIN) - { - break; - } - } - else - { - 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); - } + unsigned char high_nibble = header[1] & 0xFF; + unsigned char mid_nibble = header[2] & 0xFF; + unsigned char low_nibble = header[3] & 0xFF; + int payload_len = (int)((high_nibble << 16) + (mid_nibble << 8) + low_nibble) - 2; + + payload.resize(payload_len); + // Read the payload from the pipe. + if (pipe_read(payload.data(), payload_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 + emit finished(); } diff --git a/ui/qt/interface_toolbar_reader.h b/ui/qt/interface_toolbar_reader.h index 1b34db4fb0..75fc7cbea9 100644 --- a/ui/qt/interface_toolbar_reader.h +++ b/ui/qt/interface_toolbar_reader.h @@ -25,6 +25,10 @@ #include #include +#ifdef _WIN32 +#include +#endif + namespace Ui { class InterfaceToolbarReader; } @@ -34,8 +38,16 @@ class InterfaceToolbarReader : public QObject Q_OBJECT public: - InterfaceToolbarReader(QString ifname, QString control_in, QObject *parent = 0) : - QObject(parent), ifname_(ifname), control_in_(control_in) {} + InterfaceToolbarReader(QString ifname, void *control_in, QObject *parent = 0) : + QObject(parent), ifname_(ifname) + { +#ifdef _WIN32 + control_in_ = (HANDLE)control_in; +#else + control_in_ = (char *)control_in; + fd_in_ = -1; +#endif + } public slots: void loop(); @@ -45,8 +57,18 @@ signals: void finished(); private: +#ifdef _WIN32 + int async_pipe_read(void *data, int nbyte); +#endif + int pipe_read(char *data, int nbyte); + QString ifname_; +#ifdef _WIN32 + HANDLE control_in_; +#else QString control_in_; + int fd_in_; +#endif }; #endif // INTERFACE_TOOLBAR_READER_H diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 653ff4cf4f..cd5a2ca53e 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -714,14 +714,12 @@ MainWindow::MainWindow(QWidget *parent) : #endif 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 // // Qt version must be 5.2 or higher because the use of // QThread::requestInterruption() in interface_toolbar.cpp and // 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); #endif diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp index 0c6dcbf710..c6d30c9a6a 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/main_window_slots.cpp @@ -657,7 +657,7 @@ void MainWindow::queuedFilterAction(QString action_filter, FilterAction::Action // Capture callbacks -void MainWindow::captureCapturePrepared(capture_session *session) { +void MainWindow::captureCapturePrepared(capture_session *) { #ifdef HAVE_LIBPCAP setTitlebarForCaptureInProgress(); @@ -665,7 +665,7 @@ void MainWindow::captureCapturePrepared(capture_session *session) { /* Disable menu items that make no sense if you're currently running a capture. */ - setForCaptureInProgress(true, session->capture_opts->ifaces); + setForCaptureInProgress(true); // set_capture_if_dialog_for_capture_in_progress(TRUE); // /* Don't set up main window for a capture file. */ -- cgit v1.2.3