[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