diff options
Diffstat (limited to 'io/channel-socket.c')
| -rw-r--r-- | io/channel-socket.c | 65 |
1 files changed, 52 insertions, 13 deletions
diff --git a/io/channel-socket.c b/io/channel-socket.c index 3b7ca924ff..e53d9ac76f 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -472,7 +472,7 @@ static void qio_channel_socket_copy_fds(struct msghdr *msg, *fds = NULL; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { - int fd_size, i; + int fd_size; int gotfds; if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)) || @@ -490,22 +490,53 @@ static void qio_channel_socket_copy_fds(struct msghdr *msg, gotfds = fd_size / sizeof(int); *fds = g_renew(int, *fds, *nfds + gotfds); memcpy(*fds + *nfds, CMSG_DATA(cmsg), fd_size); + *nfds += gotfds; + } +} - for (i = 0; i < gotfds; i++) { - int fd = (*fds)[*nfds + i]; - if (fd < 0) { - continue; - } +static bool qio_channel_handle_fds(int *fds, size_t nfds, + bool preserve_blocking, Error **errp) +{ + int *end = fds + nfds, *fd; +#ifdef MSG_CMSG_CLOEXEC + if (preserve_blocking) { + /* Nothing to do */ + return true; + } +#endif + + for (fd = fds; fd != end; fd++) { + if (*fd < 0) { + continue; + } + + if (!preserve_blocking) { /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */ - qemu_socket_set_block(fd); + if (!qemu_set_blocking(*fd, true, errp)) { + return false; + } + } #ifndef MSG_CMSG_CLOEXEC - qemu_set_cloexec(fd); + qemu_set_cloexec(*fd); #endif + } + + return true; +} + +static void qio_channel_cleanup_fds(int **fds, size_t *nfds) +{ + for (size_t i = 0; i < *nfds; i++) { + if ((*fds)[i] < 0) { + continue; } - *nfds += gotfds; + close((*fds)[i]); } + + g_clear_pointer(fds, g_free); + *nfds = 0; } @@ -556,7 +587,16 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc, } if (fds && nfds) { + bool preserve_blocking = + flags & QIO_CHANNEL_READ_FLAG_FD_PRESERVE_BLOCKING; + qio_channel_socket_copy_fds(&msg, fds, nfds); + + if (!qio_channel_handle_fds(*fds, *nfds, + preserve_blocking, errp)) { + qio_channel_cleanup_fds(fds, nfds); + return -1; + } } return ret; @@ -820,11 +860,10 @@ qio_channel_socket_set_blocking(QIOChannel *ioc, { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); - if (enabled) { - qemu_socket_set_block(sioc->fd); - } else { - qemu_socket_set_nonblock(sioc->fd); + if (!qemu_set_blocking(sioc->fd, enabled, errp)) { + return -1; } + return 0; } |