Similar to virSocketRecvFD() added virSocketRecvMultipleFDs().
This function returns multiple fds through unix socket.
New function is required for "qemu-ebpf-rss-helper" program.
The helper may pass few file descriptors - eBPF program and maps.
Signed-off-by: Andrew Melnychenko <andrew(a)daynix.com>
---
src/libvirt_private.syms | 1 +
src/util/virsocket.c | 83 ++++++++++++++++++++++++++++++++++++++++
src/util/virsocket.h | 2 +
3 files changed, 86 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 43493ea76e..6987ff00c2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -3226,6 +3226,7 @@ virSecureEraseString;
# util/virsocket.h
virSocketRecvFD;
virSocketSendFD;
+virSocketRecvMultipleFDs;
# util/virsocketaddr.h
diff --git a/src/util/virsocket.c b/src/util/virsocket.c
index b971da16e3..da8af42e72 100644
--- a/src/util/virsocket.c
+++ b/src/util/virsocket.c
@@ -486,6 +486,82 @@ virSocketRecvFD(int sock, int fdflags)
return fd;
}
+
+
+/* virSocketRecvMultipleFDs receives few file descriptors through the socket.
+ The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).
+
+ Return the number of recived file descriptors on success,
+ or -1 with errno set in case of error.
+*/
+int
+virSocketRecvMultipleFDs(int sock, int *fds, size_t nfds, int fdflags)
+{
+ char byte = 0;
+ struct iovec iov;
+ struct msghdr msg;
+ int ret = -1;
+ ssize_t len;
+ struct cmsghdr *cmsg;
+ char buf[CMSG_SPACE(sizeof(int) * nfds)];
+ int fdflags_recvmsg = fdflags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;
+ int fdSize = -1;
+ int i = 0;
+ int saved_errno = 0;
+
+ if ((fdflags & ~O_CLOEXEC) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* send at least one char */
+ memset(&msg, 0, sizeof(msg));
+ iov.iov_base = &byte;
+ iov.iov_len = 1;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+
+ len = recvmsg(sock, &msg, fdflags_recvmsg);
+ if (len < 0) {
+ return -1;
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ /* be paranoiac */
+ if (len == 0 || cmsg == NULL || cmsg->cmsg_len < CMSG_LEN(sizeof(int))
+ || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+ /* fake errno: at end the file is not available */
+ errno = len ? EACCES : ENOTCONN;
+ return -1;
+ }
+
+ fdSize = cmsg->cmsg_len - CMSG_LEN(0);
+ memcpy(fds, CMSG_DATA(cmsg), fdSize);
+ ret = fdSize/sizeof(int);
+
+ /* set close-on-exec flag */
+ if (!MSG_CMSG_CLOEXEC && (fdflags & O_CLOEXEC)) {
+ for (i = 0; i < ret; ++i) {
+ if (virSetCloseExec(fds[i]) < 0) {
+ saved_errno = errno;
+ goto error;
+ }
+ }
+ }
+
+ return ret;
+error:
+ for (i = 0; i < ret; ++i) {
+ VIR_FORCE_CLOSE(fds[i]);
+ }
+ errno = saved_errno;
+ return -1;
+}
#else /* WIN32 */
int
virSocketSendFD(int sock G_GNUC_UNUSED, int fd G_GNUC_UNUSED)
@@ -500,4 +576,11 @@ virSocketRecvFD(int sock G_GNUC_UNUSED, int fdflags G_GNUC_UNUSED)
errno = ENOSYS;
return -1;
}
+
+int
+virSocketRecvMultipleFDs(int sock, int *fds, size_t nfds, int fdflags)
+{
+ errno = ENOSYS;
+ return -1;
+}
#endif /* WIN32 */
diff --git a/src/util/virsocket.h b/src/util/virsocket.h
index 419da8b3ae..c926effbc3 100644
--- a/src/util/virsocket.h
+++ b/src/util/virsocket.h
@@ -22,6 +22,8 @@
int virSocketSendFD(int sock, int fd);
int virSocketRecvFD(int sock, int fdflags);
+int
+virSocketRecvMultipleFDs(int sock, int *fds, size_t nfds, int fdflags);
#ifdef WIN32
--
2.31.1