[svn] w32pth - r37 - trunk

svn author wk cvs at cvs.gnupg.org
Mon Apr 19 11:26:56 CEST 2010


Author: wk
Date: 2010-04-19 11:26:56 +0200 (Mon, 19 Apr 2010)
New Revision: 37

Modified:
   trunk/ChangeLog
   trunk/w32-io.c
   trunk/w32-pth.c
Log:
Change the way we distinguish sockets from handles


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2010-04-14 14:32:19 UTC (rev 36)
+++ trunk/ChangeLog	2010-04-19 09:26:56 UTC (rev 37)
@@ -1,3 +1,11 @@
+2010-04-19  Werner Koch  <wk at g10code.com>
+
+	* w32-pth.c (is_socket_2): New.
+	(do_pth_read, do_pth_write): Use is_socket_2.
+
+	* w32-io.c (is_socket): New.
+	(reader, writer): Use is_socket.
+
 2010-04-08  Werner Koch  <wk at g10code.com>
 
 	* w32-io.c (reader, writer) [W32CE]: Take care of

Modified: trunk/w32-io.c
===================================================================
--- trunk/w32-io.c	2010-04-14 14:32:19 UTC (rev 36)
+++ trunk/w32-io.c	2010-04-19 09:26:56 UTC (rev 37)
@@ -306,15 +306,51 @@
 }
 
 
+/* Return true if HD refers to a socket.  */
+static int
+is_socket (HANDLE hd)
+{
+#ifdef HAVE_W32CE_SYSTEM
+  (void)hd;
+  return 0;
+#else
+  /* We need to figure out whether we are working on a socket or on a
+     handle.  A trivial way would be to check for the return code of
+     recv and see if it is WSAENOTSOCK.  However the recv may block
+     after the server process died and thus the destroy_reader will
+     hang.  Another option is to use getsockopt to test whether it is
+     a socket.  The bug here is that once a socket with a certain
+     values has been opened, closed and later a CreatePipe returned
+     the same value (i.e. handle), getsockopt still believes it is a
+     socket.  What we do now is to use a combination of GetFileType
+     and GetNamedPipeInfo.  The specs say that the latter may be used
+     on anonymous pipes as well.  Note that there are claims that
+     since winsocket version 2 ReadFile may be used on a socket but
+     only if it is supported by the service provider.  Tests on a
+     stock XP using a local TCP socket show that it does not work.  */
+  DWORD dummyflags, dummyoutsize, dummyinsize, dummyinst;
+  if (GetFileType (hd) == FILE_TYPE_PIPE
+      && !GetNamedPipeInfo (hd, &dummyflags, &dummyoutsize,
+                            &dummyinsize, &dummyinst))
+    return 1; /* Function failed; thus we assume it is a socket.  */
+  else
+    return 0; /* Success; this is not a socket.  */
+#endif
+}
+
+
 static DWORD CALLBACK 
 reader (void *arg)
 {
   struct reader_context_s *ctx = arg;
   int nbytes;
   DWORD nread;
+  int sock;
   TRACE_BEG1 (DEBUG_SYSIO, "pth:reader", ctx->file_hd,
 	      "thread=%p", ctx->thread_hd);
 
+  sock = is_socket (ctx->file_hd);
+
   for (;;)
     {
       LOCK (ctx->mutex);
@@ -342,35 +378,62 @@
 	nbytes = READBUF_SIZE - ctx->writepos;
       UNLOCK (ctx->mutex);
       
-      TRACE_LOG1 ("reading %d bytes", nbytes);
-      if (!ReadFile (ctx->file_hd,
-		     ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
-	{
-	  ctx->error_code = (int) GetLastError ();
-	  if (ctx->error_code == ERROR_BROKEN_PIPE)
-	    {
-	      ctx->eof = 1;
-	      TRACE_LOG ("got EOF (broken pipe)");
+      TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
+
+      if (sock)
+        {
+          int n;
+
+          n = recv ((int)ctx->file_hd,
+                    ctx->buffer + ctx->writepos, nbytes, 0);
+          if (n < 0)
+            {
+              ctx->error_code = (int) WSAGetLastError ();
+              if (ctx->error_code == ERROR_BROKEN_PIPE)
+                {
+                  ctx->eof = 1;
+                  TRACE_LOG ("got EOF (broken connection)");
+                }
+              else
+                {
+                  ctx->error = 1;
+                  TRACE_LOG1 ("recv error: ec=%d", ctx->error_code);
+                }
+              break;
             }
+          nread = n;
+        }
+      else
+        {
+          if (!ReadFile (ctx->file_hd,
+                         ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
+            {
+              ctx->error_code = (int) GetLastError ();
+              if (ctx->error_code == ERROR_BROKEN_PIPE)
+                {
+                  ctx->eof = 1;
+                  TRACE_LOG ("got EOF (broken pipe)");
+                }
 #ifdef HAVE_W32CE_SYSTEM
-	  else if (ctx->error_code == ERROR_PIPE_NOT_CONNECTED
-                   || ctx->error_code == ERROR_BUSY)
-	    {
-              /* This may happen while one pipe end is still dangling
-                 because the child process has not yet completed the
-                 pipe creation.  ERROR_BUSY has been seen as well, it
-                 is propabaly returned by the device manager.  */
-              ctx->error_code = 0;
-              Sleep (100);
-              continue;
-            }
+              else if (ctx->error_code == ERROR_PIPE_NOT_CONNECTED
+                       || ctx->error_code == ERROR_BUSY)
+                {
+                  /* This may happen while one pipe end is still dangling
+                     because the child process has not yet completed the
+                     pipe creation.  ERROR_BUSY has been seen as well, it
+                     is propabaly returned by the device manager.  */
+                  ctx->error_code = 0;
+                  Sleep (100);
+                  continue;
+                }
 #endif
-	  else
-	    {
-	      ctx->error = 1;
-	      TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
+              else
+                {
+                  ctx->error = 1;
+                  TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
+                }
+              break;
             }
-	  break;
         }
       if (!nread)
 	{
@@ -648,9 +711,12 @@
 {
   struct writer_context_s *ctx = arg;
   DWORD nwritten;
+  int sock;
   TRACE_BEG1 (DEBUG_SYSIO, "pth:writer", ctx->file_hd,
 	      "thread=%p", ctx->thread_hd);
 
+  sock = is_socket (ctx->file_hd);
+
   for (;;)
     {
       LOCK (ctx->mutex);
@@ -678,30 +744,52 @@
         }
       UNLOCK (ctx->mutex);
       
-      TRACE_LOG1 ("writing %d bytes", ctx->nbytes);
+      TRACE_LOG2 ("%s %d bytes", sock?"sending":"writing", ctx->nbytes);
+ 
       /* Note that CTX->nbytes is not zero at this point, because
 	 _pth_io_write always writes at least 1 byte before waking
 	 us up, unless CTX->stop_me is true, which we catch above.  */
-      if (!WriteFile (ctx->file_hd, ctx->buffer,
-		      ctx->nbytes, &nwritten, NULL))
-	{
-	  ctx->error_code = (int) GetLastError ();
+      if (sock)
+        {
+          /* We need to try send first because a socket handle can't
+             be used with WriteFile.  */
+          int n;
+          
+          n = send ((int)ctx->file_hd,
+                    ctx->buffer, ctx->nbytes, 0);
+          if (n < 0)
+            {
+              ctx->error_code = (int) WSAGetLastError ();
+              ctx->error = 1;
+              TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
+              break;
+            }
+          nwritten = n;
+        }
+      else
+        {
+          if (!WriteFile (ctx->file_hd, ctx->buffer,
+                          ctx->nbytes, &nwritten, NULL))
+            {
+              ctx->error_code = (int) GetLastError ();
 #ifdef HAVE_W32CE_SYSTEM
-	  if (ctx->error_code == ERROR_PIPE_NOT_CONNECTED
-              || ctx->error_code == ERROR_BUSY)
-	    {
-              /* This may happen while one pipe end is still dangling
-                 because the child process has not yet completed the
-                 pipe creation.  ERROR_BUSY has been seen as well, it
-                 is propabaly returned by the device manager. */
-              ctx->error_code = 0;
-              Sleep (100);
-              continue;
+              if (ctx->error_code == ERROR_PIPE_NOT_CONNECTED
+                  || ctx->error_code == ERROR_BUSY)
+                {
+                  /* This may happen while one pipe end is still
+                     dangling because the child process has not yet
+                     completed the pipe creation.  ERROR_BUSY has been
+                     seen as well, it is propabaly returned by the
+                     device manager. */
+                  ctx->error_code = 0;
+                  Sleep (100);
+                  continue;
+                }
+#endif
+              ctx->error = 1;
+              TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
+              break;
             }
-#endif
-	  ctx->error = 1;
-	  TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
-	  break;
 	}
       TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
       

Modified: trunk/w32-pth.c
===================================================================
--- trunk/w32-pth.c	2010-04-14 14:32:19 UTC (rev 36)
+++ trunk/w32-pth.c	2010-04-19 09:26:56 UTC (rev 37)
@@ -884,7 +884,40 @@
 }
 
 
+/* Return true if HD refers to a socket.  */
 static int
+is_socket_2 (int hd)
+{
+#ifdef HAVE_W32CE_SYSTEM
+  (void)hd;
+  return 1; /* Assume socket.  */
+#else
+  /* We need to figure out whether we are working on a socket or on a
+     handle.  A trivial way would be to check for the return code of
+     recv and see if it is WSAENOTSOCK.  However the recv may block
+     after the server process died and thus the destroy_reader will
+     hang.  Another option is to use getsockopt to test whether it is
+     a socket.  The bug here is that once a socket with a certain
+     values has been opened, closed and later a CreatePipe returned
+     the same value (i.e. handle), getsockopt still believes it is a
+     socket.  What we do now is to use a combination of GetFileType
+     and GetNamedPipeInfo.  The specs say that the latter may be used
+     on anonymous pipes as well.  Note that there are claims that
+     since winsocket version 2 ReadFile may be used on a socket but
+     only if it is supported by the service provider.  Tests on a
+     stock XP using a local TCP socket show that it does not work.  */
+  DWORD dummyflags, dummyoutsize, dummyinsize, dummyinst;
+  if (GetFileType ((HANDLE)hd) == FILE_TYPE_PIPE
+      && !GetNamedPipeInfo ((HANDLE)hd, &dummyflags, &dummyoutsize,
+                            &dummyinsize, &dummyinst))
+    return 1; /* Function failed; thus we assume it is a socket.  */
+  else
+    return 0; /* Success; this is not a socket.  */
+#endif
+}
+
+
+static int
 pipe_is_not_connected (void)
 {  
 #ifdef HAVE_W32CE_SYSTEM
@@ -910,6 +943,7 @@
 {
   int n;
   HANDLE hd;
+  int use_readfile = 0;
 
   /* We have to check for internal pipes first, as socket operations
      can block on these.  */
@@ -918,8 +952,20 @@
     n = _pth_io_read (fd, buffer, size);
   else
     {
-      n = recv (fd, buffer, size, 0);
-      if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
+      if (is_socket_2 (fd))
+        {
+          n = recv (fd, buffer, size, 0);
+#ifdef HAVE_W32CE_SYSTEM          
+          if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
+            use_readfile = 1; /* Fallback to ReadFile.  */
+#endif
+        }
+      else
+        {
+          n = -1;
+          use_readfile = 1;
+        }
+      if (n == -1 && use_readfile)
 	{
 	  DWORD nread = 0;
 
@@ -941,7 +987,12 @@
 	    n = (int) nread;
 	}
       else if (n == -1)
-	set_errno (map_wsa_to_errno (WSAGetLastError ()));
+        {
+          if (DBG_ERROR)
+            fprintf (dbgfp, "%s: pth_read(0x%x) recv failed: ec=%d\n",
+                     log_get_prefix (NULL), fd, (int)WSAGetLastError ());
+          set_errno (map_wsa_to_errno (WSAGetLastError ()));
+        }
     }
 
   return n;
@@ -1017,6 +1068,7 @@
 {
   int n;
   HANDLE hd;
+  int use_writefile = 0;
 
   /* We have to check for internal pipes first, as socket operations
      can block on these.  */
@@ -1025,8 +1077,20 @@
     n = _pth_io_write (fd, buffer, size);
   else
     {
-      n = send (fd, buffer, size, 0);
-      if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
+      if (is_socket_2 (fd))
+        {
+          n = send (fd, buffer, size, 0);
+#ifdef HAVE_W32CE_SYSTEM          
+          if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
+            use_writefile = 1; /* Fallback to ReadFile.  */
+#endif
+        }
+      else
+        {
+          n = -1;
+          use_writefile = 1;
+        }
+      if (n == -1 && use_writefile)
 	{
 	  DWORD nwrite;
 	  char strerr[256];
@@ -1046,7 +1110,12 @@
 	    n = (int) nwrite;
 	}
       else if (n == -1)
-	set_errno (map_wsa_to_errno (WSAGetLastError ()));
+        {
+          if (DBG_ERROR)
+            fprintf (dbgfp, "%s: pth_write(0x%x) send failed: ec=%d\n",
+                     log_get_prefix (NULL), fd, (int)WSAGetLastError ());
+          set_errno (map_wsa_to_errno (WSAGetLastError ()));
+        }
     }
 
   return n;




More information about the Gnupg-commits mailing list