diff options
Diffstat (limited to 'vendor/rustix/src/net/send_recv')
| -rw-r--r-- | vendor/rustix/src/net/send_recv/mod.rs | 380 | ||||
| -rw-r--r-- | vendor/rustix/src/net/send_recv/msg.rs | 966 | 
2 files changed, 1346 insertions, 0 deletions
diff --git a/vendor/rustix/src/net/send_recv/mod.rs b/vendor/rustix/src/net/send_recv/mod.rs new file mode 100644 index 0000000..cad2d5c --- /dev/null +++ b/vendor/rustix/src/net/send_recv/mod.rs @@ -0,0 +1,380 @@ +//! `recv`, `send`, and variants. + +#![allow(unsafe_code)] + +use crate::buffer::split_init; +#[cfg(unix)] +use crate::net::SocketAddrUnix; +use crate::net::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use crate::{backend, io}; +use backend::fd::{AsFd, BorrowedFd}; +use core::mem::MaybeUninit; + +pub use backend::net::send_recv::{RecvFlags, SendFlags}; + +#[cfg(not(any( +    windows, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +mod msg; + +#[cfg(not(any( +    windows, +    target_os = "espidf", +    target_os = "redox", +    target_os = "vita", +    target_os = "wasi" +)))] +pub use msg::*; + +/// `recv(fd, buf, flags)`—Reads data from a socket. +/// +/// # References +///  - [Beej's Guide to Network Programming] +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendrecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html +/// [Linux]: https://man7.org/linux/man-pages/man2/recv.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recv.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recv +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recv&sektion=2 +/// [NetBSD]: https://man.netbsd.org/recv.2 +/// [OpenBSD]: https://man.openbsd.org/recv.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recv§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/recv +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Receiving-Data.html +#[inline] +pub fn recv<Fd: AsFd>(fd: Fd, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> { +    unsafe { backend::net::syscalls::recv(fd.as_fd(), buf.as_mut_ptr(), buf.len(), flags) } +} + +/// `recv(fd, buf, flags)`—Reads data from a socket. +/// +/// This is equivalent to [`recv`], except that it can read into uninitialized +/// memory. It returns the slice that was initialized by this function and the +/// slice that remains uninitialized. +#[inline] +pub fn recv_uninit<Fd: AsFd>( +    fd: Fd, +    buf: &mut [MaybeUninit<u8>], +    flags: RecvFlags, +) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])> { +    let length = unsafe { +        backend::net::syscalls::recv(fd.as_fd(), buf.as_mut_ptr() as *mut u8, buf.len(), flags) +    }; + +    Ok(unsafe { split_init(buf, length?) }) +} + +/// `send(fd, buf, flags)`—Writes data to a socket. +/// +/// # References +///  - [Beej's Guide to Network Programming] +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendrecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html +/// [Linux]: https://man7.org/linux/man-pages/man2/send.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/send.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=send&sektion=2 +/// [NetBSD]: https://man.netbsd.org/send.2 +/// [OpenBSD]: https://man.openbsd.org/send.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=send§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/send +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Data.html +#[inline] +pub fn send<Fd: AsFd>(fd: Fd, buf: &[u8], flags: SendFlags) -> io::Result<usize> { +    backend::net::syscalls::send(fd.as_fd(), buf, flags) +} + +/// `recvfrom(fd, buf, flags, addr, len)`—Reads data from a socket and +/// returns the sender address. +/// +/// # References +///  - [Beej's Guide to Network Programming] +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html +/// [Linux]: https://man7.org/linux/man-pages/man2/recvfrom.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvfrom.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvfrom&sektion=2 +/// [NetBSD]: https://man.netbsd.org/recvfrom.2 +/// [OpenBSD]: https://man.openbsd.org/recvfrom.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvfrom§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/recvfrom +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Receiving-Datagrams.html +#[inline] +pub fn recvfrom<Fd: AsFd>( +    fd: Fd, +    buf: &mut [u8], +    flags: RecvFlags, +) -> io::Result<(usize, Option<SocketAddrAny>)> { +    unsafe { backend::net::syscalls::recvfrom(fd.as_fd(), buf.as_mut_ptr(), buf.len(), flags) } +} + +/// `recvfrom(fd, buf, flags, addr, len)`—Reads data from a socket and +/// returns the sender address. +/// +/// This is equivalent to [`recvfrom`], except that it can read into +/// uninitialized memory. It returns the slice that was initialized by this +/// function and the slice that remains uninitialized. +#[allow(clippy::type_complexity)] +#[inline] +pub fn recvfrom_uninit<Fd: AsFd>( +    fd: Fd, +    buf: &mut [MaybeUninit<u8>], +    flags: RecvFlags, +) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>], Option<SocketAddrAny>)> { +    let (length, addr) = unsafe { +        backend::net::syscalls::recvfrom(fd.as_fd(), buf.as_mut_ptr() as *mut u8, buf.len(), flags)? +    }; +    let (init, uninit) = unsafe { split_init(buf, length) }; +    Ok((init, uninit, addr)) +} + +/// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific IP +/// address. +/// +/// # References +///  - [Beej's Guide to Network Programming] +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +pub fn sendto<Fd: AsFd>( +    fd: Fd, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddr, +) -> io::Result<usize> { +    _sendto(fd.as_fd(), buf, flags, addr) +} + +fn _sendto( +    fd: BorrowedFd<'_>, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddr, +) -> io::Result<usize> { +    match addr { +        SocketAddr::V4(v4) => backend::net::syscalls::sendto_v4(fd, buf, flags, v4), +        SocketAddr::V6(v6) => backend::net::syscalls::sendto_v6(fd, buf, flags, v6), +    } +} + +/// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific +/// address. +/// +/// # References +///  - [Beej's Guide to Network Programming] +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +pub fn sendto_any<Fd: AsFd>( +    fd: Fd, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddrAny, +) -> io::Result<usize> { +    _sendto_any(fd.as_fd(), buf, flags, addr) +} + +fn _sendto_any( +    fd: BorrowedFd<'_>, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddrAny, +) -> io::Result<usize> { +    match addr { +        SocketAddrAny::V4(v4) => backend::net::syscalls::sendto_v4(fd, buf, flags, v4), +        SocketAddrAny::V6(v6) => backend::net::syscalls::sendto_v6(fd, buf, flags, v6), +        #[cfg(unix)] +        SocketAddrAny::Unix(unix) => backend::net::syscalls::sendto_unix(fd, buf, flags, unix), +    } +} + +/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_in))`—Writes data to +/// a socket to a specific IPv4 address. +/// +/// # References +///  - [Beej's Guide to Network Programming] +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +#[inline] +#[doc(alias = "sendto")] +pub fn sendto_v4<Fd: AsFd>( +    fd: Fd, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddrV4, +) -> io::Result<usize> { +    backend::net::syscalls::sendto_v4(fd.as_fd(), buf, flags, addr) +} + +/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_in6))`—Writes data +/// to a socket to a specific IPv6 address. +/// +/// # References +///  - [Beej's Guide to Network Programming] +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +#[inline] +#[doc(alias = "sendto")] +pub fn sendto_v6<Fd: AsFd>( +    fd: Fd, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddrV6, +) -> io::Result<usize> { +    backend::net::syscalls::sendto_v6(fd.as_fd(), buf, flags, addr) +} + +/// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_un))`—Writes data to +/// a socket to a specific Unix-domain socket address. +/// +/// # References +///  - [Beej's Guide to Network Programming] +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [Winsock] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +///  - [glibc] +/// +/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendto.2 +/// [OpenBSD]: https://man.openbsd.org/sendto.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendto +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html +#[cfg(unix)] +#[inline] +#[doc(alias = "sendto")] +pub fn sendto_unix<Fd: AsFd>( +    fd: Fd, +    buf: &[u8], +    flags: SendFlags, +    addr: &SocketAddrUnix, +) -> io::Result<usize> { +    backend::net::syscalls::sendto_unix(fd.as_fd(), buf, flags, addr) +} diff --git a/vendor/rustix/src/net/send_recv/msg.rs b/vendor/rustix/src/net/send_recv/msg.rs new file mode 100644 index 0000000..78fb865 --- /dev/null +++ b/vendor/rustix/src/net/send_recv/msg.rs @@ -0,0 +1,966 @@ +//! [`recvmsg`], [`sendmsg`], and related functions. + +#![allow(unsafe_code)] + +use crate::backend::{self, c}; +use crate::fd::{AsFd, BorrowedFd, OwnedFd}; +use crate::io::{self, IoSlice, IoSliceMut}; +#[cfg(linux_kernel)] +use crate::net::UCred; + +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem::{align_of, size_of, size_of_val, take}; +#[cfg(linux_kernel)] +use core::ptr::addr_of; +use core::{ptr, slice}; + +use super::{RecvFlags, SendFlags, SocketAddrAny, SocketAddrV4, SocketAddrV6}; + +/// Macro for defining the amount of space to allocate in a buffer for use with +/// [`RecvAncillaryBuffer::new`] and [`SendAncillaryBuffer::new`]. +/// +/// # Examples +/// +/// Allocate a buffer for a single file descriptor: +/// ``` +/// # use rustix::cmsg_space; +/// let mut space = [0; rustix::cmsg_space!(ScmRights(1))]; +/// ``` +/// +/// Allocate a buffer for credentials: +/// ``` +/// # #[cfg(linux_kernel)] +/// # { +/// # use rustix::cmsg_space; +/// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))]; +/// # } +/// ``` +/// +/// Allocate a buffer for two file descriptors and credentials: +/// ``` +/// # #[cfg(linux_kernel)] +/// # { +/// # use rustix::cmsg_space; +/// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))]; +/// # } +/// ``` +#[macro_export] +macro_rules! cmsg_space { +    // Base Rules +    (ScmRights($len:expr)) => { +        $crate::net::__cmsg_space( +            $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(), +        ) +    }; +    (ScmCredentials($len:expr)) => { +        $crate::net::__cmsg_space( +            $len * ::core::mem::size_of::<$crate::net::UCred>(), +        ) +    }; + +    // Combo Rules +    ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{ +        // We only have to add `cmsghdr` alignment once; all other times we can +        // use `cmsg_aligned_space`. +        let sum = $crate::cmsg_space!($firstid($firstex)); +        $( +            let sum = sum + $crate::cmsg_aligned_space!($restid($restex)); +        )* +        sum +    }}; +} + +/// Like `cmsg_space`, but doesn't add padding for `cmsghdr` alignment. +#[doc(hidden)] +#[macro_export] +macro_rules! cmsg_aligned_space { +    // Base Rules +    (ScmRights($len:expr)) => { +        $crate::net::__cmsg_aligned_space( +            $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(), +        ) +    }; +    (ScmCredentials($len:expr)) => { +        $crate::net::__cmsg_aligned_space( +            $len * ::core::mem::size_of::<$crate::net::UCred>(), +        ) +    }; + +    // Combo Rules +    ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{ +        let sum = cmsg_aligned_space!($firstid($firstex)); +        $( +            let sum = sum + cmsg_aligned_space!($restid($restex)); +        )* +        sum +    }}; +} + +#[doc(hidden)] +pub const fn __cmsg_space(len: usize) -> usize { +    // Add `align_of::<c::cmsghdr>()` so that we can align the user-provided +    // `&[u8]` to the required alignment boundary. +    let len = len + align_of::<c::cmsghdr>(); + +    __cmsg_aligned_space(len) +} + +#[doc(hidden)] +pub const fn __cmsg_aligned_space(len: usize) -> usize { +    // Convert `len` to `u32` for `CMSG_SPACE`. This would be `try_into()` if +    // we could call that in a `const fn`. +    let converted_len = len as u32; +    if converted_len as usize != len { +        unreachable!(); // `CMSG_SPACE` size overflow +    } + +    unsafe { c::CMSG_SPACE(converted_len) as usize } +} + +/// Ancillary message for [`sendmsg`], [`sendmsg_v4`], [`sendmsg_v6`], +/// [`sendmsg_unix`], and [`sendmsg_any`]. +#[non_exhaustive] +pub enum SendAncillaryMessage<'slice, 'fd> { +    /// Send file descriptors. +    #[doc(alias = "SCM_RIGHTS")] +    ScmRights(&'slice [BorrowedFd<'fd>]), +    /// Send process credentials. +    #[cfg(linux_kernel)] +    #[doc(alias = "SCM_CREDENTIAL")] +    ScmCredentials(UCred), +} + +impl SendAncillaryMessage<'_, '_> { +    /// Get the maximum size of an ancillary message. +    /// +    /// This can be helpful in determining the size of the buffer you allocate. +    pub const fn size(&self) -> usize { +        match self { +            Self::ScmRights(slice) => cmsg_space!(ScmRights(slice.len())), +            #[cfg(linux_kernel)] +            Self::ScmCredentials(_) => cmsg_space!(ScmCredentials(1)), +        } +    } +} + +/// Ancillary message for [`recvmsg`]. +#[non_exhaustive] +pub enum RecvAncillaryMessage<'a> { +    /// Received file descriptors. +    #[doc(alias = "SCM_RIGHTS")] +    ScmRights(AncillaryIter<'a, OwnedFd>), +    /// Received process credentials. +    #[cfg(linux_kernel)] +    #[doc(alias = "SCM_CREDENTIALS")] +    ScmCredentials(UCred), +} + +/// Buffer for sending ancillary messages with [`sendmsg`], [`sendmsg_v4`], +/// [`sendmsg_v6`], [`sendmsg_unix`], and [`sendmsg_any`]. +/// +/// Use the [`push`] function to add messages to send. +/// +/// [`push`]: SendAncillaryBuffer::push +pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> { +    /// Raw byte buffer for messages. +    buffer: &'buf mut [u8], + +    /// The amount of the buffer that is used. +    length: usize, + +    /// Phantom data for lifetime of `&'slice [BorrowedFd<'fd>]`. +    _phantom: PhantomData<&'slice [BorrowedFd<'fd>]>, +} + +impl<'buf> From<&'buf mut [u8]> for SendAncillaryBuffer<'buf, '_, '_> { +    fn from(buffer: &'buf mut [u8]) -> Self { +        Self::new(buffer) +    } +} + +impl Default for SendAncillaryBuffer<'_, '_, '_> { +    fn default() -> Self { +        Self { +            buffer: &mut [], +            length: 0, +            _phantom: PhantomData, +        } +    } +} + +impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> { +    /// Create a new, empty `SendAncillaryBuffer` from a raw byte buffer. +    /// +    /// The buffer size may be computed with [`cmsg_space`], or it may be +    /// zero for an empty buffer, however in that case, consider `default()` +    /// instead, or even using [`send`] instead of `sendmsg`. +    /// +    /// # Examples +    /// +    /// Allocate a buffer for a single file descriptor: +    /// ``` +    /// # use rustix::cmsg_space; +    /// # use rustix::net::SendAncillaryBuffer; +    /// let mut space = [0; rustix::cmsg_space!(ScmRights(1))]; +    /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space); +    /// ``` +    /// +    /// Allocate a buffer for credentials: +    /// ``` +    /// # #[cfg(linux_kernel)] +    /// # { +    /// # use rustix::cmsg_space; +    /// # use rustix::net::SendAncillaryBuffer; +    /// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))]; +    /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space); +    /// # } +    /// ``` +    /// +    /// Allocate a buffer for two file descriptors and credentials: +    /// ``` +    /// # #[cfg(linux_kernel)] +    /// # { +    /// # use rustix::cmsg_space; +    /// # use rustix::net::SendAncillaryBuffer; +    /// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))]; +    /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space); +    /// # } +    /// ``` +    /// +    /// [`send`]: crate::net::send +    #[inline] +    pub fn new(buffer: &'buf mut [u8]) -> Self { +        Self { +            buffer: align_for_cmsghdr(buffer), +            length: 0, +            _phantom: PhantomData, +        } +    } + +    /// Returns a pointer to the message data. +    pub(crate) fn as_control_ptr(&mut self) -> *mut u8 { +        // When the length is zero, we may be using a `&[]` address, which may +        // be an invalid but non-null pointer, and on some platforms, that +        // causes `sendmsg` to fail with `EFAULT` or `EINVAL` +        #[cfg(not(linux_kernel))] +        if self.length == 0 { +            return core::ptr::null_mut(); +        } + +        self.buffer.as_mut_ptr() +    } + +    /// Returns the length of the message data. +    pub(crate) fn control_len(&self) -> usize { +        self.length +    } + +    /// Delete all messages from the buffer. +    pub fn clear(&mut self) { +        self.length = 0; +    } + +    /// Add an ancillary message to the buffer. +    /// +    /// Returns `true` if the message was added successfully. +    pub fn push(&mut self, msg: SendAncillaryMessage<'slice, 'fd>) -> bool { +        match msg { +            SendAncillaryMessage::ScmRights(fds) => { +                let fds_bytes = +                    unsafe { slice::from_raw_parts(fds.as_ptr().cast::<u8>(), size_of_val(fds)) }; +                self.push_ancillary(fds_bytes, c::SOL_SOCKET as _, c::SCM_RIGHTS as _) +            } +            #[cfg(linux_kernel)] +            SendAncillaryMessage::ScmCredentials(ucred) => { +                let ucred_bytes = unsafe { +                    slice::from_raw_parts(addr_of!(ucred).cast::<u8>(), size_of_val(&ucred)) +                }; +                self.push_ancillary(ucred_bytes, c::SOL_SOCKET as _, c::SCM_CREDENTIALS as _) +            } +        } +    } + +    /// Pushes an ancillary message to the buffer. +    fn push_ancillary(&mut self, source: &[u8], cmsg_level: c::c_int, cmsg_type: c::c_int) -> bool { +        macro_rules! leap { +            ($e:expr) => {{ +                match ($e) { +                    Some(x) => x, +                    None => return false, +                } +            }}; +        } + +        // Calculate the length of the message. +        let source_len = leap!(u32::try_from(source.len()).ok()); + +        // Calculate the new length of the buffer. +        let additional_space = unsafe { c::CMSG_SPACE(source_len) }; +        let new_length = leap!(self.length.checked_add(additional_space as usize)); +        let buffer = leap!(self.buffer.get_mut(..new_length)); + +        // Fill the new part of the buffer with zeroes. +        buffer[self.length..new_length].fill(0); +        self.length = new_length; + +        // Get the last header in the buffer. +        let last_header = leap!(messages::Messages::new(buffer).last()); + +        // Set the header fields. +        last_header.cmsg_len = unsafe { c::CMSG_LEN(source_len) } as _; +        last_header.cmsg_level = cmsg_level; +        last_header.cmsg_type = cmsg_type; + +        // Get the pointer to the payload and copy the data. +        unsafe { +            let payload = c::CMSG_DATA(last_header); +            ptr::copy_nonoverlapping(source.as_ptr(), payload, source_len as _); +        } + +        true +    } +} + +impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>> +    for SendAncillaryBuffer<'_, 'slice, 'fd> +{ +    fn extend<T: IntoIterator<Item = SendAncillaryMessage<'slice, 'fd>>>(&mut self, iter: T) { +        // TODO: This could be optimized to add every message in one go. +        iter.into_iter().all(|msg| self.push(msg)); +    } +} + +/// Buffer for receiving ancillary messages with [`recvmsg`]. +/// +/// Use the [`drain`] function to iterate over the received messages. +/// +/// [`drain`]: RecvAncillaryBuffer::drain +#[derive(Default)] +pub struct RecvAncillaryBuffer<'buf> { +    /// Raw byte buffer for messages. +    buffer: &'buf mut [u8], + +    /// The portion of the buffer we've read from already. +    read: usize, + +    /// The amount of the buffer that is used. +    length: usize, +} + +impl<'buf> From<&'buf mut [u8]> for RecvAncillaryBuffer<'buf> { +    fn from(buffer: &'buf mut [u8]) -> Self { +        Self::new(buffer) +    } +} + +impl<'buf> RecvAncillaryBuffer<'buf> { +    /// Create a new, empty `RecvAncillaryBuffer` from a raw byte buffer. +    /// +    /// The buffer size may be computed with [`cmsg_space`], or it may be +    /// zero for an empty buffer, however in that case, consider `default()` +    /// instead, or even using [`recv`] instead of `recvmsg`. +    /// +    /// # Examples +    /// +    /// Allocate a buffer for a single file descriptor: +    /// ``` +    /// # use rustix::cmsg_space; +    /// # use rustix::net::RecvAncillaryBuffer; +    /// let mut space = [0; rustix::cmsg_space!(ScmRights(1))]; +    /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space); +    /// ``` +    /// +    /// Allocate a buffer for credentials: +    /// ``` +    /// # #[cfg(linux_kernel)] +    /// # { +    /// # use rustix::cmsg_space; +    /// # use rustix::net::RecvAncillaryBuffer; +    /// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))]; +    /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space); +    /// # } +    /// ``` +    /// +    /// Allocate a buffer for two file descriptors and credentials: +    /// ``` +    /// # #[cfg(linux_kernel)] +    /// # { +    /// # use rustix::cmsg_space; +    /// # use rustix::net::RecvAncillaryBuffer; +    /// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))]; +    /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space); +    /// # } +    /// ``` +    /// +    /// [`recv`]: crate::net::recv +    #[inline] +    pub fn new(buffer: &'buf mut [u8]) -> Self { +        Self { +            buffer: align_for_cmsghdr(buffer), +            read: 0, +            length: 0, +        } +    } + +    /// Returns a pointer to the message data. +    pub(crate) fn as_control_ptr(&mut self) -> *mut u8 { +        // When the length is zero, we may be using a `&[]` address, which may +        // be an invalid but non-null pointer, and on some platforms, that +        // causes `sendmsg` to fail with `EFAULT` or `EINVAL` +        #[cfg(not(linux_kernel))] +        if self.buffer.is_empty() { +            return core::ptr::null_mut(); +        } + +        self.buffer.as_mut_ptr() +    } + +    /// Returns the length of the message data. +    pub(crate) fn control_len(&self) -> usize { +        self.buffer.len() +    } + +    /// Set the length of the message data. +    /// +    /// # Safety +    /// +    /// The buffer must be filled with valid message data. +    pub(crate) unsafe fn set_control_len(&mut self, len: usize) { +        self.length = len; +        self.read = 0; +    } + +    /// Delete all messages from the buffer. +    pub(crate) fn clear(&mut self) { +        self.drain().for_each(drop); +    } + +    /// Drain all messages from the buffer. +    pub fn drain(&mut self) -> AncillaryDrain<'_> { +        AncillaryDrain { +            messages: messages::Messages::new(&mut self.buffer[self.read..][..self.length]), +            read: &mut self.read, +            length: &mut self.length, +        } +    } +} + +impl Drop for RecvAncillaryBuffer<'_> { +    fn drop(&mut self) { +        self.clear(); +    } +} + +/// Return a slice of `buffer` starting at the first `cmsghdr` alignment +/// boundary. +#[inline] +fn align_for_cmsghdr(buffer: &mut [u8]) -> &mut [u8] { +    // If the buffer is empty, we won't be writing anything into it, so it +    // doesn't need to be aligned. +    if buffer.is_empty() { +        return buffer; +    } + +    let align = align_of::<c::cmsghdr>(); +    let addr = buffer.as_ptr() as usize; +    let adjusted = (addr + (align - 1)) & align.wrapping_neg(); +    &mut buffer[adjusted - addr..] +} + +/// An iterator that drains messages from a [`RecvAncillaryBuffer`]. +pub struct AncillaryDrain<'buf> { +    /// Inner iterator over messages. +    messages: messages::Messages<'buf>, + +    /// Increment the number of messages we've read. +    read: &'buf mut usize, + +    /// Decrement the total length. +    length: &'buf mut usize, +} + +impl<'buf> AncillaryDrain<'buf> { +    /// A closure that converts a message into a [`RecvAncillaryMessage`]. +    fn cvt_msg( +        read: &mut usize, +        length: &mut usize, +        msg: &c::cmsghdr, +    ) -> Option<RecvAncillaryMessage<'buf>> { +        unsafe { +            // Advance the `read` pointer. +            let msg_len = msg.cmsg_len as usize; +            *read += msg_len; +            *length -= msg_len; + +            // Get a pointer to the payload. +            let payload = c::CMSG_DATA(msg); +            let payload_len = msg.cmsg_len as usize - c::CMSG_LEN(0) as usize; + +            // Get a mutable slice of the payload. +            let payload: &'buf mut [u8] = slice::from_raw_parts_mut(payload, payload_len); + +            // Determine what type it is. +            let (level, msg_type) = (msg.cmsg_level, msg.cmsg_type); +            match (level as _, msg_type as _) { +                (c::SOL_SOCKET, c::SCM_RIGHTS) => { +                    // Create an iterator that reads out the file descriptors. +                    let fds = AncillaryIter::new(payload); + +                    Some(RecvAncillaryMessage::ScmRights(fds)) +                } +                #[cfg(linux_kernel)] +                (c::SOL_SOCKET, c::SCM_CREDENTIALS) => { +                    if payload_len >= size_of::<UCred>() { +                        let ucred = payload.as_ptr().cast::<UCred>().read_unaligned(); +                        Some(RecvAncillaryMessage::ScmCredentials(ucred)) +                    } else { +                        None +                    } +                } +                _ => None, +            } +        } +    } +} + +impl<'buf> Iterator for AncillaryDrain<'buf> { +    type Item = RecvAncillaryMessage<'buf>; + +    fn next(&mut self) -> Option<Self::Item> { +        let read = &mut self.read; +        let length = &mut self.length; +        self.messages.find_map(|ev| Self::cvt_msg(read, length, ev)) +    } + +    fn size_hint(&self) -> (usize, Option<usize>) { +        let (_, max) = self.messages.size_hint(); +        (0, max) +    } + +    fn fold<B, F>(self, init: B, f: F) -> B +    where +        Self: Sized, +        F: FnMut(B, Self::Item) -> B, +    { +        let read = self.read; +        let length = self.length; +        self.messages +            .filter_map(|ev| Self::cvt_msg(read, length, ev)) +            .fold(init, f) +    } + +    fn count(self) -> usize { +        let read = self.read; +        let length = self.length; +        self.messages +            .filter_map(|ev| Self::cvt_msg(read, length, ev)) +            .count() +    } + +    fn last(self) -> Option<Self::Item> +    where +        Self: Sized, +    { +        let read = self.read; +        let length = self.length; +        self.messages +            .filter_map(|ev| Self::cvt_msg(read, length, ev)) +            .last() +    } + +    fn collect<B: FromIterator<Self::Item>>(self) -> B +    where +        Self: Sized, +    { +        let read = self.read; +        let length = self.length; +        self.messages +            .filter_map(|ev| Self::cvt_msg(read, length, ev)) +            .collect() +    } +} + +impl FusedIterator for AncillaryDrain<'_> {} + +/// `sendmsg(msghdr)`—Sends a message on a socket. +/// +/// # References +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg( +    socket: impl AsFd, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    flags: SendFlags, +) -> io::Result<usize> { +    backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags) +} + +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv4 address. +/// +/// # References +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg_v4( +    socket: impl AsFd, +    addr: &SocketAddrV4, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    flags: SendFlags, +) -> io::Result<usize> { +    backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags) +} + +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv6 address. +/// +/// # References +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg_v6( +    socket: impl AsFd, +    addr: &SocketAddrV6, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    flags: SendFlags, +) -> io::Result<usize> { +    backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags) +} + +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific Unix-domain +/// address. +/// +/// # References +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +#[cfg(unix)] +pub fn sendmsg_unix( +    socket: impl AsFd, +    addr: &super::SocketAddrUnix, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    flags: SendFlags, +) -> io::Result<usize> { +    backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags) +} + +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific address. +/// +/// # References +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg_any( +    socket: impl AsFd, +    addr: Option<&SocketAddrAny>, +    iov: &[IoSlice<'_>], +    control: &mut SendAncillaryBuffer<'_, '_, '_>, +    flags: SendFlags, +) -> io::Result<usize> { +    match addr { +        None => backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags), +        Some(SocketAddrAny::V4(addr)) => { +            backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags) +        } +        Some(SocketAddrAny::V6(addr)) => { +            backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags) +        } +        #[cfg(unix)] +        Some(SocketAddrAny::Unix(addr)) => { +            backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags) +        } +    } +} + +/// `recvmsg(msghdr)`—Receives a message from a socket. +/// +/// # References +///  - [POSIX] +///  - [Linux] +///  - [Apple] +///  - [FreeBSD] +///  - [NetBSD] +///  - [OpenBSD] +///  - [DragonFly BSD] +///  - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/recvmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/recvmsg.2 +/// [OpenBSD]: https://man.openbsd.org/recvmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/recvmsg +#[inline] +pub fn recvmsg( +    socket: impl AsFd, +    iov: &mut [IoSliceMut<'_>], +    control: &mut RecvAncillaryBuffer<'_>, +    flags: RecvFlags, +) -> io::Result<RecvMsgReturn> { +    backend::net::syscalls::recvmsg(socket.as_fd(), iov, control, flags) +} + +/// The result of a successful [`recvmsg`] call. +pub struct RecvMsgReturn { +    /// The number of bytes received. +    pub bytes: usize, + +    /// The flags received. +    pub flags: RecvFlags, + +    /// The address of the socket we received from, if any. +    pub address: Option<SocketAddrAny>, +} + +/// An iterator over data in an ancillary buffer. +pub struct AncillaryIter<'data, T> { +    /// The data we're iterating over. +    data: &'data mut [u8], + +    /// The raw data we're removing. +    _marker: PhantomData<T>, +} + +impl<'data, T> AncillaryIter<'data, T> { +    /// Create a new iterator over data in an ancillary buffer. +    /// +    /// # Safety +    /// +    /// The buffer must contain valid ancillary data. +    unsafe fn new(data: &'data mut [u8]) -> Self { +        assert_eq!(data.len() % size_of::<T>(), 0); + +        Self { +            data, +            _marker: PhantomData, +        } +    } +} + +impl<'data, T> Drop for AncillaryIter<'data, T> { +    fn drop(&mut self) { +        self.for_each(drop); +    } +} + +impl<T> Iterator for AncillaryIter<'_, T> { +    type Item = T; + +    fn next(&mut self) -> Option<Self::Item> { +        // See if there is a next item. +        if self.data.len() < size_of::<T>() { +            return None; +        } + +        // Get the next item. +        let item = unsafe { self.data.as_ptr().cast::<T>().read_unaligned() }; + +        // Move forward. +        let data = take(&mut self.data); +        self.data = &mut data[size_of::<T>()..]; + +        Some(item) +    } + +    fn size_hint(&self) -> (usize, Option<usize>) { +        let len = self.len(); +        (len, Some(len)) +    } + +    fn count(self) -> usize { +        self.len() +    } + +    fn last(mut self) -> Option<Self::Item> { +        self.next_back() +    } +} + +impl<T> FusedIterator for AncillaryIter<'_, T> {} + +impl<T> ExactSizeIterator for AncillaryIter<'_, T> { +    fn len(&self) -> usize { +        self.data.len() / size_of::<T>() +    } +} + +impl<T> DoubleEndedIterator for AncillaryIter<'_, T> { +    fn next_back(&mut self) -> Option<Self::Item> { +        // See if there is a next item. +        if self.data.len() < size_of::<T>() { +            return None; +        } + +        // Get the next item. +        let item = unsafe { +            let ptr = self.data.as_ptr().add(self.data.len() - size_of::<T>()); +            ptr.cast::<T>().read_unaligned() +        }; + +        // Move forward. +        let len = self.data.len(); +        let data = take(&mut self.data); +        self.data = &mut data[..len - size_of::<T>()]; + +        Some(item) +    } +} + +mod messages { +    use crate::backend::c; +    use crate::backend::net::msghdr; +    use core::iter::FusedIterator; +    use core::marker::PhantomData; +    use core::ptr::NonNull; + +    /// An iterator over the messages in an ancillary buffer. +    pub(super) struct Messages<'buf> { +        /// The message header we're using to iterate over the messages. +        msghdr: c::msghdr, + +        /// The current pointer to the next message header to return. +        /// +        /// This has a lifetime of `'buf`. +        header: Option<NonNull<c::cmsghdr>>, + +        /// Capture the original lifetime of the buffer. +        _buffer: PhantomData<&'buf mut [u8]>, +    } + +    impl<'buf> Messages<'buf> { +        /// Create a new iterator over messages from a byte buffer. +        pub(super) fn new(buf: &'buf mut [u8]) -> Self { +            let msghdr = { +                let mut h = msghdr::zero_msghdr(); +                h.msg_control = buf.as_mut_ptr().cast(); +                h.msg_controllen = buf.len().try_into().expect("buffer too large for msghdr"); +                h +            }; + +            // Get the first header. +            let header = NonNull::new(unsafe { c::CMSG_FIRSTHDR(&msghdr) }); + +            Self { +                msghdr, +                header, +                _buffer: PhantomData, +            } +        } +    } + +    impl<'a> Iterator for Messages<'a> { +        type Item = &'a mut c::cmsghdr; + +        #[inline] +        fn next(&mut self) -> Option<Self::Item> { +            // Get the current header. +            let header = self.header?; + +            // Get the next header. +            self.header = NonNull::new(unsafe { c::CMSG_NXTHDR(&self.msghdr, header.as_ptr()) }); + +            // If the headers are equal, we're done. +            if Some(header) == self.header { +                self.header = None; +            } + +            // SAFETY: The lifetime of `header` is tied to this. +            Some(unsafe { &mut *header.as_ptr() }) +        } + +        fn size_hint(&self) -> (usize, Option<usize>) { +            if self.header.is_some() { +                // The remaining buffer *could* be filled with zero-length +                // messages. +                let max_size = unsafe { c::CMSG_LEN(0) } as usize; +                let remaining_count = self.msghdr.msg_controllen as usize / max_size; +                (1, Some(remaining_count)) +            } else { +                (0, Some(0)) +            } +        } +    } + +    impl FusedIterator for Messages<'_> {} +}  | 
