diff options
author | Håkon Øye Amundsen <haakon.amundsen@nordicsemi.no> | 2017-08-25 11:28:34 +0200 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2017-08-28 05:48:01 +0000 |
commit | 018f6bff18785a1c3971a1ccfe3b1b5243d4d154 (patch) | |
tree | aa4d61e478e39f628000dd6cf7bbbccc2e745a7d /ui | |
parent | 7aeff4fb904e67ce8f81053f595b8a8b0340cb52 (diff) |
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>
Diffstat (limited to 'ui')
-rw-r--r-- | ui/qt/interface_toolbar.cpp | 15 | ||||
-rw-r--r-- | ui/qt/interface_toolbar.h | 2 | ||||
-rw-r--r-- | ui/qt/interface_toolbar_reader.cpp | 170 | ||||
-rw-r--r-- | ui/qt/interface_toolbar_reader.h | 26 | ||||
-rw-r--r-- | ui/qt/main_window.cpp | 4 | ||||
-rw-r--r-- | ui/qt/main_window_slots.cpp | 4 |
6 files changed, 161 insertions, 60 deletions
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 <QObject> #include <QByteArray> +#ifdef _WIN32 +#include <windows.h> +#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. */ |