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