[RFC PATCH 04/10] virsocket: Added receive for multiple fds.

Andrew Melnychenko andrew at daynix.com
Wed Jul 28 08:17:08 UTC 2021


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 at 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




More information about the libvir-list mailing list