extcap: Interface Toolbar support on Windows
authorHåkon Øye Amundsen <haakon.amundsen@nordicsemi.no>
Fri, 25 Aug 2017 09:28:34 +0000 (11:28 +0200)
committerAnders Broman <a.broman58@gmail.com>
Mon, 28 Aug 2017 05:48:01 +0000 (05:48 +0000)
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>
15 files changed:
AUTHORS.src
capture_opts.c
capture_opts.h
doc/README.extcap
doc/extcap_example.py
extcap.c
extcap.h
extcap_spawn.c
extcap_spawn.h
ui/qt/interface_toolbar.cpp
ui/qt/interface_toolbar.h
ui/qt/interface_toolbar_reader.cpp
ui/qt/interface_toolbar_reader.h
ui/qt/main_window.cpp
ui/qt/main_window_slots.cpp

index 172a1a3f404832006f4e4d9d7e24157b48354702..6e8bd4f44fa40279408bf3cddaa44565855d2379 100644 (file)
@@ -3955,6 +3955,7 @@ James Lynch               <lynch007[AT]gmail.com>
 Chidambaram Arunachalam        <carunach[AT]cisco.com>
 João Valverde         <joao.valverde[AT]tecnico.ulisboa.pt>
 Benoît Canet          <benoit[AT]scylladb.com>
+Håkon Øye Amundsen      <haakon.amundsen[AT]nordicsemi.no>
 
 Acknowledgements
 ------------
index 0f7a88ee3f403efd916397077687687b4daafe92..4d63ba4d125ec607b899a823bf1251e929477d5a 100644 (file)
@@ -70,6 +70,8 @@ capture_opts_init(capture_options *capture_opts)
     capture_opts->default_options.extcap_pid      = INVALID_EXTCAP_PID;
 #ifdef _WIN32
     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
     capture_opts->default_options.extcap_control_in  = 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;
 #ifdef _WIN32
     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
     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);
@@ -1234,6 +1238,8 @@ collect_ifaces(capture_options *capture_opts)
             interface_opts.extcap_userdata = NULL;
 #ifdef _WIN32
             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
             interface_opts.extcap_control_in = NULL;
             interface_opts.extcap_control_out = NULL;
index 22d03c84728ac91e7e814eef2fcfd5ee76b2d4d2..311cc4ac9789050435de98e25ba8536004515630 100644 (file)
@@ -238,6 +238,8 @@ typedef struct interface_options_tag {
     guint             extcap_child_watch;
 #ifdef _WIN32
     HANDLE            extcap_pipe_h;
+    HANDLE            extcap_control_in_h;
+    HANDLE            extcap_control_out_h;
 #endif
     gchar            *extcap_control_in;
     gchar            *extcap_control_out;
index f1e27ce01c14fbc305406f2e44b867a7cc5b6e08..3ce07aa16164a4b674a642ce66c7c9b1a02eb006 100644 (file)
@@ -356,7 +356,7 @@ Control packet:
   The common sync pipe indication. This protocol uses the value 'T'.
 
  Message Length:
-  Payload length + 2 bytes for argument number and command.
+  Payload length + 2 bytes for control number and command.
 
  Control Number:
    Unique number to identify the control.  This number also gives the order of
index e984b374aa75b0ce16000be2b55657c8be2c378f..9c14ddeae779a898f0e62c5fe1f9f8b2a21827b5 100755 (executable)
@@ -340,28 +340,22 @@ def extcap_capture(interface, fifo, control_in, control_out, in_delay, in_verify
        message = in_message
        verify = in_verify
        counter = 1
-
-       if not os.path.exists(fifo):
-               print ( "Fifo does not exist, exiting!", file=sys.stderr )
-               sys.exit(1)
-
        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")
 
+       with open(fifo, 'wb', 0 ) as fh:
+               fh.write (pcap_fake_header())
 
-       if control_in != None:
-               # Start reading thread
-               thread = Thread(target = control_read_thread, args = (control_in, fn_out))
-               thread.start()
+               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:
-               fh.write (pcap_fake_header())
+               if fn_out != None:
+                       control_write_defaults(fn_out)
 
                while True:
                        if fn_out != None:
@@ -383,10 +377,6 @@ def extcap_capture(interface, fifo, control_in, control_out, in_delay, in_verify
                fn_out.close()
 
 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
        # where the message cannot be read. (really?)
        fh = open(fifo, 'wb', 0 )
index d025c9fe256e58d589366d6ebee26b119c5366ca..e88edc8dbc1bb717c456b5489c67843ec388b20f 100644 (file)
--- a/extcap.c
+++ b/extcap.c
@@ -1041,6 +1041,24 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
             CloseHandle(interface_opts.extcap_pipe_h);
             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
         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))
         {
             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_CONTROL_OUT_PREFIX);
+                               EXTCAP_CONTROL_OUT_PREFIX, FALSE);
+#ifdef _WIN32
+            interface_opts.extcap_control_out_h = pipe_h;
+#endif
         }
 
         /* create pipe for fifo */
         if (!extcap_create_pipe(interface_opts.name, &interface_opts.extcap_fifo,
-                                EXTCAP_PIPE_PREFIX))
+                                EXTCAP_PIPE_PREFIX, TRUE))
         {
             return FALSE;
         }
@@ -1403,7 +1427,18 @@ extcap_init_interfaces(capture_options *capture_opts)
          */
         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
 
@@ -1416,15 +1451,14 @@ extcap_init_interfaces(capture_options *capture_opts)
     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
     gchar timestr[ 14 + 1 ];
     time_t current_time;
-
     gchar *pipename = NULL;
-
     SECURITY_ATTRIBUTES security;
+
     /* create pipename */
     current_time = time(NULL);
     /*
@@ -1440,18 +1474,19 @@ gboolean extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe
     security.bInheritHandle = TRUE;
     security.lpSecurityDescriptor = NULL;
 
-    /* create a namedPipe*/
+    /* create a namedPipe */
     pipe_h = CreateNamedPipe(
                  utf_8to16(pipename),
                  PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
-                 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
-                 5, 65536, 65536,
+                 byte_mode ? PIPE_TYPE_BYTE : PIPE_TYPE_MESSAGE | byte_mode ? PIPE_READMODE_BYTE : PIPE_READMODE_MESSAGE | PIPE_WAIT,
+                 1, 65536, 65536,
                  300,
                  &security);
 
     if (pipe_h == INVALID_HANDLE_VALUE)
     {
         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nError creating pipe => (%d)", GetLastError());
+        g_free (pipename);
         return FALSE;
     }
     else
index 2e6739fa00d69f12f19e3b5eae1837d32ee7f337..013ccdb4fd649441d6424cb97337b059c6be6c10 100644 (file)
--- a/extcap.h
+++ b/extcap.h
@@ -40,8 +40,8 @@
 
 /* Prefix for the pipe interfaces */
 #define EXTCAP_PIPE_PREFIX "wireshark_extcap"
-#define EXTCAP_CONTROL_IN_PREFIX  "wireshark_control_in"
-#define EXTCAP_CONTROL_OUT_PREFIX "wireshark_control_out"
+#define EXTCAP_CONTROL_IN_PREFIX  "wireshark_control_ext_to_ws"
+#define EXTCAP_CONTROL_OUT_PREFIX "wireshark_control_ws_to_ext"
 
 #define EXTCAP_ARGUMENT_CONFIG                  "--extcap-config"
 #define EXTCAP_ARGUMENT_LIST_INTERFACES         "--extcap-interfaces"
@@ -143,11 +143,11 @@ gboolean
 extcap_init_interfaces(capture_options * capture_opts);
 
 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 */
 void
-extcap_if_cleanup(capture_options * capture_opts _U_, gchar ** errormsg);
+extcap_if_cleanup(capture_options * capture_opts, gchar ** errormsg);
 
 struct preference *
 extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg * arg);
index 8b9b5988bffde023076844143e0d6bfb2000e82a..d88c3945d033bf81f6bffc9d8dd4af94f8a21cd9 100644 (file)
@@ -287,67 +287,117 @@ GPid extcap_spawn_async(extcap_userdata *userdata, GPtrArray *args)
 }
 
 #ifdef _WIN32
+
+typedef struct
+{
+    HANDLE pipeHandle;
+    OVERLAPPED ol;
+    BOOL pendingIO;
+} PIPEINTS;
+
 gboolean
-extcap_wait_for_pipe(HANDLE pipe_h, HANDLE pid)
+extcap_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
 {
-    DWORD dw;
-    HANDLE handles[2];
-    OVERLAPPED ov;
-    gboolean success = FALSE;
-    ov.Pointer = 0;
-    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
-    ConnectNamedPipe(pipe_h, &ov);
-    handles[0] = ov.hEvent;
-    handles[1] = pid;
-
-    if (GetLastError() == ERROR_PIPE_CONNECTED)
+    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, "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);
-        if (dw == WAIT_OBJECT_0)
+        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())
         {
-            /* ConnectNamedPipe finished. */
-            DWORD code;
+        case ERROR_IO_PENDING:
+            num_waiting_to_connect++;
+            pipeinsts[i].pendingIO = TRUE;
+            break;
 
-            code = GetLastError();
-            if (code == ERROR_IO_PENDING)
+        case ERROR_PIPE_CONNECTED:
+            if (SetEvent(pipeinsts[i].ol.hEvent))
             {
-                DWORD dummy;
-                if (!GetOverlappedResult(ov.hEvent, &ov, &dummy, TRUE))
-                {
-                    code = GetLastError();
-                }
-                else
-                {
-                    code = ERROR_SUCCESS;
-                    success = TRUE;
-                }
-            }
+                break;
+            } // Fallthrough if this fails.
 
-            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))
+    }
+
+    // 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)
         {
-            /* extcap process terminated. */
-            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe.");
+            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds.");
+            return FALSE;
         }
-        else if (dw == WAIT_TIMEOUT)
+        // If index points to our handles array
+        else if (idx >= 0 && idx < num_handles)
         {
-            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds.");
+            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
         {
             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
+            return FALSE;
         }
     }
 
-    CloseHandle(ov.hEvent);
-
-    return success;
+    return TRUE;
 }
 #endif
 
index 16d8a97a58f29f3401d0e32a1944034690f24495..858671865a2abbff8eb92810717129559a322fa4 100644 (file)
@@ -47,7 +47,7 @@ gboolean extcap_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar
 GPid extcap_spawn_async ( extcap_userdata * userdata, GPtrArray * args );
 
 #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);
 #endif
 
index b28fee9abeb01321702ad6009b56eb54031d93ff..ffddf28f50a15fd552c69657dcba91f2bdac068c 100644 (file)
@@ -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;
         }
 
index cdbfb57906aceec1828dc8f2ac2fc53c55120f3c..404dc1ccdb76222db1889614af31368b3af90f11 100644 (file)
@@ -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();
index f4565fe6c3a17d1c25b00970b287c9f2b8b5d71b..99b15a47b3ffc2984dac70a4e86d406a51dc6653 100644 (file)
 
 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();
 }
 
index 1b34db4fb0f9d4d5e0a592efe80c8afd607bf9aa..75fc7cbea9f79c671bbe6ebb0b73a7e250b6ea43 100644 (file)
 #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
index 653ff4cf4fa868f9ebbca521ab19046546f9be8e..cd5a2ca53e4bc4efd0c2a301b67b541567cd1388 100644 (file)
@@ -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
 
index 0c6dcbf7108fdf1ddc098c8aaea923e8850228a0..c6d30c9a6a86c6031dd434db0f11b0fad1d584e2 100644 (file)
@@ -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. */