[svn] assuan - r371 - trunk/src
svn author wk
cvs at cvs.gnupg.org
Mon Apr 19 10:55:19 CEST 2010
Author: wk
Date: 2010-04-19 10:55:19 +0200 (Mon, 19 Apr 2010)
New Revision: 371
Modified:
trunk/src/ChangeLog
trunk/src/system-w32.c
Log:
More robust detection of sockets
Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog 2010-04-16 00:52:49 UTC (rev 370)
+++ trunk/src/ChangeLog 2010-04-19 08:55:19 UTC (rev 371)
@@ -1,3 +1,8 @@
+2010-04-19 Werner Koch <wk at g10code.com>
+
+ * system-w32.c (is_socket): New.
+ (__assuan_read, __assuan_write): Use is_socket.
+
2010-04-16 Marcus Brinkmann <marcus at g10code.de>
* assuan-uds.c (uds_reader, uds_sendfd): Don't break strict
Modified: trunk/src/system-w32.c
===================================================================
--- trunk/src/system-w32.c 2010-04-16 00:52:49 UTC (rev 370)
+++ trunk/src/system-w32.c 2010-04-19 08:55:19 UTC (rev 371)
@@ -162,40 +162,63 @@
+/* Return true if HD refers to a socket. */
+static int
+is_socket (HANDLE hd)
+{
+ /* 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. */
+}
+
+
static ssize_t
__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
{
- /* Due to the peculiarities of the W32 API we can't use read for a
- network socket and thus we try to use recv first and fallback to
- read if recv detects that it is not a network socket. */
int res;
-
- res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
+ int ec = 0;
+
+ if (is_socket (fd))
+ {
+ res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
+ if (res == -1)
+ ec = WSAGetLastError ();
+ }
+ else
+ {
+ DWORD nread = 0;
+ if (!ReadFile (fd, buffer, size, &nread, NULL))
+ {
+ res = -1;
+ ec = GetLastError ();
+ }
+ else
+ res = nread;
+ }
if (res == -1)
{
- switch (WSAGetLastError ())
+ switch (ec)
{
case WSAENOTSOCK:
- {
- DWORD nread = 0;
-
- res = ReadFile (fd, buffer, size, &nread, NULL);
- if (! res)
- {
- switch (GetLastError ())
- {
- case ERROR_BROKEN_PIPE:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- }
- res = -1;
- }
- else
- res = (int) nread;
- }
+ gpg_err_set_errno (EBADF);
break;
case WSAEWOULDBLOCK:
@@ -220,35 +243,50 @@
__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size)
{
- /* Due to the peculiarities of the W32 API we can't use write for a
- network socket and thus we try to use send first and fallback to
- write if send detects that it is not a network socket. */
int res;
-
- res = send (HANDLE2SOCKET (fd), buffer, size, 0);
- if (res == -1 && WSAGetLastError () == WSAENOTSOCK)
+ int ec = 0;
+
+ if (is_socket (fd))
{
+ res = send (HANDLE2SOCKET (fd), buffer, size, 0);
+ if (res == -1)
+ ec = WSAGetLastError ();
+ }
+ else
+ {
DWORD nwrite;
- res = WriteFile (fd, buffer, size, &nwrite, NULL);
- if (! res)
+ if (!WriteFile (fd, buffer, size, &nwrite, NULL))
{
- switch (GetLastError ())
- {
- case ERROR_BROKEN_PIPE:
- case ERROR_NO_DATA:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- break;
- }
res = -1;
+ ec = GetLastError ();
}
- else
- res = (int) nwrite;
+ else
+ res = (int)nwrite;
}
+ if (res == -1)
+ {
+ switch (ec)
+ {
+ case WSAENOTSOCK:
+ gpg_err_set_errno (EBADF);
+ break;
+
+ case WSAEWOULDBLOCK:
+ gpg_err_set_errno (EAGAIN);
+ break;
+
+ case ERROR_BROKEN_PIPE:
+ case ERROR_NO_DATA:
+ gpg_err_set_errno (EPIPE);
+ break;
+
+ default:
+ gpg_err_set_errno (EIO);
+ break;
+ }
+
+ }
return res;
}
More information about the Gnupg-commits
mailing list