summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2015-11-09 20:29:34 +0100
committerMarc-André Lureau <marcandre.lureau@gmail.com>2016-02-13 11:28:23 +0100
commit1877229a43c411f4145a767730c617c5714bc979 (patch)
tree20e7ee5762eeb25a85ad00143594ad49130a38e7
parentc3b52e0f9557ff5bfa10e6bf895c6a1dda731495 (diff)
downloadspice-gtk-1877229a43c411f4145a767730c617c5714bc979.tar.gz
spice-gtk-1877229a43c411f4145a767730c617c5714bc979.tar.xz
spice-gtk-1877229a43c411f4145a767730c617c5714bc979.zip
Add spice_channel_unix_read_fd()
Utility function used in the messages with socket ancillary fd. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
-rw-r--r--src/spice-channel-priv.h3
-rw-r--r--src/spice-channel.c68
2 files changed, 71 insertions, 0 deletions
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 1941b1b..7eda96a 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 != NULL;
+ 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.