]> code.delx.au - pulseaudio/commitdiff
core: make sure win32 sockets remain blocking
authorPierre Ossman <ossman@cendio.se>
Fri, 20 Sep 2013 08:10:50 +0000 (10:10 +0200)
committerTanu Kaskinen <tanu.kaskinen@linux.intel.com>
Fri, 15 Nov 2013 08:53:19 +0000 (10:53 +0200)
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
src/pulsecore/core-util.h
src/pulsecore/poll-win32.c

index e925918954b8c0fcaaaaf7e0820399f356d80e4b..49fcc0ff4b8d14d472e9d7f742804da052090a84 100644 (file)
 
 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;
 
index e117e9f242b1531d6f064b4b6404cc5f375b0bf3..e6cb261bbddc98669043ec30eb418fe304f4beb9 100644 (file)
@@ -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);
index 4256ed75fa07905f3c1a4a4d65d6fc68448d911a..4a70171f71551bbc9c8f761bf706bf66c1d4308c 100644 (file)
@@ -65,6 +65,8 @@ typedef unsigned long nfds_t;
 
 #include <time.h>
 
+#include <pulsecore/core-util.h>
+
 #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.  */