aboutsummaryrefslogtreecommitdiffstats
path: root/src/w32-io.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2010-04-16 14:08:41 +0000
committerWerner Koch <[email protected]>2010-04-16 14:08:41 +0000
commit779823c09cba151c3eb9043bc8ce28adb0dd737d (patch)
treeb6434ab36dc404a4423032be5dace321a76fb988 /src/w32-io.c
parentMake generated header file read-only in an emacs buffer. (diff)
downloadgpgme-779823c09cba151c3eb9043bc8ce28adb0dd737d.tar.gz
gpgme-779823c09cba151c3eb9043bc8ce28adb0dd737d.zip
More robust detection of handle and sockets
Diffstat (limited to 'src/w32-io.c')
-rw-r--r--src/w32-io.c66
1 files changed, 46 insertions, 20 deletions
diff --git a/src/w32-io.c b/src/w32-io.c
index 762d617f..d05db702 100644
--- a/src/w32-io.c
+++ b/src/w32-io.c
@@ -1,6 +1,6 @@
/* w32-io.c - W32 API I/O functions.
Copyright (C) 2000 Werner Koch (dd9jn)
- Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
+ Copyright (C) 2001, 2002, 2003, 2004, 2007, 2010 g10 Code GmbH
This file is part of GPGME.
@@ -175,16 +175,46 @@ set_synchronize (HANDLE hd)
}
+/* 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 DWORD CALLBACK
reader (void *arg)
{
struct reader_context_s *ctx = arg;
int nbytes;
DWORD nread;
- int try_recv = 1;
+ int sock;
TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
"thread=%p", ctx->thread_hd);
+ sock = is_socket (ctx->file_hd);
+
for (;;)
{
LOCK (ctx->mutex);
@@ -212,17 +242,15 @@ reader (void *arg)
nbytes = READBUF_SIZE - ctx->writepos;
UNLOCK (ctx->mutex);
- TRACE_LOG1 ("reading %d bytes", nbytes);
+ TRACE_LOG2 ("%s %d bytes", sock? "receiving":"reading", nbytes);
- if (try_recv)
+ if (sock)
{
int n;
n = recv (handle_to_socket (ctx->file_hd),
ctx->buffer + ctx->writepos, nbytes, 0);
- if (n < 0 && WSAGetLastError () == WSAENOTSOCK)
- try_recv = 0;
- else if (n < 0)
+ if (n < 0)
{
ctx->error_code = (int) WSAGetLastError ();
if (ctx->error_code == ERROR_BROKEN_PIPE)
@@ -237,11 +265,9 @@ reader (void *arg)
}
break;
}
- else
- nread = n;
-
+ nread = n;
}
- if (!try_recv)
+ else
{
if (!ReadFile (ctx->file_hd,
ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
@@ -540,10 +566,12 @@ writer (void *arg)
{
struct writer_context_s *ctx = arg;
DWORD nwritten;
- int try_send = 1;
+ int sock;
TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
"thread=%p", ctx->thread_hd);
+ sock = is_socket (ctx->file_hd);
+
for (;;)
{
LOCK (ctx->mutex);
@@ -571,11 +599,12 @@ writer (void *arg)
}
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
_gpgme_io_write always writes at least 1 byte before waking
us up, unless CTX->stop_me is true, which we catch above. */
- if (try_send)
+ if (sock)
{
/* We need to try send first because a socket handle can't
be used with WriteFile. */
@@ -583,19 +612,16 @@ writer (void *arg)
n = send (handle_to_socket (ctx->file_hd),
ctx->buffer, ctx->nbytes, 0);
- if (n < 0 && WSAGetLastError () == WSAENOTSOCK)
- try_send = 0;
- else if (n < 0)
+ if (n < 0)
{
ctx->error_code = (int) WSAGetLastError ();
ctx->error = 1;
TRACE_LOG1 ("send error: ec=%d", ctx->error_code);
break;
}
- else
- nwritten = n;
+ nwritten = n;
}
- if (!try_send)
+ else
{
if (!WriteFile (ctx->file_hd, ctx->buffer,
ctx->nbytes, &nwritten, NULL))