diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-15 16:37:08 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-17 16:30:22 -0600 |
| commit | 45df4d0d9b577fecee798d672695fe24ff57fb1b (patch) | |
| tree | 1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/rustix/src/net/send_recv | |
| parent | f94f79608393d4ab127db63cc41668445ef6b243 (diff) | |
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based
authorization system with SpiceDB's relation-based authorization.
Key changes:
- Migrate from Rust to Go implementation
- Replace Cedar policies with SpiceDB schema and relationships
- Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks
- Update build system and dependencies for Go ecosystem
- Maintain Envoy integration for external authorization
This change enables more flexible permission modeling through SpiceDB's
Google Zanzibar inspired relation-based system, supporting complex
hierarchical permissions that were difficult to express in Cedar.
Breaking change: Existing Cedar policies and Rust-based configuration
will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/rustix/src/net/send_recv')
| -rw-r--r-- | vendor/rustix/src/net/send_recv/mod.rs | 192 | ||||
| -rw-r--r-- | vendor/rustix/src/net/send_recv/msg.rs | 961 |
2 files changed, 0 insertions, 1153 deletions
diff --git a/vendor/rustix/src/net/send_recv/mod.rs b/vendor/rustix/src/net/send_recv/mod.rs deleted file mode 100644 index 0aac6d2e..00000000 --- a/vendor/rustix/src/net/send_recv/mod.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! `recv`, `send`, and variants. - -#![allow(unsafe_code)] - -use crate::buffer::Buffer; -use crate::net::addr::SocketAddrArg; -use crate::net::SocketAddrAny; -use crate::{backend, io}; -use backend::fd::AsFd; -use core::cmp::min; - -pub use backend::net::send_recv::{RecvFlags, ReturnFlags, SendFlags}; - -#[cfg(not(any( - windows, - target_os = "espidf", - target_os = "horizon", - target_os = "redox", - target_os = "vita" -)))] -mod msg; - -#[cfg(not(any( - windows, - target_os = "espidf", - target_os = "horizon", - target_os = "redox", - target_os = "vita" -)))] -pub use msg::*; - -/// `recv(fd, buf, flags)`—Reads data from a socket. -/// -/// In addition to the `Buffer::Output` return value, this also returns the -/// number of bytes received before any truncation due to the -/// [`RecvFlags::TRUNC`] flag. -/// -/// # 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/9799919799/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://sourceware.org/glibc/manual/latest/html_node/Receiving-Data.html -#[inline] -#[allow(clippy::type_complexity)] -pub fn recv<Fd: AsFd, Buf: Buffer<u8>>( - fd: Fd, - mut buf: Buf, - flags: RecvFlags, -) -> io::Result<(Buf::Output, usize)> { - let (ptr, len) = buf.parts_mut(); - // SAFETY: `recv` behaves. - let recv_len = unsafe { backend::net::syscalls::recv(fd.as_fd(), (ptr, len), flags)? }; - // If the `TRUNC` flag is set, the returned `length` may be longer than the - // buffer length. - let min_len = min(len, recv_len); - // SAFETY: `recv` behaves. - unsafe { Ok((buf.assume_init(min_len), recv_len)) } -} - -/// `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/9799919799/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://sourceware.org/glibc/manual/latest/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. -/// -/// In addition to the `Buffer::Output` return value, this also returns the -/// number of bytes received before any truncation due to the -/// [`RecvFlags::TRUNC`] flag. -/// -/// # 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/9799919799/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://sourceware.org/glibc/manual/latest/html_node/Receiving-Datagrams.html -#[inline] -pub fn recvfrom<Fd: AsFd, Buf: Buffer<u8>>( - fd: Fd, - mut buf: Buf, - flags: RecvFlags, -) -> io::Result<(Buf::Output, usize, Option<SocketAddrAny>)> { - let (ptr, len) = buf.parts_mut(); - // SAFETY: `recvfrom` behaves. - let (recv_len, addr) = - unsafe { backend::net::syscalls::recvfrom(fd.as_fd(), (ptr, len), flags)? }; - // If the `TRUNC` flag is set, the returned `length` may be longer than the - // buffer length. - let min_len = min(len, recv_len); - // SAFETY: `recvfrom` behaves. - unsafe { Ok((buf.assume_init(min_len), recv_len, 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/9799919799/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://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html -pub fn sendto<Fd: AsFd>( - fd: Fd, - buf: &[u8], - flags: SendFlags, - addr: &impl SocketAddrArg, -) -> io::Result<usize> { - backend::net::syscalls::sendto(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 deleted file mode 100644 index 7df60a5e..00000000 --- a/vendor/rustix/src/net/send_recv/msg.rs +++ /dev/null @@ -1,961 +0,0 @@ -//! [`recvmsg`], [`sendmsg`], and related functions. - -#![allow(unsafe_code)] - -#[cfg(target_os = "linux")] -use crate::backend::net::msghdr::noaddr_msghdr; -use crate::backend::{self, c}; -use crate::fd::{AsFd, BorrowedFd, OwnedFd}; -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::net::addr::SocketAddrArg; -#[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, MaybeUninit}; -#[cfg(linux_kernel)] -use core::ptr::addr_of; -use core::{ptr, slice}; - -use super::{RecvFlags, ReturnFlags, SendFlags, SocketAddrAny}; - -/// 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 std::mem::MaybeUninit; -/// # use rustix::cmsg_space; -/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))]; -/// # let _: &[MaybeUninit<u8>] = space.as_slice(); -/// ``` -/// -/// Allocate a buffer for credentials: -/// ``` -/// # #[cfg(linux_kernel)] -/// # { -/// # use std::mem::MaybeUninit; -/// # use rustix::cmsg_space; -/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))]; -/// # let _: &[MaybeUninit<u8>] = space.as_slice(); -/// # } -/// ``` -/// -/// Allocate a buffer for two file descriptors and credentials: -/// ``` -/// # #[cfg(linux_kernel)] -/// # { -/// # use std::mem::MaybeUninit; -/// # use rustix::cmsg_space; -/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))]; -/// # let _: &[MaybeUninit<u8>] = space.as_slice(); -/// # } -/// ``` -#[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 - }}; -} - -/// Helper function for [`cmsg_space`]. -#[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) -} - -/// Helper function for [`cmsg_aligned_space`]. -#[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`] and [`sendmsg_addr`]. -#[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 used to determine the size of the buffer to allocate for a - /// [`SendAncillaryBuffer::new`] with one message. - 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`] and -/// [`sendmsg_addr`]. -/// -/// 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 [MaybeUninit<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 [MaybeUninit<u8>]> for SendAncillaryBuffer<'buf, '_, '_> { - fn from(buffer: &'buf mut [MaybeUninit<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 std::mem::MaybeUninit; - /// # use rustix::cmsg_space; - /// # use rustix::net::SendAncillaryBuffer; - /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))]; - /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space); - /// ``` - /// - /// Allocate a buffer for credentials: - /// ``` - /// # #[cfg(linux_kernel)] - /// # { - /// # use std::mem::MaybeUninit; - /// # use rustix::cmsg_space; - /// # use rustix::net::SendAncillaryBuffer; - /// let mut space = [MaybeUninit::uninit(); 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 std::mem::MaybeUninit; - /// # use rustix::cmsg_space; - /// # use rustix::net::SendAncillaryBuffer; - /// let mut space = [MaybeUninit::uninit(); 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 [MaybeUninit<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().cast() - } - - /// 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(MaybeUninit::new(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 usize); - } - - 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 [MaybeUninit<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 [MaybeUninit<u8>]> for RecvAncillaryBuffer<'buf> { - fn from(buffer: &'buf mut [MaybeUninit<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 std::mem::MaybeUninit; - /// # use rustix::cmsg_space; - /// # use rustix::net::RecvAncillaryBuffer; - /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))]; - /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space); - /// ``` - /// - /// Allocate a buffer for credentials: - /// ``` - /// # #[cfg(linux_kernel)] - /// # { - /// # use std::mem::MaybeUninit; - /// # use rustix::cmsg_space; - /// # use rustix::net::RecvAncillaryBuffer; - /// let mut space = [MaybeUninit::uninit(); 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 std::mem::MaybeUninit; - /// # use rustix::cmsg_space; - /// # use rustix::net::RecvAncillaryBuffer; - /// let mut space = [MaybeUninit::uninit(); 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 [MaybeUninit<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().cast() - } - - /// 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_and_length: Some((&mut self.read, &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 [MaybeUninit<u8>]) -> &mut [MaybeUninit<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. - /// Decrement the total length. - read_and_length: Option<(&'buf mut usize, &'buf mut usize)>, -} - -impl<'buf> AncillaryDrain<'buf> { - /// Create an iterator for control messages that were received without - /// [`RecvAncillaryBuffer`]. - /// - /// # Safety - /// - /// The buffer must contain valid message data (or be empty). - pub unsafe fn parse(buffer: &'buf mut [u8]) -> Self { - Self { - messages: messages::Messages::new(buffer), - read_and_length: None, - } - } - - fn advance( - read_and_length: &mut Option<(&'buf mut usize, &'buf mut usize)>, - msg: &c::cmsghdr, - ) -> Option<RecvAncillaryMessage<'buf>> { - // Advance the `read` pointer. - if let Some((read, length)) = read_and_length { - let msg_len = msg.cmsg_len as usize; - **read += msg_len; - **length -= msg_len; - } - - Self::cvt_msg(msg) - } - - /// A closure that converts a message into a [`RecvAncillaryMessage`]. - fn cvt_msg(msg: &c::cmsghdr) -> Option<RecvAncillaryMessage<'buf>> { - unsafe { - // 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> { - self.messages - .find_map(|ev| Self::advance(&mut self.read_and_length, ev)) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - let (_, max) = self.messages.size_hint(); - (0, max) - } - - fn fold<B, F>(mut self, init: B, f: F) -> B - where - Self: Sized, - F: FnMut(B, Self::Item) -> B, - { - self.messages - .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) - .fold(init, f) - } - - fn count(mut self) -> usize { - self.messages - .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) - .count() - } - - fn last(mut self) -> Option<Self::Item> - where - Self: Sized, - { - self.messages - .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) - .last() - } - - fn collect<B: FromIterator<Self::Item>>(mut self) -> B - where - Self: Sized, - { - self.messages - .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) - .collect() - } -} - -impl FusedIterator for AncillaryDrain<'_> {} - -/// An ABI-compatible wrapper for `mmsghdr`, for sending multiple messages with -/// [sendmmsg]. -#[cfg(target_os = "linux")] -#[repr(transparent)] -pub struct MMsgHdr<'a> { - raw: c::mmsghdr, - _phantom: PhantomData<&'a mut ()>, -} - -#[cfg(target_os = "linux")] -impl<'a> MMsgHdr<'a> { - /// Constructs a new message with no destination address. - pub fn new(iov: &'a [IoSlice<'_>], control: &'a mut SendAncillaryBuffer<'_, '_, '_>) -> Self { - Self::wrap(noaddr_msghdr(iov, control)) - } - - /// Constructs a new message to a specific address. - /// - /// This requires a `SocketAddrAny` instead of using `impl SocketAddrArg`; - /// to obtain a `SocketAddrAny`, use [`SocketAddrArg::as_any`]. - pub fn new_with_addr( - addr: &'a SocketAddrAny, - iov: &'a [IoSlice<'_>], - control: &'a mut SendAncillaryBuffer<'_, '_, '_>, - ) -> Self { - // The reason we use `SocketAddrAny` instead of `SocketAddrArg` here, - // and avoid `use_msghdr`, is that we need a pointer that will remain - // valid for the duration of the `'a` lifetime. `SocketAddrAny` can - // give us a pointer directly, so we use that. - let mut msghdr = noaddr_msghdr(iov, control); - msghdr.msg_name = addr.as_ptr() as _; - msghdr.msg_namelen = bitcast!(addr.addr_len()); - - Self::wrap(msghdr) - } - - fn wrap(msg_hdr: c::msghdr) -> Self { - Self { - raw: c::mmsghdr { - msg_hdr, - msg_len: 0, - }, - _phantom: PhantomData, - } - } - - /// Returns the number of bytes sent. This will return 0 until after a - /// successful call to [sendmmsg]. - pub fn bytes_sent(&self) -> usize { - self.raw.msg_len as usize - } -} - -/// `sendmsg(msghdr)`—Sends a message on a socket. -/// -/// This function is for use on connected sockets, as it doesn't have a way to -/// specify an address. See [`sendmsg_addr`] to send messages on unconnected -/// sockets. -/// -/// # References -/// - [POSIX] -/// - [Linux] -/// - [Apple] -/// - [FreeBSD] -/// - [NetBSD] -/// - [OpenBSD] -/// - [DragonFly BSD] -/// - [illumos] -/// -/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/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<Fd: AsFd>( - socket: Fd, - 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 address. -/// -/// # References -/// - [POSIX] -/// - [Linux] -/// - [Apple] -/// - [FreeBSD] -/// - [NetBSD] -/// - [OpenBSD] -/// - [DragonFly BSD] -/// - [illumos] -/// -/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/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_addr<Fd: AsFd>( - socket: Fd, - addr: &impl SocketAddrArg, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - flags: SendFlags, -) -> io::Result<usize> { - backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags) -} - -/// `sendmmsg(msghdr)`—Sends multiple messages on a socket. -/// -/// # References -/// - [Linux] -/// -/// [Linux]: https://man7.org/linux/man-pages/man2/sendmmsg.2.html -#[inline] -#[cfg(target_os = "linux")] -pub fn sendmmsg<Fd: AsFd>( - socket: Fd, - msgs: &mut [MMsgHdr<'_>], - flags: SendFlags, -) -> io::Result<usize> { - backend::net::syscalls::sendmmsg(socket.as_fd(), msgs, 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/9799919799/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<Fd: AsFd>( - socket: Fd, - iov: &mut [IoSliceMut<'_>], - control: &mut RecvAncillaryBuffer<'_>, - flags: RecvFlags, -) -> io::Result<RecvMsg> { - backend::net::syscalls::recvmsg(socket.as_fd(), iov, control, flags) -} - -/// The result of a successful [`recvmsg`] call. -#[derive(Debug, Clone)] -pub struct RecvMsg { - /// The number of bytes received. - /// - /// When `RecvFlags::TRUNC` is in use, this may be greater than the length - /// of the buffer, as it reflects the number of bytes received before - /// truncation into the buffer. - pub bytes: usize, - - /// The flags received. - pub flags: ReturnFlags, - - /// 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::mem::MaybeUninit; - 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 [MaybeUninit<u8>]>, - } - - pub(super) trait AllowedMsgBufType {} - impl AllowedMsgBufType for u8 {} - impl AllowedMsgBufType for MaybeUninit<u8> {} - - impl<'buf> Messages<'buf> { - /// Create a new iterator over messages from a byte buffer. - pub(super) fn new(buf: &'buf mut [impl AllowedMsgBufType]) -> Self { - let mut msghdr = msghdr::zero_msghdr(); - msghdr.msg_control = buf.as_mut_ptr().cast(); - msghdr.msg_controllen = buf.len().try_into().expect("buffer too large for msghdr"); - - // 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<'_> {} -} |
