<div dir="ltr"><div>Hi,</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>virSocketRecvFD()<br>
{<br>
int fds[1];<br>
<br>
virSocketRecvMultipleFDs(sock, fds, 1, fdflags);<br>
return fds[0];<br>
}</div></blockquote><div>Yea, it's a good idea. <br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Aug 20, 2021 at 3:57 PM Michal Prívozník <<a href="mailto:mprivozn@redhat.com">mprivozn@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 7/28/21 10:17 AM, Andrew Melnychenko wrote:<br>
> Similar to virSocketRecvFD() added virSocketRecvMultipleFDs().<br>
> This function returns multiple fds through unix socket.<br>
> New function is required for "qemu-ebpf-rss-helper" program.<br>
> The helper may pass few file descriptors - eBPF program and maps.<br>
> <br>
> Signed-off-by: Andrew Melnychenko <<a href="mailto:andrew@daynix.com" target="_blank">andrew@daynix.com</a>><br>
> ---<br>
> src/libvirt_private.syms | 1 +<br>
> src/util/virsocket.c | 83 ++++++++++++++++++++++++++++++++++++++++<br>
> src/util/virsocket.h | 2 +<br>
> 3 files changed, 86 insertions(+)<br>
> <br>
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms<br>
> index 43493ea76e..6987ff00c2 100644<br>
> --- a/src/libvirt_private.syms<br>
> +++ b/src/libvirt_private.syms<br>
> @@ -3226,6 +3226,7 @@ virSecureEraseString;<br>
> # util/virsocket.h<br>
> virSocketRecvFD;<br>
> virSocketSendFD;<br>
> +virSocketRecvMultipleFDs;<br>
<br>
This needs to be ordered. The correct order is:<br>
<br>
# util/virsocket.h<br>
virSocketRecvFD;<br>
virSocketRecvMultipleFDs;<br>
virSocketSendFD;<br>
<br>
<br>
> <br>
> <br>
> # util/virsocketaddr.h<br>
> diff --git a/src/util/virsocket.c b/src/util/virsocket.c<br>
> index b971da16e3..da8af42e72 100644<br>
> --- a/src/util/virsocket.c<br>
> +++ b/src/util/virsocket.c<br>
> @@ -486,6 +486,82 @@ virSocketRecvFD(int sock, int fdflags)<br>
> <br>
> return fd;<br>
> }<br>
> +<br>
> +<br>
> +/* virSocketRecvMultipleFDs receives few file descriptors through the socket.<br>
> + The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).<br>
> +<br>
> + Return the number of recived file descriptors on success,<br>
> + or -1 with errno set in case of error.<br>
> +*/<br>
> +int<br>
> +virSocketRecvMultipleFDs(int sock, int *fds, size_t nfds, int fdflags)<br>
> +{<br>
> + char byte = 0;<br>
> + struct iovec iov;<br>
> + struct msghdr msg;<br>
> + int ret = -1;<br>
> + ssize_t len;<br>
> + struct cmsghdr *cmsg;<br>
> + char buf[CMSG_SPACE(sizeof(int) * nfds)];<br>
> + int fdflags_recvmsg = fdflags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;<br>
> + int fdSize = -1;<br>
> + int i = 0;<br>
> + int saved_errno = 0;<br>
> +<br>
> + if ((fdflags & ~O_CLOEXEC) != 0) {<br>
> + errno = EINVAL;<br>
> + return -1;<br>
> + }<br>
> +<br>
> + /* send at least one char */<br>
> + memset(&msg, 0, sizeof(msg));<br>
> + iov.iov_base = &byte;<br>
> + iov.iov_len = 1;<br>
> + msg.msg_iov = &iov;<br>
> + msg.msg_iovlen = 1;<br>
> + msg.msg_name = NULL;<br>
> + msg.msg_namelen = 0;<br>
> +<br>
> + msg.msg_control = buf;<br>
> + msg.msg_controllen = sizeof(buf);<br>
> +<br>
> + len = recvmsg(sock, &msg, fdflags_recvmsg);<br>
> + if (len < 0) {<br>
> + return -1;<br>
> + }<br>
> +<br>
> + cmsg = CMSG_FIRSTHDR(&msg);<br>
> + /* be paranoiac */<br>
> + if (len == 0 || cmsg == NULL || cmsg->cmsg_len < CMSG_LEN(sizeof(int))<br>
> + || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {<br>
> + /* fake errno: at end the file is not available */<br>
> + errno = len ? EACCES : ENOTCONN;<br>
> + return -1;<br>
> + }<br>
> +<br>
> + fdSize = cmsg->cmsg_len - CMSG_LEN(0);<br>
> + memcpy(fds, CMSG_DATA(cmsg), fdSize);<br>
> + ret = fdSize/sizeof(int);<br>
<br>
Please put a space before and after '/'. Like this:<br>
<br>
ret = fdSize / sizeof(int);<br>
<br>
> +<br>
> + /* set close-on-exec flag */<br>
> + if (!MSG_CMSG_CLOEXEC && (fdflags & O_CLOEXEC)) {<br>
> + for (i = 0; i < ret; ++i) {<br>
> + if (virSetCloseExec(fds[i]) < 0) {<br>
> + saved_errno = errno;<br>
<br>
This isn't needed really, because ..<br>
<br>
> + goto error;<br>
> + }<br>
> + }<br>
> + }<br>
> +<br>
> + return ret;<br>
> +error:<br>
> + for (i = 0; i < ret; ++i) {<br>
> + VIR_FORCE_CLOSE(fds[i]);<br>
<br>
.. VIR_FORCE_CLOSE() doesn't change errno.<br>
<br>
> + }<br>
> + errno = saved_errno;<br>
> + return -1;<br>
> +}<br>
<br>
But I wonder if this function is needed. I mean, we currently have<br>
virSocketRecvFD() and this new function looks very much like it. Would<br>
it be possible to turn virSocketRecvFD() into virSocketRecvMultipleFDs()<br>
and fix all (current) callers of virSocketRecvFD()?<br>
<br>
Alternatively, we can have virSocketRecvMultipleFDs() as you propose and<br>
then virSocketRecvFD() be just a thin wrapper over<br>
virSocketRecvMultipleFDs(), e.g. like this:<br>
<br>
virSocketRecvFD()<br>
{<br>
int fds[1];<br>
<br>
virSocketRecvMultipleFDs(sock, fds, 1, fdflags);<br>
return fds[0];<br>
}<br>
<br>
Or even better, have virSocketRecvFD() return FD via argument and its<br>
retval be 0/-1 (success/fail).<br>
<br>
My aim is to avoid having nearly the same code twice.<br>
<br>
Michal<br>
<br>
</blockquote></div>