[Spice-devel] [PATCH v4 2/5] Add spice_channel_unix_read_fd()

Marc-André Lureau marcandre.lureau at gmail.com
Thu Feb 4 23:36:49 UTC 2016


From: Marc-André Lureau <marcandre.lureau at redhat.com>

Utility function used in the messages with socket ancillary fd.

Signed-off-by: Marc-André Lureau <marcandre.lureau at redhat.com>
---
 src/spice-channel-priv.h |  3 +++
 src/spice-channel.c      | 68 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)

diff --git a/src/spice-channel-priv.h b/src/spice-channel-priv.h
index d60ea73..526b661 100644
--- a/src/spice-channel-priv.h
+++ b/src/spice-channel-priv.h
@@ -205,6 +205,9 @@ void spice_vmc_write_async(SpiceChannel *self,
                            gpointer user_data);
 gssize spice_vmc_write_finish(SpiceChannel *self,
                               GAsyncResult *result, GError **error);
+#ifdef G_OS_UNIX
+gint spice_channel_unix_read_fd(SpiceChannel *channel);
+#endif
 
 G_END_DECLS
 
diff --git a/src/spice-channel.c b/src/spice-channel.c
index ff85715..db2e5c2 100644
--- a/src/spice-channel.c
+++ b/src/spice-channel.c
@@ -872,6 +872,74 @@ static void spice_channel_write_msg(SpiceChannel *channel, SpiceMsgOut *out)
     spice_msg_out_unref(out);
 }
 
+#ifdef G_OS_UNIX
+static ssize_t read_fd(int fd, int *msgfd)
+{
+    struct msghdr msg = { NULL, };
+    struct iovec iov[1];
+    union {
+        struct cmsghdr cmsg;
+        char control[CMSG_SPACE(sizeof(int))];
+    } msg_control;
+    struct cmsghdr *cmsg;
+    ssize_t ret;
+    char c;
+
+    iov[0].iov_base = &c;
+    iov[0].iov_len = 1;
+
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &msg_control;
+    msg.msg_controllen = sizeof(msg_control);
+
+    ret = recvmsg(fd, &msg, 0);
+    if (ret > 0) {
+        for (cmsg = CMSG_FIRSTHDR(&msg);
+             cmsg;
+             cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+            if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+                cmsg->cmsg_level != SOL_SOCKET ||
+                cmsg->cmsg_type != SCM_RIGHTS) {
+                continue;
+            }
+
+            memcpy(msgfd, CMSG_DATA(cmsg), sizeof(int));
+            if (*msgfd < 0) {
+                continue;
+            }
+        }
+    }
+    return ret;
+}
+
+G_GNUC_INTERNAL
+gint spice_channel_unix_read_fd(SpiceChannel *channel)
+{
+    SpiceChannelPrivate *c = channel->priv;
+    gint fd = -1;
+
+    g_return_val_if_fail(g_socket_get_family(c->sock) == G_SOCKET_FAMILY_UNIX, -1);
+
+    while (1) {
+        /* g_socket_receive_message() is not convenient here because it
+         * reads all control messages, and overly complicated to deal with */
+        if (read_fd(g_socket_get_fd(c->sock), &fd) > 0) {
+            break;
+        }
+
+        if (errno == EWOULDBLOCK) {
+            g_coroutine_socket_wait(&c->coroutine, c->sock, G_IO_IN);
+        } else {
+            g_warning("failed to get fd: %s", g_strerror(errno));
+            return -1;
+        }
+    }
+
+    return fd;
+}
+#endif
+
 /*
  * Read at least 1 more byte of data straight off the wire
  * into the requested buffer.
-- 
2.5.0



More information about the Spice-devel mailing list