Windows: Wait for dumpcap to initialize.
authorGerald Combs <gerald@wireshark.org>
Wed, 27 Apr 2016 19:14:11 +0000 (12:14 -0700)
committerGerald Combs <gerald@wireshark.org>
Wed, 27 Apr 2016 23:11:34 +0000 (23:11 +0000)
As the MSDN documentation says, "CreateProcess returns without waiting
for the new process to finish its initialization." Add an SP_INIT sync
pipe indicator on Windows and use it in dumpcap to signal to its parent
that it has started up.

Change-Id: I88a4c158871dbe2dd6eba13434e92c5d4b1c2e4b
Reviewed-on: https://code.wireshark.org/review/15132
Reviewed-by: Gerald Combs <gerald@wireshark.org>
capchild/capture_sync.c
dumpcap.c
sync_pipe.h

index edd0c5de7a559917020c5293752f8c63eb7a8c09..9d4ab636e287a52319168b81dc5db0e1214ba27d 100644 (file)
 #include <process.h>    /* For spawning child process */
 #endif
 
-
-
 #ifdef _WIN32
 static void create_dummy_signal_pipe();
 static HANDLE dummy_signal_pipe; /* Dummy named pipe which lets the child check for a dropped connection */
 static gchar *dummy_control_id;
+static gboolean pipe_wait_for_init(int pipe_fd);
 #else
 static const char *sync_pipe_signame(int);
 #endif
@@ -696,6 +695,10 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
         g_free( (gpointer) argv);
         return FALSE;
     }
+    if (!pipe_wait_for_init(sync_pipe_read_fd)) {
+        return FALSE;
+    }
+
     cap_session->fork_child = pi.hProcess;
     /* We may need to store this and close it later */
     CloseHandle(pi.hThread);
@@ -950,6 +953,10 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
         g_free( (gpointer) argv);
         return -1;
     }
+    if (!pipe_wait_for_init(*message_read_fd)) {
+        return -1;
+    }
+
     *fork_child = pi.hProcess;
     /* We may need to store this and close it later */
     CloseHandle(pi.hThread);
@@ -1716,6 +1723,28 @@ pipe_convert_header(const guchar *header, int header_len, char *indicator, int *
     *block_len = (header[1]&0xFF)<<16 | (header[2]&0xFF)<<8 | (header[3]&0xFF);
 }
 
+#ifdef _WIN32
+/* CreateProcess returns immediately. Wait for the child process to send
+   us SP_INIT. Note that WaitForInputIdle is the wrong call to use here
+   as it only applies to GUI applications:
+   https://blogs.msdn.microsoft.com/oldnewthing/20100325-00/?p=14493
+ */
+gboolean
+pipe_wait_for_init(int pipe_fd) {
+    char indicator;
+    char buffer[SP_MAX_MSG_LEN+1] = {0};
+    char *primary_msg;
+
+    pipe_read_block(pipe_fd, &indicator, SP_MAX_MSG_LEN, buffer, &primary_msg);
+    if (indicator != SP_INIT) {
+        report_failure("Child sent startup indicator '%c', expected '%c'.",
+            indicator, SP_INIT);
+        return FALSE;
+    }
+    return TRUE;
+}
+#endif
+
 /* read a message from the sending pipe in the standard format
    (1-byte message indicator, 3-byte message length (excluding length
    and indicator field), and the rest is the message) */
index 21230b7ec754a438692e7e83a5420127fa1274c8..20389eaa0d617f74b375596203683605919ec113 100644 (file)
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -4131,6 +4131,8 @@ main(int argc, char *argv[])
                     exit_main(1);
                 }
             }
+            /* Let our parent know we're fully initialized. */
+            pipe_write_block(2, SP_INIT, "All systems go.");
 #endif
             break;
 
index 455b2b4bd64370b9b102ba8dd4c2b3d5bf572157..0fac40b5f083d0a9a3498d91ab7a1280d0e35ca2 100644 (file)
@@ -62,6 +62,7 @@
  * Win32 only: Indications sent out on the signal pipe (from parent to child)
  * (UNIX-like sends signals for this)
  */
+#define SP_INIT         'I'     /* child process initialized */
 #define SP_QUIT         'Q'     /* "gracefully" capture quit message (SIGUSR1) */
 
 /* write a single message header to the recipient pipe */