From 670d9afb902f264b6410d307c429f02ed8685fd3 Mon Sep 17 00:00:00 2001 From: JinWang An Date: Wed, 1 Dec 2021 16:54:34 +0900 Subject: Imported Upstream version 1.4.2 --- src/w32-io.c | 219 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 125 insertions(+), 94 deletions(-) (limited to 'src/w32-io.c') 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; -- cgit v1.2.3