For the Wireshark/TShark -> dumpcap signal pipe on Windows, use a named
authorgerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 26 Oct 2007 16:32:28 +0000 (16:32 +0000)
committergerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 26 Oct 2007 16:32:28 +0000 (16:32 +0000)
pipe instead of stdin.  Add an argument (currently the parent PID) back
to the "-Z" flag and use it to construct the pipe name.  This lets us
pass the parent's stdin handle to dumpcap, which lets us capture from
stdin on Windows.  Add a comment about checking for the parent process.

In capture_loop.c, remove the wait_forever argument from cap_pipe_select()
since it was always FALSE.  Set the timeout under Windows to 250 ms
instead of 250000 ms.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@23279 f5534014-38df-0310-8fa8-9805f1628bb7

Makefile.nmake
capture_loop.c
capture_sync.c
capture_sync.h
dumpcap.c

index 0c9f126603dd1f402d0dccb76b5a8c479c1d498e..83751d57f2d7617af0d903412fbad3ff325fa26a 100644 (file)
@@ -274,10 +274,10 @@ randpkt.exe       : $(randpkt_OBJECTS) getopt.obj
        mt.exe -nologo -manifest "randpkt.exe.manifest" -outputresource:randpkt.exe;1
 !ENDIF
 
-dumpcap.exe    : $(LIBS_CHECK) config.h svnversion.h $(dumpcap_OBJECTS) getopt.obj inet_ntop.obj mkstemp.obj wiretap\wiretap-$(WTAP_VERSION).lib image\dumpcap.res 
+dumpcap.exe    : $(LIBS_CHECK) config.h svnversion.h $(dumpcap_OBJECTS) getopt.obj epan/unicode-utils.obj inet_ntop.obj mkstemp.obj wiretap\wiretap-$(WTAP_VERSION).lib image\dumpcap.res 
        @echo Linking $@
        $(LINK) @<<
-               /OUT:dumpcap.exe $(conflags) $(conlibsdll) $(LDFLAGS) /SUBSYSTEM:console $(dumpcap_LIBS) $(dumpcap_OBJECTS) getopt.obj inet_ntop.obj mkstemp.obj image\dumpcap.res
+               /OUT:dumpcap.exe $(conflags) $(conlibsdll) $(LDFLAGS) /SUBSYSTEM:console $(dumpcap_LIBS) $(dumpcap_OBJECTS) getopt.obj epan/unicode-utils.obj inet_ntop.obj mkstemp.obj image\dumpcap.res
 <<
 !IF "$(MSVC_VARIANT)" == "MSVC2005" || "$(MSVC_VARIANT)" == "MSVC2005EE" || "$(MSVC_VARIANT)" == "DOTNET20" 
        mt.exe -nologo -manifest "dumpcap.exe.manifest" -outputresource:dumpcap.exe;1
index 8493302087e555797b7b5a8185200785fe47ff73..de9538f9a3924983e8ec3b1f224344622e177523 100644 (file)
@@ -156,7 +156,7 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr
  * the string cap_pipe_err_str should be used instead of errno.
  */
 static int
-cap_pipe_select(int pipe_fd, gboolean wait_forever) {
+cap_pipe_select(int pipe_fd) {
 #ifndef _WIN32
   fd_set      rfds;
   struct timeval timeout, *pto;
@@ -166,13 +166,11 @@ cap_pipe_select(int pipe_fd, gboolean wait_forever) {
 
   FD_ZERO(&rfds);
   FD_SET(pipe_fd, &rfds);
-  if (wait_forever) {
-    pto = NULL;
-  } else {
-    timeout.tv_sec = 0;
-    timeout.tv_usec = CAP_READ_TIMEOUT * 1000;
-    pto = &timeout;
-  }
+
+  timeout.tv_sec = 0;
+  timeout.tv_usec = CAP_READ_TIMEOUT * 1000;
+  pto = &timeout;
+
   sel_ret = select(pipe_fd+1, &rfds, NULL, NULL, pto);
   if (sel_ret < 0)
     cap_pipe_err_str = strerror(errno);
@@ -185,7 +183,6 @@ cap_pipe_select(int pipe_fd, gboolean wait_forever) {
    */
   HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd);
   wchar_t *err_str;
-  DWORD timeout = wait_forever ? INFINITE : CAP_READ_TIMEOUT * 1000;
   DWORD wait_ret;
 
   if (hPipe == INVALID_HANDLE_VALUE) {
@@ -195,7 +192,7 @@ cap_pipe_select(int pipe_fd, gboolean wait_forever) {
 
   cap_pipe_err_str = "Unknown error";
 
-  wait_ret = WaitForSingleObject(hPipe, timeout);
+  wait_ret = WaitForSingleObject(hPipe, CAP_READ_TIMEOUT);
   switch (wait_ret) {
     /* XXX - This probably isn't correct */
     case WAIT_ABANDONED:
@@ -374,7 +371,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
   /* read the pcap header */
   bytes_read = 0;
   while (bytes_read < sizeof magic) {
-    sel_ret = cap_pipe_select(fd, FALSE);
+    sel_ret = cap_pipe_select(fd);
     if (sel_ret < 0) {
       g_snprintf(errmsg, errmsgl,
         "Unexpected error from select: %s", strerror(errno));
@@ -429,7 +426,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
   /* Read the rest of the header */
   bytes_read = 0;
   while (bytes_read < sizeof(struct pcap_hdr)) {
-    sel_ret = cap_pipe_select(fd, FALSE);
+    sel_ret = cap_pipe_select(fd);
     if (sel_ret < 0) {
       g_snprintf(errmsg, errmsgl,
         "Unexpected error from select: %s", strerror(errno));
@@ -962,7 +959,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
 #ifdef LOG_CAPTURE_VERBOSE
     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe");
 #endif
-    sel_ret = cap_pipe_select(ld->cap_pipe_fd, FALSE);
+    sel_ret = cap_pipe_select(ld->cap_pipe_fd);
     if (sel_ret <= 0) {
       inpkts = 0;
       if (sel_ret < 0 && errno != EINTR) {
@@ -1002,7 +999,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch with select");
 #endif
     if (ld->pcap_fd != -1) {
-      sel_ret = cap_pipe_select(ld->pcap_fd, FALSE);
+      sel_ret = cap_pipe_select(ld->pcap_fd);
       if (sel_ret > 0) {
         /*
          * "select()" says we can read from it without blocking; go for
index 1a9723344f9d4640461a9610f8e2d0c71f71af21..9c840ea2644b9ff346725c7d2972765022e58b33 100644 (file)
@@ -254,14 +254,15 @@ sync_pipe_start(capture_options *capture_opts) {
     char buffer_size[ARGV_NUMBER_LEN];
     HANDLE sync_pipe_read;                  /* pipe used to send messages from child to parent */
     HANDLE sync_pipe_write;                 /* pipe used to send messages from child to parent */
-    HANDLE signal_pipe_read;                /* pipe used to send messages from parent to child (currently only stop) */
-    HANDLE signal_pipe_write;               /* pipe used to send messages from parent to child (currently only stop) */
+    HANDLE signal_pipe;                     /* named pipe used to send messages from parent to child (currently only stop) */
     GString *args = g_string_sized_new(200);
     gchar *quoted_arg;
     SECURITY_ATTRIBUTES sa;
     STARTUPINFO si;
     PROCESS_INFORMATION pi;
     int i;
+    char control_id[ARGV_NUMBER_LEN];
+    gchar *signal_pipe_name;
 #else
     char errmsg[1024+1];
     int sync_pipe[2];                       /* pipe used to send messages from child to parent */
@@ -354,6 +355,12 @@ sync_pipe_start(capture_options *capture_opts) {
     /* dumpcap should be running in capture child mode (hidden feature) */
 #ifndef DEBUG_CHILD
     argv = sync_pipe_add_arg(argv, &argc, "-Z");
+#ifdef _WIN32
+    g_snprintf(control_id, ARGV_NUMBER_LEN, "%d", GetCurrentProcessId());
+    argv = sync_pipe_add_arg(argv, &argc, control_id);
+#else
+    argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
+#endif
 #endif
 
 #ifdef _WIN32
@@ -389,13 +396,16 @@ sync_pipe_start(capture_options *capture_opts) {
       return FALSE;
     }
 
-    /* Create a pipe for the parent process */
-    if (! CreatePipe(&signal_pipe_read, &signal_pipe_write, &sa, 512)) {
+    /* Create the signal pipe */
+    signal_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT, control_id);
+    signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name),
+      PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL);
+    g_free(signal_pipe_name);
+
+    if (signal_pipe == INVALID_HANDLE_VALUE) {
       /* Couldn't create the signal pipe between parent and child. */
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create signal pipe: %s",
                         strerror(errno));
-      CloseHandle(sync_pipe_read);
-      CloseHandle(sync_pipe_write);
       g_free( (gpointer) argv[0]);
       g_free( (gpointer) argv);
       return FALSE;
@@ -410,7 +420,7 @@ sync_pipe_start(capture_options *capture_opts) {
 #else
     si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
     si.wShowWindow  = SW_HIDE;  /* this hides the console window */
-    si.hStdInput = signal_pipe_read;
+    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
     si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
     si.hStdError = sync_pipe_write;
     /*si.hStdError = (HANDLE) _get_osfhandle(2);*/
@@ -446,10 +456,8 @@ sync_pipe_start(capture_options *capture_opts) {
     sync_pipe_read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY);
 
     /* associate the operating system filehandle to a C run-time file handle */
-    capture_opts->signal_pipe_write_fd = _open_osfhandle( (long) signal_pipe_write, _O_BINARY);
+    capture_opts->signal_pipe_write_fd = _open_osfhandle( (long) signal_pipe, _O_BINARY);
 
-    /* child owns the read side now, close our handle */
-    CloseHandle(signal_pipe_read);
 #else /* _WIN32 */
     if (pipe(sync_pipe) < 0) {
       /* Couldn't create the pipe between parent and child. */
@@ -804,6 +812,7 @@ sync_interface_list_open(gchar **msg) {
     /* dumpcap should be running in capture child mode (hidden feature) */
 #ifndef DEBUG_CHILD
     argv = sync_pipe_add_arg(argv, &argc, "-Z");
+    argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
 #endif
 
     return sync_pipe_run_command(argv, msg);
@@ -843,6 +852,7 @@ sync_linktype_list_open(gchar *ifname, gchar **msg) {
     /* dumpcap should be running in capture child mode (hidden feature) */
 #ifndef DEBUG_CHILD
     argv = sync_pipe_add_arg(argv, &argc, "-Z");
+    argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
 #endif
 
     return sync_pipe_run_command(argv, msg);
@@ -880,6 +890,7 @@ sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg) {
     /* dumpcap should be running in capture child mode (hidden feature) */
 #ifndef DEBUG_CHILD
     argv = sync_pipe_add_arg(argv, &argc, "-Z");
+    argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
 #endif
 
     return sync_pipe_open_command(argv, read_fd, fork_child, msg);
index a0a9f551854ee3bd64bd50c38eea2150ac51e17d..46eff4a71519ce1f22ecf9540078ebf2b73efcc4 100644 (file)
@@ -58,9 +58,11 @@ extern void
 sync_pipe_kill(int fork_child);
 
 /** Has the parent signalled the child to stop? */
+#define SIGNAL_PIPE_CTRL_ID_NONE "none"
 #ifdef _WIN32
 extern gboolean
 signal_pipe_check_running(void);
+#define SIGNAL_PIPE_FORMAT "\\\\.\\pipe\\wireshark.%s.signal"
 #endif
 
 /** Get an interface list using dumpcap */
index 41603be2e1014a68f7b9e09a7028d6dd476f96ab..3bdcf3ce445088afec3aa7e34b1dd06a7206b7c0 100644 (file)
--- a/dumpcap.c
+++ b/dumpcap.c
 #include "capture-wpcap.h"
 #endif
 
+#ifdef _WIN32
+#include "epan/unicode-utils.h"
+#endif
+
 #include "sync_pipe.h"
 
 #include "capture.h"
 /*#define DEBUG_DUMPCAP*/
 
 gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */
+#ifdef _WIN32
+gchar *sig_pipe_name = NULL;
+HANDLE sig_pipe_handle = NULL;
+#endif
 
 static void
 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
@@ -253,7 +261,7 @@ main(int argc, char *argv[])
   gboolean             print_statistics = FALSE;
   int                  status, run_once_args = 0;
 
-#define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z"
+#define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z:"
 
 #ifdef _WIN32
 #define OPTSTRING_WIN32 "B:"
@@ -365,6 +373,23 @@ main(int argc, char *argv[])
 #ifdef _WIN32
           /* set output pipe to binary mode, to avoid ugly text conversions */
          _setmode(2, O_BINARY);
+          /*
+           * optarg = the control ID, aka the PPID, currently used for the
+           * signal pipe name.
+           */
+          if (strcmp(optarg, SIGNAL_PIPE_CTRL_ID_NONE) != 0) {
+              sig_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT,
+                  optarg);
+              sig_pipe_handle = CreateFile(utf_8to16(sig_pipe_name),
+                  GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+              if (sig_pipe_handle == INVALID_HANDLE_VALUE) {
+                  g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+                      "Signal pipe: Unable to open %s.  Dead parent?",
+                      sig_pipe_name);
+                  exit_main(1);
+              }
+          }
 #endif
           break;
 
@@ -632,27 +657,38 @@ report_packet_drops(int drops)
 gboolean
 signal_pipe_check_running(void)
 {
-    /* any news from our parent (stdin)? -> just stop the capture */
-    HANDLE handle;
+    /* any news from our parent? -> just stop the capture */
     DWORD avail = 0;
     gboolean result;
 
-
     /* if we are running standalone, no check required */
     if(!capture_child) {
         return TRUE;
     }
 
-    handle = (HANDLE) GetStdHandle(STD_INPUT_HANDLE);
-    result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
+    if(!sig_pipe_name || !sig_pipe_handle) {
+        /* This shouldn't happen */
+        g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+            "Signal pipe: No name or handle");
+        return FALSE;
+    }
+
+    /*
+     * XXX - We should have the process ID of the parent (from the "-Z" flag)
+     * at this point.  Should we check to see if the parent is still alive,
+     * e.g. by using OpenProcess?
+     */
+
+    result = PeekNamedPipe(sig_pipe_handle, NULL, 0, NULL, &avail, NULL);
 
     if(!result || avail > 0) {
         /* peek failed or some bytes really available */
         /* (if not piping from stdin this would fail) */
         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
-            "Signal pipe: Stop capture");
+            "Signal pipe: Stop capture: %s", sig_pipe_name);
         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
-            "Signal pipe: handle: %x result: %u avail: %u", handle, result, avail);
+            "Signal pipe: %s (%p) result: %u avail: %u", sig_pipe_name,
+            sig_pipe_handle, result, avail);
         return FALSE;
     } else {
         /* pipe ok and no bytes available */