static ssize_t _hostsock_recvmsg(
    oe_fd_t* sock_,
    struct oe_msghdr* msg,
    int flags)
{
    ssize_t ret = -1;
    sock_t* sock = _cast_sock(sock_);
    oe_errno = 0;
    void* buf = NULL;
    size_t buf_size = 0;
    size_t data_size = 0;
    oe_socklen_t namelen_out = 0;
    size_t controllen_out = 0;

    /* Check the parameters. */
    if (!sock || !msg || (msg->msg_iovlen && !msg->msg_iov))
        OE_RAISE_ERRNO(OE_EINVAL);

    /* Flatten the IO vector into contiguous heap memory. */
    if (oe_iov_pack(
            msg->msg_iov, (int)msg->msg_iovlen, &buf, &buf_size, &data_size) !=
        0)
        OE_RAISE_ERRNO(OE_ENOMEM);

    /*
     * According to the POSIX specification, when the data_size is greater
     * than SSIZE_MAX, the result is implementation-defined. OE raises an
     * error in this case.
     * Refer to
     * https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html
     * for more detail.
     */
    if (data_size > OE_SSIZE_MAX)
        OE_RAISE_ERRNO(OE_EINVAL);

    /* Call the host. */
    {
        if (oe_syscall_recvmsg_ocall(
                &ret,
                sock->host_fd,
                msg->msg_name,
                msg->msg_namelen,
                &namelen_out,
                buf,
                msg->msg_iovlen,
                buf_size,
                msg->msg_control,
                msg->msg_controllen,
                &controllen_out,
                flags) != OE_OK)
        {
            OE_RAISE_ERRNO(OE_EINVAL);
        }

        if (ret == -1)
            OE_RAISE_ERRNO(oe_errno);
    }

    if (!msg->msg_name)
        msg->msg_namelen = 0;
    else
    {
        /*
         * Error out the case if the namelen_out is greater than the size
         * of sockaddr_storage.
         */
        if (namelen_out > sizeof(struct oe_sockaddr_storage))
            OE_RAISE_ERRNO(OE_EINVAL);

        /*
         * Note that the returned value can still exceed the supplied one,
         * which indicates a truncation.
         */
        if (msg->msg_namelen >= namelen_out)
            msg->msg_namelen = namelen_out;
    }

    if (!msg->msg_control)
        msg->msg_controllen = 0;
    else
    {
        /*
         * Update the msg_controllen only if the supplied value is greater than
         * or equal to the returned value. Otherwise, keep the msg_controllen
         * unchanged, which indicates a truncation. In addition, explicitly
         * setting the MSG_CTRUNC flag when the truncation occurs.
         */
        if (msg->msg_controllen >= controllen_out)
            msg->msg_controllen = controllen_out;
        else
            msg->msg_flags |= OE_MSG_CTRUNC;
    }

    /*
     * Guard the special case that a host sets an arbitrarily large value.
     * The return value should not exceed data_size.
     */
    if (ret > (ssize_t)data_size)
    {
        ret = -1;
        OE_RAISE_ERRNO(OE_EINVAL);
    }

    /* Synchronize data read with IO vector. */
    if (oe_iov_sync(msg->msg_iov, (int)msg->msg_iovlen, buf, buf_size) != 0)
        OE_RAISE_ERRNO(OE_EINVAL);

done:

    if (buf)
        oe_free(buf);

    return ret;
}
static ssize_t _hostsock_recvmsg(
    oe_fd_t* sock_,
    struct oe_msghdr* msg,
    int flags)
{
    ssize_t ret = -1;
    sock_t* sock = _cast_sock(sock_);
    oe_errno = 0;
    void* buf = NULL;
    size_t buf_size = 0;
    size_t data_size = 0;
    oe_socklen_t namelen_out = 0;
    size_t controllen_out = 0;

     
    if (!sock || !msg || (msg->msg_iovlen && !msg->msg_iov))
        OE_RAISE_ERRNO(OE_EINVAL);

     
    if (oe_iov_pack(
            msg->msg_iov, (int)msg->msg_iovlen, &buf, &buf_size, &data_size) !=
        0)
        OE_RAISE_ERRNO(OE_ENOMEM);

     
    if (data_size > OE_SSIZE_MAX)
        OE_RAISE_ERRNO(OE_EINVAL);

     
    {
        if (oe_syscall_recvmsg_ocall(
                &ret,
                sock->host_fd,
                msg->msg_name,
                msg->msg_namelen,
                &namelen_out,
                buf,
                msg->msg_iovlen,
                buf_size,
                msg->msg_control,
                msg->msg_controllen,
                &controllen_out,
                flags) != OE_OK)
        {
            OE_RAISE_ERRNO(OE_EINVAL);
        }

        if (ret == -1)
            OE_RAISE_ERRNO(oe_errno);
    }

    if (!msg->msg_name)
        msg->msg_namelen = 0;
    else
    {
         
        if (namelen_out > sizeof(struct oe_sockaddr_storage))
            OE_RAISE_ERRNO(OE_EINVAL);

         
        if (msg->msg_namelen >= namelen_out)
            msg->msg_namelen = namelen_out;
    }

    if (!msg->msg_control)
        msg->msg_controllen = 0;
    else
    {
         
        if (msg->msg_controllen >= controllen_out)
            msg->msg_controllen = controllen_out;
        else
            msg->msg_flags |= OE_MSG_CTRUNC;
    }

     
    if (ret > (ssize_t)data_size)
    {
        ret = -1;
        OE_RAISE_ERRNO(OE_EINVAL);
    }

     
    if (oe_iov_sync(msg->msg_iov, (int)msg->msg_iovlen, buf, buf_size) != 0)
        OE_RAISE_ERRNO(OE_EINVAL);

done:

    if (buf)
        oe_free(buf);

    return ret;
}