After receiving descriptors with SCM_RIGHTS the socket channel resets
O_NONBLOCK on each of them with fcntl(F_SETFL).  macOS rejects F_SETFL
on POSIX shared memory descriptors, so every message carrying such a
descriptor caused the connection to drop.  Those descriptors are passed
in blocking mode anyway, so there is nothing to change on them.  Query
the flags with F_GETFL first and only issue F_SETFL when O_NONBLOCK is
actually set.

Signed-off-by: Tim Pambor <[email protected]>
---
 io/channel-socket.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/io/channel-socket.c b/io/channel-socket.c
index 7920cee639..1785fd5bfe 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -520,8 +520,23 @@ static bool qio_channel_handle_fds(int *fds, size_t nfds,
         }
 
         if (!preserve_blocking) {
-            /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
-            if (!qemu_set_blocking(*fd, true, errp)) {
+            /*
+             * O_NONBLOCK is preserved across SCM_RIGHTS so reset it.
+             *
+             * Some descriptors reject F_SETFL outright, e.g. POSIX
+             * shared memory on macOS.  They are passed in blocking
+             * mode anyway, so only touch descriptors that have it set.
+             */
+            int flags = fcntl(*fd, F_GETFL);
+
+            if (flags < 0) {
+                error_setg_errno(errp, errno,
+                                 "Can't get file descriptor %d flags", *fd);
+                return false;
+            }
+
+            if ((flags & O_NONBLOCK) &&
+                !qemu_set_blocking(*fd, true, errp)) {
                 return false;
             }
         }

-- 
2.55.0


Reply via email to