From 8a3134d2c32a2932195626e3ea01e5cc008eb5eb Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 20 Sep 2013 10:10:50 +0200 Subject: [PATCH 3/8] core: make sure win32 sockets remain blocking Commit 7e344b5 hade the side effect of forcing every socket to be non-blocking on Windows. This is because of a (documented) side effect of WSAEventSelect(). So we need to make sure to restore blocking behaviour afterwards for relevant sockets. --- src/pulsecore/core-util.c | 64 +++++++++++++++++++++++++++++++++++++++++----- src/pulsecore/core-util.h | 3 +++ src/pulsecore/poll-win32.c | 5 ++++ 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 64578ad..62d1130 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -149,6 +149,10 @@ static pa_strlist *recorded_env = NULL; #ifdef OS_IS_WIN32 +static fd_set nonblocking_fds; +#endif + +#ifdef OS_IS_WIN32 #include "poll.h" @@ -179,30 +183,76 @@ char *pa_win32_get_toplevel(HANDLE handle) { #endif -/** Make a file descriptor nonblock. Doesn't do any error checking */ -void pa_make_fd_nonblock(int fd) { +static void set_nonblock(int fd, bool nonblock) { #ifdef O_NONBLOCK - int v; + int v, nv; pa_assert(fd >= 0); pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0); - if (!(v & O_NONBLOCK)) + if (nonblock) + nv = v | O_NONBLOCK; + else + nv = v & ~O_NONBLOCK; + + if (v != nv) pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0); #elif defined(OS_IS_WIN32) - u_long arg = 1; + u_long arg; + + if (nonblock) + arg = 1; + else + arg = 0; + if (ioctlsocket(fd, FIONBIO, &arg) < 0) { pa_assert_se(WSAGetLastError() == WSAENOTSOCK); pa_log_warn("Only sockets can be made non-blocking!"); + return; } + + /* There is no method to query status, so we remember all fds */ + if (nonblock) + FD_SET(fd, &nonblocking_fds); + else + FD_CLR(fd, &nonblocking_fds); #else pa_log_warn("Non-blocking I/O not supported.!"); #endif } +/** Make a file descriptor nonblock. Doesn't do any error checking */ +void pa_make_fd_nonblock(int fd) { + set_nonblock(fd, true); +} + +/** Make a file descriptor blocking. Doesn't do any error checking */ +void pa_make_fd_block(int fd) { + set_nonblock(fd, false); +} + +/** Query if a file descriptor is non-blocking */ +bool pa_is_fd_nonblock(int fd) { + +#ifdef O_NONBLOCK + int v; + pa_assert(fd >= 0); + + pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0); + + return !!(v & O_NONBLOCK); + +#elif defined(OS_IS_WIN32) + return !!FD_ISSET(fd, &nonblocking_fds); +#else + return false; +#endif + +} + /* Set the FD_CLOEXEC flag for a fd */ void pa_make_fd_cloexec(int fd) { @@ -531,13 +581,15 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { return ret; } -/** Platform independent read function. Necessary since not all +/** Platform independent close function. Necessary since not all * systems treat all file descriptors equal. */ int pa_close(int fd) { #ifdef OS_IS_WIN32 int ret; + FD_CLR(fd, &nonblocking_fds); + if ((ret = closesocket(fd)) == 0) return 0; diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index e117e9f..e6cb261 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -57,6 +57,9 @@ struct timeval; #endif void pa_make_fd_nonblock(int fd); +void pa_make_fd_block(int fd); +bool pa_is_fd_nonblock(int fd); + void pa_make_fd_cloexec(int fd); int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid, bool update_perms); diff --git a/src/pulsecore/poll-win32.c b/src/pulsecore/poll-win32.c index 4256ed7..4a70171 100644 --- a/src/pulsecore/poll-win32.c +++ b/src/pulsecore/poll-win32.c @@ -65,6 +65,8 @@ typedef unsigned long nfds_t; #include +#include + #ifndef INFTIM # define INFTIM (-1) #endif @@ -602,6 +604,9 @@ restart: /* It's a socket. */ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); WSAEventSelect ((SOCKET) h, 0, 0); + /* Have to restore blocking as WSAEventSelect() clears it */ + if (!pa_is_fd_nonblock(pfd[i].fd)) + pa_make_fd_block(pfd[i].fd); /* If we're lucky, WSAEnumNetworkEvents already provided a way to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */ -- 1.8.3.1