summaryrefslogtreecommitdiff
path: root/src/w32-io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/w32-io.c')
-rw-r--r--src/w32-io.c219
1 files changed, 125 insertions, 94 deletions
diff --git a/src/w32-io.c b/src/w32-io.c
index cbc3064..d896ec0 100644
--- a/src/w32-io.c
+++ b/src/w32-io.c
@@ -162,7 +162,9 @@ struct reader_context_s
HANDLE have_data_ev;
/* This is automatically reset. */
HANDLE have_space_ev;
- HANDLE stopped;
+ /* This is manually reset but actually only triggered once. */
+ HANDLE close_ev;
+
size_t readpos, writepos;
char buffer[READBUF_SIZE];
};
@@ -194,7 +196,7 @@ struct writer_context_s
/* This is manually reset. */
HANDLE have_data;
HANDLE is_empty;
- HANDLE stopped;
+ HANDLE close_ev;
size_t nbytes;
char buffer[WRITEBUF_SIZE];
};
@@ -264,8 +266,8 @@ reader (void *arg)
int nbytes;
DWORD nread;
int sock;
- TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
- "thread=%p", ctx->thread_hd);
+ TRACE_BEG2 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
+ "file_sock=%d, thread=%p", ctx->file_sock, ctx->thread_hd);
if (ctx->file_hd != INVALID_HANDLE_VALUE)
sock = 0;
@@ -316,6 +318,21 @@ reader (void *arg)
}
else
{
+ /* Check whether the shutdown triggered the error -
+ no need to to print a warning in this case. */
+ if ( ctx->error_code == WSAECONNABORTED
+ || ctx->error_code == WSAECONNRESET)
+ {
+ LOCK (ctx->mutex);
+ if (ctx->stop_me)
+ {
+ UNLOCK (ctx->mutex);
+ TRACE_LOG ("got shutdown");
+ break;
+ }
+ UNLOCK (ctx->mutex);
+ }
+
ctx->error = 1;
TRACE_LOG1 ("recv error: ec=%d", ctx->error_code);
}
@@ -357,6 +374,7 @@ reader (void *arg)
UNLOCK (ctx->mutex);
break;
}
+
TRACE_LOG1 ("got %u bytes", nread);
ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
@@ -367,9 +385,18 @@ reader (void *arg)
}
/* Indicate that we have an error or EOF. */
if (!SetEvent (ctx->have_data_ev))
- TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
- (int) GetLastError ());
- SetEvent (ctx->stopped);
+ TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
+ (int) GetLastError ());
+
+ TRACE_LOG ("waiting for close");
+ WaitForSingleObject (ctx->close_ev, INFINITE);
+
+ CloseHandle (ctx->close_ev);
+ CloseHandle (ctx->have_data_ev);
+ CloseHandle (ctx->have_space_ev);
+ CloseHandle (ctx->thread_hd);
+ DESTROY_LOCK (ctx->mutex);
+ free (ctx);
return TRACE_SUC ();
}
@@ -400,6 +427,9 @@ create_reader (int fd)
TRACE_SYSERR (EIO);
return NULL;
}
+ TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d",
+ fd, fd_table[fd].handle, fd_table[fd].socket,
+ fd_table[fd].dup_from);
ctx->file_hd = fd_table[fd].handle;
ctx->file_sock = fd_table[fd].socket;
@@ -408,16 +438,16 @@ create_reader (int fd)
if (ctx->have_data_ev)
ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
if (ctx->have_space_ev)
- ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
- if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->stopped)
+ ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+ if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->close_ev)
{
TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
if (ctx->have_data_ev)
CloseHandle (ctx->have_data_ev);
if (ctx->have_space_ev)
CloseHandle (ctx->have_space_ev);
- if (ctx->stopped)
- CloseHandle (ctx->stopped);
+ if (ctx->close_ev)
+ CloseHandle (ctx->close_ev);
free (ctx);
/* FIXME: Translate the error code. */
TRACE_SYSERR (EIO);
@@ -442,8 +472,8 @@ create_reader (int fd)
CloseHandle (ctx->have_data_ev);
if (ctx->have_space_ev)
CloseHandle (ctx->have_space_ev);
- if (ctx->stopped)
- CloseHandle (ctx->stopped);
+ if (ctx->close_ev)
+ CloseHandle (ctx->close_ev);
free (ctx);
TRACE_SYSERR (EIO);
return NULL;
@@ -461,6 +491,9 @@ create_reader (int fd)
}
+/* Prepare destruction of the reader thread for CTX. Returns 0 if a
+ call to this function is sufficient and destroy_reader_finish shall
+ not be called. */
static void
destroy_reader (struct reader_context_s *ctx)
{
@@ -492,24 +525,32 @@ destroy_reader (struct reader_context_s *ctx)
}
#endif
- TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
- "waiting for termination of thread %p", ctx->thread_hd);
- WaitForSingleObject (ctx->stopped, INFINITE);
- TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
- "thread %p has terminated", ctx->thread_hd);
+ /* The reader thread is usually blocking in recv or ReadFile. If
+ the peer does not send an EOF or breaks the pipe the WFSO might
+ get stuck waiting for the termination of the reader thread. This
+ happens quite often with sockets, thus we definitely need to get
+ out of the recv. A shutdown does this nicely. For handles
+ (i.e. pipes) it would also be nice to cancel the operation, but
+ such a feature is only available since Vista. Thus we need to
+ dlopen that syscall. */
+ if (ctx->file_hd != INVALID_HANDLE_VALUE)
+ {
+ /* Fixme: Call CancelSynchronousIo (handle_of_thread). */
+ }
+ else if (ctx->file_sock != INVALID_SOCKET)
+ {
+ if (shutdown (ctx->file_sock, 2))
+ TRACE2 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
+ "shutdown socket %d failed: %s",
+ ctx->file_sock, (int) WSAGetLastError ());
+ }
- if (ctx->stopped)
- CloseHandle (ctx->stopped);
- if (ctx->have_data_ev)
- CloseHandle (ctx->have_data_ev);
- if (ctx->have_space_ev)
- CloseHandle (ctx->have_space_ev);
- CloseHandle (ctx->thread_hd);
- DESTROY_LOCK (ctx->mutex);
- free (ctx);
+ /* After setting this event CTX is void. */
+ SetEvent (ctx->close_ev);
}
+
/* Find a reader context or create a new one. Note that the reader
context will last until a _gpgme_io_close. */
static struct reader_context_s *
@@ -546,26 +587,6 @@ find_reader (int fd, int start_it)
}
-static void
-kill_reader (int fd)
-{
- int i;
-
- LOCK (reader_table_lock);
- for (i = 0; i < reader_table_size; i++)
- {
- if (reader_table[i].used && reader_table[i].fd == fd)
- {
- destroy_reader (reader_table[i].context);
- reader_table[i].context = NULL;
- reader_table[i].used = 0;
- break;
- }
- }
- UNLOCK (reader_table_lock);
-}
-
-
int
_gpgme_io_read (int fd, void *buffer, size_t count)
{
@@ -652,8 +673,8 @@ writer (void *arg)
struct writer_context_s *ctx = arg;
DWORD nwritten;
int sock;
- TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
- "thread=%p", ctx->thread_hd);
+ TRACE_BEG2 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
+ "file_sock=%d, thread=%p", ctx->file_sock, ctx->thread_hd);
if (ctx->file_hd != INVALID_HANDLE_VALUE)
sock = 0;
@@ -735,7 +756,16 @@ writer (void *arg)
/* Indicate that we have an error. */
if (!SetEvent (ctx->is_empty))
TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
- SetEvent (ctx->stopped);
+
+ TRACE_LOG ("waiting for close");
+ WaitForSingleObject (ctx->close_ev, INFINITE);
+
+ CloseHandle (ctx->close_ev);
+ CloseHandle (ctx->have_data);
+ CloseHandle (ctx->is_empty);
+ CloseHandle (ctx->thread_hd);
+ DESTROY_LOCK (ctx->mutex);
+ free (ctx);
return TRACE_SUC ();
}
@@ -766,6 +796,9 @@ create_writer (int fd)
TRACE_SYSERR (EIO);
return NULL;
}
+ TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d",
+ fd, fd_table[fd].handle, fd_table[fd].socket,
+ fd_table[fd].dup_from);
ctx->file_hd = fd_table[fd].handle;
ctx->file_sock = fd_table[fd].socket;
@@ -774,16 +807,16 @@ create_writer (int fd)
if (ctx->have_data)
ctx->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
if (ctx->is_empty)
- ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
- if (!ctx->have_data || !ctx->is_empty || !ctx->stopped)
+ ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+ if (!ctx->have_data || !ctx->is_empty || !ctx->close_ev)
{
TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
if (ctx->have_data)
CloseHandle (ctx->have_data);
if (ctx->is_empty)
CloseHandle (ctx->is_empty);
- if (ctx->stopped)
- CloseHandle (ctx->stopped);
+ if (ctx->close_ev)
+ CloseHandle (ctx->close_ev);
free (ctx);
/* FIXME: Translate the error code. */
TRACE_SYSERR (EIO);
@@ -808,8 +841,8 @@ create_writer (int fd)
CloseHandle (ctx->have_data);
if (ctx->is_empty)
CloseHandle (ctx->is_empty);
- if (ctx->stopped)
- CloseHandle (ctx->stopped);
+ if (ctx->close_ev)
+ CloseHandle (ctx->close_ev);
free (ctx);
TRACE_SYSERR (EIO);
return NULL;
@@ -826,6 +859,7 @@ create_writer (int fd)
return ctx;
}
+
static void
destroy_writer (struct writer_context_s *ctx)
{
@@ -855,21 +889,8 @@ destroy_writer (struct writer_context_s *ctx)
}
#endif
- TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
- "waiting for termination of thread %p", ctx->thread_hd);
- WaitForSingleObject (ctx->stopped, INFINITE);
- TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
- "thread %p has terminated", ctx->thread_hd);
-
- if (ctx->stopped)
- CloseHandle (ctx->stopped);
- if (ctx->have_data)
- CloseHandle (ctx->have_data);
- if (ctx->is_empty)
- CloseHandle (ctx->is_empty);
- CloseHandle (ctx->thread_hd);
- DESTROY_LOCK (ctx->mutex);
- free (ctx);
+ /* After setting this event CTX is void. */
+ SetEvent (ctx->close_ev);
}
@@ -909,26 +930,6 @@ find_writer (int fd, int start_it)
}
-static void
-kill_writer (int fd)
-{
- int i;
-
- LOCK (writer_table_lock);
- for (i = 0; i < writer_table_size; i++)
- {
- if (writer_table[i].used && writer_table[i].fd == fd)
- {
- destroy_writer (writer_table[i].context);
- writer_table[i].context = NULL;
- writer_table[i].used = 0;
- break;
- }
- }
- UNLOCK (writer_table_lock);
-}
-
-
int
_gpgme_io_write (int fd, const void *buffer, size_t count)
{
@@ -1149,8 +1150,36 @@ _gpgme_io_close (int fd)
return TRACE_SYSRES (-1);
}
- kill_reader (fd);
- kill_writer (fd);
+ TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d",
+ fd, fd_table[fd].handle, fd_table[fd].socket,
+ fd_table[fd].dup_from);
+
+ LOCK (reader_table_lock);
+ for (i = 0; i < reader_table_size; i++)
+ {
+ if (reader_table[i].used && reader_table[i].fd == fd)
+ {
+ destroy_reader (reader_table[i].context);
+ reader_table[i].context = NULL;
+ reader_table[i].used = 0;
+ break;
+ }
+ }
+ UNLOCK (reader_table_lock);
+
+ LOCK (writer_table_lock);
+ for (i = 0; i < writer_table_size; i++)
+ {
+ if (writer_table[i].used && writer_table[i].fd == fd)
+ {
+ destroy_writer (writer_table[i].context);
+ writer_table[i].context = NULL;
+ writer_table[i].used = 0;
+ break;
+ }
+ }
+ UNLOCK (writer_table_lock);
+
LOCK (notify_table_lock);
for (i = 0; i < DIM (notify_table); i++)
{
@@ -1544,7 +1573,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
args = calloc (2 + i + 1, sizeof (*args));
args[0] = (char *) _gpgme_get_w32spawn_path ();
args[1] = tmp_name;
- args[2] = path;
+ args[2] = (char *)path;
memcpy (&args[3], &argv[1], i * sizeof (*args));
memset (&sec_attr, 0, sizeof sec_attr);
@@ -1734,7 +1763,9 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
"nfds=%u, nonblock=%u", nfds, nonblock);
+#if 0
restart:
+#endif
TRACE_SEQ (dbg_help, "select on [ ");
any = 0;
nwait = 0;