diff options
author | Marc-André Lureau <marcandre.lureau@redhat.com> | 2015-11-09 20:29:34 +0100 |
---|---|---|
committer | Marc-André Lureau <marcandre.lureau@gmail.com> | 2016-02-13 11:28:23 +0100 |
commit | 1877229a43c411f4145a767730c617c5714bc979 (patch) | |
tree | 20e7ee5762eeb25a85ad00143594ad49130a38e7 | |
parent | c3b52e0f9557ff5bfa10e6bf895c6a1dda731495 (diff) | |
download | spice-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.h | 3 | ||||
-rw-r--r-- | src/spice-channel.c | 68 |
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. |