From 8cdfa445d6629ffef4cb84967ff7017654045bc2 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 2 Jul 2025 18:36:06 -0600 Subject: chore: add vendor directory --- vendor/rustix/src/net/addr.rs | 182 +++ vendor/rustix/src/net/mod.rs | 35 + vendor/rustix/src/net/netdevice.rs | 107 ++ vendor/rustix/src/net/send_recv/mod.rs | 192 +++ vendor/rustix/src/net/send_recv/msg.rs | 961 ++++++++++++++ vendor/rustix/src/net/socket.rs | 461 +++++++ vendor/rustix/src/net/socket_addr_any.rs | 344 +++++ vendor/rustix/src/net/socketpair.rs | 36 + vendor/rustix/src/net/sockopt.rs | 1649 +++++++++++++++++++++++ vendor/rustix/src/net/types.rs | 2132 ++++++++++++++++++++++++++++++ vendor/rustix/src/net/wsa.rs | 49 + 11 files changed, 6148 insertions(+) create mode 100644 vendor/rustix/src/net/addr.rs create mode 100644 vendor/rustix/src/net/mod.rs create mode 100644 vendor/rustix/src/net/netdevice.rs create mode 100644 vendor/rustix/src/net/send_recv/mod.rs create mode 100644 vendor/rustix/src/net/send_recv/msg.rs create mode 100644 vendor/rustix/src/net/socket.rs create mode 100644 vendor/rustix/src/net/socket_addr_any.rs create mode 100644 vendor/rustix/src/net/socketpair.rs create mode 100644 vendor/rustix/src/net/sockopt.rs create mode 100644 vendor/rustix/src/net/types.rs create mode 100644 vendor/rustix/src/net/wsa.rs (limited to 'vendor/rustix/src/net') diff --git a/vendor/rustix/src/net/addr.rs b/vendor/rustix/src/net/addr.rs new file mode 100644 index 00000000..13e5c24f --- /dev/null +++ b/vendor/rustix/src/net/addr.rs @@ -0,0 +1,182 @@ +//! Types for implementers of socket address types or code that is generic over +//! address types. +//! +//! The concrete address types and [`SocketAddrAny`] are in +//! [the parent module][`super`]. + +#![allow(unsafe_code)] +use core::mem::{size_of, MaybeUninit}; +use core::ptr; + +use crate::backend::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; +use crate::utils::as_ptr; + +use super::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; + +pub use crate::backend::net::addr::SocketAddrStorage; + +#[cfg(unix)] +use super::SocketAddrUnix; + +/// Opaque type equivalent to `sockaddr` in C. +/// +/// This is always used behind a raw pointer that is cast from a pointer to a +/// `sockaddr`-compatible C type, and then cast back to a `sockaddr` pointer to +/// be passed to a system call. +#[repr(C)] +pub struct SocketAddrOpaque { + _data: [u8; 0], +} + +/// A type for the length of a socket address. +/// +/// This type will always be big enough to hold any socket address, but never +/// bigger than `usize`. +#[doc(alias = "socklen_t")] +pub type SocketAddrLen = u32; + +/// A trait abstracting over the types that can be passed as a `sockaddr`. +/// +/// # Safety +/// +/// Implementers of this trait must ensure that `with_sockaddr` calls `f` with +/// a pointer that is readable for the passed length, and points to data that +/// is a valid socket address for the system calls that accept `sockaddr` as a +/// const pointer. +pub unsafe trait SocketAddrArg { + /// Call a closure with the pointer and length to the corresponding C type. + /// + /// The memory pointed to by the pointer of size length is guaranteed to be + /// valid only for the duration of the call. + /// + /// The API uses a closure so that: + /// - The libc types are not exposed in the rustix API. + /// - Types like `SocketAddrUnix` that contain their corresponding C type + /// can pass it directly without a copy. + /// - Other socket types can construct their C-compatible struct on the + /// stack and call the closure with a pointer to it. + /// + /// # Safety + /// + /// For `f` to use its pointer argument, it'll contain an `unsafe` block. + /// The caller of `with_sockaddr` here is responsible for ensuring that the + /// safety condition for that `unsafe` block is satisfied by the guarantee + /// that `with_sockaddr` here provides. + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R; + + /// Convert to `SocketAddrAny`. + fn as_any(&self) -> SocketAddrAny { + let mut storage = MaybeUninit::::uninit(); + // SAFETY: We've allocated `storage` here, we're writing to it, and + // we're using the number of bytes written. + unsafe { + let len = self.write_sockaddr(storage.as_mut_ptr()); + SocketAddrAny::new(storage, len) + } + } + + /// Encode an address into a `SocketAddrStorage`. + /// + /// Returns the number of bytes that were written. + /// + /// For a safe interface to this functionality, use [`as_any`]. + /// + /// [`as_any`]: Self::as_any + /// + /// # Safety + /// + /// `storage` must be valid to write up to `size_of()` + /// bytes to. + unsafe fn write_sockaddr(&self, storage: *mut SocketAddrStorage) -> SocketAddrLen { + // The closure dereferences exactly `len` bytes at `ptr`. + self.with_sockaddr(|ptr, len| { + ptr::copy_nonoverlapping(ptr.cast::(), storage.cast::(), len as usize); + len + }) + } +} + +/// Helper for implementing `SocketAddrArg::with_sockaddr`. +/// +/// # Safety +/// +/// This calls `f` with a pointer to an object it has a reference to, with the +/// and the length of that object, so they'll be valid for the duration of the +/// call. +pub(crate) unsafe fn call_with_sockaddr( + addr: &A, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, +) -> R { + let ptr = as_ptr(addr).cast(); + let len = size_of::() as SocketAddrLen; + f(ptr, len) +} + +// SAFETY: This just forwards to the inner `SocketAddrArg` implementations. +unsafe impl SocketAddrArg for SocketAddr { + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R { + match self { + Self::V4(v4) => v4.with_sockaddr(f), + Self::V6(v6) => v6.with_sockaddr(f), + } + } +} + +// SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles +// calling `f` with the needed preconditions. +unsafe impl SocketAddrArg for SocketAddrV4 { + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R { + call_with_sockaddr(&encode_sockaddr_v4(self), f) + } +} + +// SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles +// calling `f` with the needed preconditions. +unsafe impl SocketAddrArg for SocketAddrV6 { + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R { + call_with_sockaddr(&encode_sockaddr_v6(self), f) + } +} + +#[cfg(unix)] +// SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles +// calling `f` with the needed preconditions. +unsafe impl SocketAddrArg for SocketAddrUnix { + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R { + f(as_ptr(&self.unix).cast(), self.addr_len()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::backend::c; + + #[test] + fn test_layouts() { + assert_eq_size!(SocketAddrLen, c::socklen_t); + + #[cfg(not(any(windows, target_os = "redox")))] + assert_eq!( + memoffset::span_of!(c::msghdr, msg_namelen).len(), + size_of::() + ); + + assert!(size_of::() <= size_of::()); + } +} diff --git a/vendor/rustix/src/net/mod.rs b/vendor/rustix/src/net/mod.rs new file mode 100644 index 00000000..e5560905 --- /dev/null +++ b/vendor/rustix/src/net/mod.rs @@ -0,0 +1,35 @@ +//! Network-related operations. +//! +//! On Windows, one must call [`wsa_startup`] in the process before calling any +//! of these APIs. [`wsa_cleanup`] may be used in the process if these APIs are +//! no longer needed. +//! +//! [`wsa_startup`]: https://docs.rs/rustix/*/x86_64-pc-windows-msvc/rustix/net/fn.wsa_startup.html +//! [`wsa_cleanup`]: https://docs.rs/rustix/*/x86_64-pc-windows-msvc/rustix/net/fn.wsa_cleanup.html + +pub mod addr; +mod send_recv; +mod socket; +mod socket_addr_any; +#[cfg(not(any(windows, target_os = "wasi")))] +mod socketpair; +mod types; +#[cfg(windows)] +mod wsa; + +#[cfg(linux_kernel)] +pub mod netdevice; +pub mod sockopt; + +pub use crate::maybe_polyfill::net::{ + IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, +}; +pub use send_recv::*; +pub use socket::*; +pub use socket_addr_any::SocketAddrAny; +pub(crate) use socket_addr_any::SocketAddrBuf; +#[cfg(not(any(windows, target_os = "wasi")))] +pub use socketpair::socketpair; +pub use types::*; +#[cfg(windows)] +pub use wsa::{wsa_cleanup, wsa_startup}; diff --git a/vendor/rustix/src/net/netdevice.rs b/vendor/rustix/src/net/netdevice.rs new file mode 100644 index 00000000..1ddd918e --- /dev/null +++ b/vendor/rustix/src/net/netdevice.rs @@ -0,0 +1,107 @@ +//! Low-level Linux network device access +//! +//! The methods in this module take a socket's file descriptor to communicate +//! with the kernel in their ioctl call: +//! - glibc uses an `AF_UNIX`, `AF_INET`, or `AF_INET6` socket. The address +//! family itself does not matter and glibc tries the next address family if +//! socket creation with one fails. +//! - Android (bionic) uses an `AF_INET` socket. +//! - Both create the socket with `SOCK_DGRAM|SOCK_CLOEXEC` type/flag. +//! - The [manual pages] specify that the ioctl calls “can be used on any +//! socket's file descriptor regardless of the family or type”. +//! +//! # References +//! - [Linux] +//! +//! [manual pages]: https://man7.org/linux/man-pages/man7/netdevice.7.html +//! [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html + +use crate::fd::AsFd; +use crate::io; +#[cfg(feature = "alloc")] +use alloc::string::String; + +/// `ioctl(fd, SIOCGIFINDEX, ifreq)`—Returns the interface index for a given +/// name. +/// +/// See the [module-level documentation] for information about `fd` usage. +/// +/// # References +/// - [Linux] +/// +/// [module-level documentation]: self +/// [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html +#[inline] +#[doc(alias = "SIOCGIFINDEX")] +pub fn name_to_index(fd: Fd, if_name: &str) -> io::Result { + crate::backend::net::netdevice::name_to_index(fd.as_fd(), if_name) +} + +/// `ioctl(fd, SIOCGIFNAME, ifreq)`—Returns the interface name for a given +/// index. +/// +/// See the [module-level documentation] for information about `fd` usage. +/// +/// # References +/// - [Linux] +/// +/// [module-level documentation]: self +/// [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html +#[inline] +#[doc(alias = "SIOCGIFNAME")] +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub fn index_to_name(fd: Fd, index: u32) -> io::Result { + crate::backend::net::netdevice::index_to_name(fd.as_fd(), index) +} + +#[cfg(test)] +mod tests { + use crate::backend::net::netdevice::{index_to_name, name_to_index}; + use crate::fd::AsFd; + use crate::net::{AddressFamily, SocketFlags, SocketType}; + + #[test] + fn test_name_to_index() { + let fd = crate::net::socket_with( + AddressFamily::INET, + SocketType::DGRAM, + SocketFlags::CLOEXEC, + None, + ) + .unwrap(); + + let loopback_index = std::fs::read_to_string("/sys/class/net/lo/ifindex") + .unwrap() + .as_str() + .split_at(1) + .0 + .parse::() + .unwrap(); + assert_eq!(Ok(loopback_index), name_to_index(fd.as_fd(), "lo")); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_index_to_name() { + let fd = crate::net::socket_with( + AddressFamily::INET, + SocketType::DGRAM, + SocketFlags::CLOEXEC, + None, + ) + .unwrap(); + + let loopback_index = std::fs::read_to_string("/sys/class/net/lo/ifindex") + .unwrap() + .as_str() + .split_at(1) + .0 + .parse::() + .unwrap(); + assert_eq!( + Ok("lo".to_owned()), + index_to_name(fd.as_fd(), loopback_index) + ); + } +} 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 00000000..0aac6d2e --- /dev/null +++ b/vendor/rustix/src/net/send_recv/mod.rs @@ -0,0 +1,192 @@ +//! `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: 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: Fd, buf: &[u8], flags: SendFlags) -> io::Result { + 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: Fd, + mut buf: Buf, + flags: RecvFlags, +) -> io::Result<(Buf::Output, usize, Option)> { + 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: Fd, + buf: &[u8], + flags: SendFlags, + addr: &impl SocketAddrArg, +) -> io::Result { + 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 new file mode 100644 index 00000000..7df60a5e --- /dev/null +++ b/vendor/rustix/src/net/send_recv/msg.rs @@ -0,0 +1,961 @@ +//! [`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] = 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] = 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] = 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::()` so that we can align the user-provided + // `&[u8]` to the required alignment boundary. + let len = len + align_of::(); + + __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], + + /// 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]> for SendAncillaryBuffer<'buf, '_, '_> { + fn from(buffer: &'buf mut [MaybeUninit]) -> 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]) -> 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::(), 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::(), 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> + for SendAncillaryBuffer<'_, 'slice, 'fd> +{ + fn extend>>(&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], + + /// 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]> for RecvAncillaryBuffer<'buf> { + fn from(buffer: &'buf mut [MaybeUninit]) -> 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]) -> 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]) -> &mut [MaybeUninit] { + // 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::(); + 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> { + // 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> { + 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::() { + let ucred = payload.as_ptr().cast::().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.messages + .find_map(|ev| Self::advance(&mut self.read_and_length, ev)) + } + + fn size_hint(&self) -> (usize, Option) { + let (_, max) = self.messages.size_hint(); + (0, max) + } + + fn fold(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 + where + Self: Sized, + { + self.messages + .filter_map(|ev| Self::advance(&mut self.read_and_length, ev)) + .last() + } + + fn collect>(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( + socket: Fd, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + flags: SendFlags, +) -> io::Result { + 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( + socket: Fd, + addr: &impl SocketAddrArg, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + flags: SendFlags, +) -> io::Result { + 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( + socket: Fd, + msgs: &mut [MMsgHdr<'_>], + flags: SendFlags, +) -> io::Result { + 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( + socket: Fd, + iov: &mut [IoSliceMut<'_>], + control: &mut RecvAncillaryBuffer<'_>, + flags: RecvFlags, +) -> io::Result { + 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, +} + +/// 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, +} + +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::(), 0); + + Self { + data, + _marker: PhantomData, + } + } +} + +impl<'data, T> Drop for AncillaryIter<'data, T> { + fn drop(&mut self) { + self.for_each(drop); + } +} + +impl Iterator for AncillaryIter<'_, T> { + type Item = T; + + fn next(&mut self) -> Option { + // See if there is a next item. + if self.data.len() < size_of::() { + return None; + } + + // Get the next item. + let item = unsafe { self.data.as_ptr().cast::().read_unaligned() }; + + // Move forward. + let data = take(&mut self.data); + self.data = &mut data[size_of::()..]; + + Some(item) + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } + + fn count(self) -> usize { + self.len() + } + + fn last(mut self) -> Option { + self.next_back() + } +} + +impl FusedIterator for AncillaryIter<'_, T> {} + +impl ExactSizeIterator for AncillaryIter<'_, T> { + fn len(&self) -> usize { + self.data.len() / size_of::() + } +} + +impl DoubleEndedIterator for AncillaryIter<'_, T> { + fn next_back(&mut self) -> Option { + // See if there is a next item. + if self.data.len() < size_of::() { + return None; + } + + // Get the next item. + let item = unsafe { + let ptr = self.data.as_ptr().add(self.data.len() - size_of::()); + ptr.cast::().read_unaligned() + }; + + // Move forward. + let len = self.data.len(); + let data = take(&mut self.data); + self.data = &mut data[..len - size_of::()]; + + 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>, + + /// Capture the original lifetime of the buffer. + _buffer: PhantomData<&'buf mut [MaybeUninit]>, + } + + pub(super) trait AllowedMsgBufType {} + impl AllowedMsgBufType for u8 {} + impl AllowedMsgBufType for MaybeUninit {} + + 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 { + // 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) { + 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<'_> {} +} diff --git a/vendor/rustix/src/net/socket.rs b/vendor/rustix/src/net/socket.rs new file mode 100644 index 00000000..fff302ad --- /dev/null +++ b/vendor/rustix/src/net/socket.rs @@ -0,0 +1,461 @@ +use crate::fd::OwnedFd; +use crate::net::addr::SocketAddrArg; +use crate::net::SocketAddrAny; +use crate::{backend, io}; +use backend::fd::AsFd; + +pub use crate::net::{AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}; +#[cfg(unix)] +pub use backend::net::addr::SocketAddrUnix; + +/// `socket(domain, type_, protocol)`—Creates a socket. +/// +/// POSIX guarantees that `socket` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// To pass extra flags such as [`SocketFlags::CLOEXEC`] or +/// [`SocketFlags::NONBLOCK`], use [`socket_with`]. +/// +/// # 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#socket +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/socket.html +/// [Linux]: https://man7.org/linux/man-pages/man2/socket.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/socket.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2 +/// [NetBSD]: https://man.netbsd.org/socket.2 +/// [OpenBSD]: https://man.openbsd.org/socket.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=socket§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/socket +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Creating-a-Socket.html +#[inline] +pub fn socket( + domain: AddressFamily, + type_: SocketType, + protocol: Option, +) -> io::Result { + backend::net::syscalls::socket(domain, type_, protocol) +} + +/// `socket_with(domain, type_ | flags, protocol)`—Creates a socket, with +/// flags. +/// +/// POSIX guarantees that `socket` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// `socket_with` is the same as [`socket`] but adds an additional flags +/// operand. +/// +/// # 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#socket +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/socket.html +/// [Linux]: https://man7.org/linux/man-pages/man2/socket.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/socket.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2 +/// [NetBSD]: https://man.netbsd.org/socket.2 +/// [OpenBSD]: https://man.openbsd.org/socket.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=socket§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/socket +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Creating-a-Socket.html +#[doc(alias("socket"))] +#[inline] +pub fn socket_with( + domain: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Option, +) -> io::Result { + backend::net::syscalls::socket_with(domain, type_, flags, protocol) +} + +/// `bind(sockfd, addr)`—Binds a socket to an 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#bind +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/bind.html +/// [Linux]: https://man7.org/linux/man-pages/man2/bind.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/bind.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2 +/// [NetBSD]: https://man.netbsd.org/bind.2 +/// [OpenBSD]: https://man.openbsd.org/bind.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=bind§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/bind +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Setting-Address.html +pub fn bind(sockfd: Fd, addr: &impl SocketAddrArg) -> io::Result<()> { + backend::net::syscalls::bind(sockfd.as_fd(), addr) +} + +/// `connect(sockfd, addr)`—Initiates a connection to an IP address. +/// +/// On Windows, a non-blocking socket returns [`Errno::WOULDBLOCK`] if the +/// connection cannot be completed immediately, rather than +/// `Errno::INPROGRESS`. +/// +/// # 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#connect +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/connect.html +/// [Linux]: https://man7.org/linux/man-pages/man2/connect.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/connect.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=connect&sektion=2 +/// [NetBSD]: https://man.netbsd.org/connect.2 +/// [OpenBSD]: https://man.openbsd.org/connect.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=connect§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/connect +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Connecting.html +/// [`Errno::WOULDBLOCK`]: io::Errno::WOULDBLOCK +pub fn connect(sockfd: Fd, addr: &impl SocketAddrArg) -> io::Result<()> { + backend::net::syscalls::connect(sockfd.as_fd(), addr) +} + +/// `connect(sockfd, {.sa_family = AF_UNSPEC}, sizeof(struct sockaddr))`— +/// Dissolve the socket's association. +/// +/// On UDP sockets, BSD platforms report [`Errno::AFNOSUPPORT`] or +/// [`Errno::INVAL`] even if the disconnect was successful. +/// +/// # 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#connect +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/connect.html +/// [Linux]: https://man7.org/linux/man-pages/man2/connect.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/connect.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=connect&sektion=2 +/// [NetBSD]: https://man.netbsd.org/connect.2 +/// [OpenBSD]: https://man.openbsd.org/connect.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=connect§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/connect +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Connecting.html +/// [`Errno::AFNOSUPPORT`]: io::Errno::AFNOSUPPORT +/// [`Errno::INVAL`]: io::Errno::INVAL +#[inline] +#[doc(alias = "connect")] +pub fn connect_unspec(sockfd: Fd) -> io::Result<()> { + backend::net::syscalls::connect_unspec(sockfd.as_fd()) +} + +/// `listen(fd, backlog)`—Enables listening for incoming connections. +/// +/// # 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#listen +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/listen.html +/// [Linux]: https://man7.org/linux/man-pages/man2/listen.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/listen.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=listen&sektion=2 +/// [NetBSD]: https://man.netbsd.org/listen.2 +/// [OpenBSD]: https://man.openbsd.org/listen.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=listen§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/listen +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Listening.html +#[inline] +pub fn listen(sockfd: Fd, backlog: i32) -> io::Result<()> { + backend::net::syscalls::listen(sockfd.as_fd(), backlog) +} + +/// `accept(fd, NULL, NULL)`—Accepts an incoming connection. +/// +/// Use [`acceptfrom`] to retrieve the peer address. +/// +/// POSIX guarantees that `accept` will use the lowest unused file descriptor, +/// however it is not safe in general to rely on this, as file descriptors may +/// be unexpectedly allocated on other threads or in libraries. +/// +/// See [`accept_with`] to pass additional flags. +/// +/// # 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#acceptthank-you-for-calling-port-3490. +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/accept.html +/// [Linux]: https://man7.org/linux/man-pages/man2/accept.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/accept.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=accept&sektion=2 +/// [NetBSD]: https://man.netbsd.org/accept.2 +/// [OpenBSD]: https://man.openbsd.org/accept.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=accept§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/accept +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Accepting-Connections.html +#[inline] +pub fn accept(sockfd: Fd) -> io::Result { + backend::net::syscalls::accept(sockfd.as_fd()) +} + +/// `accept4(fd, NULL, NULL, flags)`—Accepts an incoming connection, with +/// flags. +/// +/// Use [`acceptfrom_with`] to retrieve the peer address. +/// +/// Even though POSIX guarantees that this will use the lowest unused file +/// descriptor, it is not safe in general to rely on this, as file descriptors +/// may be unexpectedly allocated on other threads or in libraries. +/// +/// `accept_with` is the same as [`accept`] but adds an additional flags +/// operand. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/accept4.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=accept4&sektion=2 +/// [NetBSD]: https://man.netbsd.org/accept4.2 +/// [OpenBSD]: https://man.openbsd.org/accept4.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=accept4§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/accept4 +#[inline] +#[doc(alias = "accept4")] +pub fn accept_with(sockfd: Fd, flags: SocketFlags) -> io::Result { + backend::net::syscalls::accept_with(sockfd.as_fd(), flags) +} + +/// `accept(fd, &addr, &len)`—Accepts an incoming connection and returns the +/// peer address. +/// +/// Use [`accept`] if the peer address isn't needed. +/// +/// See [`acceptfrom_with`] to pass additional flags. +/// +/// # 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#acceptthank-you-for-calling-port-3490. +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/accept.html +/// [Linux]: https://man7.org/linux/man-pages/man2/accept.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/accept.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=accept&sektion=2 +/// [NetBSD]: https://man.netbsd.org/accept.2 +/// [OpenBSD]: https://man.openbsd.org/accept.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=accept§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/accept +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Accepting-Connections.html +#[inline] +#[doc(alias = "accept")] +pub fn acceptfrom(sockfd: Fd) -> io::Result<(OwnedFd, Option)> { + backend::net::syscalls::acceptfrom(sockfd.as_fd()) +} + +/// `accept4(fd, &addr, &len, flags)`—Accepts an incoming connection and +/// returns the peer address, with flags. +/// +/// Use [`accept_with`] if the peer address isn't needed. +/// +/// `acceptfrom_with` is the same as [`acceptfrom`] but adds an additional +/// flags operand. +/// +/// # References +/// - [Linux] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/accept4.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=accept4&sektion=2 +/// [NetBSD]: https://man.netbsd.org/accept4.2 +/// [OpenBSD]: https://man.openbsd.org/accept4.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=accept4§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/accept4 +#[inline] +#[doc(alias = "accept4")] +pub fn acceptfrom_with( + sockfd: Fd, + flags: SocketFlags, +) -> io::Result<(OwnedFd, Option)> { + backend::net::syscalls::acceptfrom_with(sockfd.as_fd(), flags) +} + +/// `shutdown(fd, how)`—Closes the read and/or write sides of a stream. +/// +/// # 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#close-and-shutdownget-outta-my-face +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/shutdown.html +/// [Linux]: https://man7.org/linux/man-pages/man2/shutdown.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/shutdown.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-shutdown +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=shutdown&sektion=2 +/// [NetBSD]: https://man.netbsd.org/shutdown.2 +/// [OpenBSD]: https://man.openbsd.org/shutdown.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=shutdown§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/shutdown +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Closing-a-Socket.html +#[inline] +pub fn shutdown(sockfd: Fd, how: Shutdown) -> io::Result<()> { + backend::net::syscalls::shutdown(sockfd.as_fd(), how) +} + +/// `getsockname(fd, addr, len)`—Returns the address a socket is bound to. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [Winsock] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/getsockname.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getsockname.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockname.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockname +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getsockname&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getsockname.2 +/// [OpenBSD]: https://man.openbsd.org/getsockname.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getsockname§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getsockname +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Reading-Address.html +#[inline] +pub fn getsockname(sockfd: Fd) -> io::Result { + backend::net::syscalls::getsockname(sockfd.as_fd()) +} + +/// `getpeername(fd, addr, len)`—Returns the address a socket is connected +/// to. +/// +/// # 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#getpeernamewho-are-you +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/getpeername.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpeername.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpeername.2.html +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getpeername +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=getpeername&sektion=2 +/// [NetBSD]: https://man.netbsd.org/getpeername.2 +/// [OpenBSD]: https://man.openbsd.org/getpeername.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=getpeername§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/getpeername +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Who-is-Connected.html +#[inline] +pub fn getpeername(sockfd: Fd) -> io::Result> { + backend::net::syscalls::getpeername(sockfd.as_fd()) +} diff --git a/vendor/rustix/src/net/socket_addr_any.rs b/vendor/rustix/src/net/socket_addr_any.rs new file mode 100644 index 00000000..7a953044 --- /dev/null +++ b/vendor/rustix/src/net/socket_addr_any.rs @@ -0,0 +1,344 @@ +//! The [`SocketAddrAny`] type and related utilities. + +#![allow(unsafe_code)] + +use crate::backend::c; +use crate::backend::net::read_sockaddr; +use crate::io::Errno; +use crate::net::addr::{SocketAddrArg, SocketAddrLen, SocketAddrOpaque, SocketAddrStorage}; +#[cfg(unix)] +use crate::net::SocketAddrUnix; +use crate::net::{AddressFamily, SocketAddr, SocketAddrV4, SocketAddrV6}; +use core::fmt; +use core::mem::{size_of, MaybeUninit}; +use core::num::NonZeroU32; + +/// Temporary buffer for creating a `SocketAddrAny` from a syscall that writes +/// to a `sockaddr_t` and `socklen_t` +/// +/// Unlike `SocketAddrAny`, this does not maintain the invariant that `len` +/// bytes are initialized. +pub(crate) struct SocketAddrBuf { + pub(crate) len: c::socklen_t, + pub(crate) storage: MaybeUninit, +} + +impl SocketAddrBuf { + #[inline] + pub(crate) const fn new() -> Self { + Self { + len: size_of::() as c::socklen_t, + storage: MaybeUninit::::uninit(), + } + } + + /// Convert the buffer into [`SocketAddrAny`]. + /// + /// # Safety + /// + /// A valid address must have been written into `self.storage` and its + /// length written into `self.len`. + #[inline] + pub(crate) unsafe fn into_any(self) -> SocketAddrAny { + SocketAddrAny::new(self.storage, bitcast!(self.len)) + } + + /// Convert the buffer into [`Option`]. + /// + /// This returns `None` if `len` is zero or other platform-specific + /// conditions define the address as empty. + /// + /// # Safety + /// + /// Either valid address must have been written into `self.storage` and its + /// length written into `self.len`, or `self.len` must have been set to 0. + #[inline] + pub(crate) unsafe fn into_any_option(self) -> Option { + let len = bitcast!(self.len); + if read_sockaddr::sockaddr_nonempty(self.storage.as_ptr().cast(), len) { + Some(SocketAddrAny::new(self.storage, len)) + } else { + None + } + } +} + +/// A type that can hold any kind of socket address, as a safe abstraction for +/// `sockaddr_storage`. +/// +/// Socket addresses can be converted to `SocketAddrAny` via the [`From`] and +/// [`Into`] traits. `SocketAddrAny` can be converted back to a specific socket +/// address type with [`TryFrom`] and [`TryInto`]. These implementations return +/// [`Errno::AFNOSUPPORT`] if the address family does not match the requested +/// type. +#[derive(Clone)] +#[doc(alias = "sockaddr_storage")] +pub struct SocketAddrAny { + // Invariants: + // - `len` is at least `size_of::()` + // - `len` is at most `size_of::()` + // - The first `len` bytes of `storage` are initialized. + pub(crate) len: NonZeroU32, + pub(crate) storage: MaybeUninit, +} + +impl SocketAddrAny { + /// Creates a socket address from `storage`, which is initialized for `len` + /// bytes. + /// + /// # Panics + /// + /// if `len` is smaller than the sockaddr header or larger than + /// `SocketAddrStorage`. + /// + /// # Safety + /// + /// - `storage` must contain a valid socket address. + /// - `len` bytes must be initialized. + #[inline] + pub const unsafe fn new(storage: MaybeUninit, len: SocketAddrLen) -> Self { + assert!(len as usize >= size_of::()); + assert!(len as usize <= size_of::()); + let len = NonZeroU32::new_unchecked(len); + Self { storage, len } + } + + /// Creates a socket address from reading from `ptr`, which points at `len` + /// initialized bytes. + /// + /// # Panics + /// + /// if `len` is smaller than the sockaddr header or larger than + /// `SocketAddrStorage`. + /// + /// # Safety + /// + /// - `ptr` must be a pointer to memory containing a valid socket address. + /// - `len` bytes must be initialized. + pub unsafe fn read(ptr: *const SocketAddrStorage, len: SocketAddrLen) -> Self { + assert!(len as usize >= size_of::()); + assert!(len as usize <= size_of::()); + let mut storage = MaybeUninit::::uninit(); + core::ptr::copy_nonoverlapping( + ptr.cast::(), + storage.as_mut_ptr().cast::(), + len as usize, + ); + let len = NonZeroU32::new_unchecked(len); + Self { storage, len } + } + + /// Gets the initialized part of the storage as bytes. + #[inline] + fn bytes(&self) -> &[u8] { + let len = self.len.get() as usize; + unsafe { core::slice::from_raw_parts(self.storage.as_ptr().cast(), len) } + } + + /// Gets the address family of this socket address. + #[inline] + pub fn address_family(&self) -> AddressFamily { + // SAFETY: Our invariants maintain that the `sa_family` field is + // initialized. + unsafe { + AddressFamily::from_raw(crate::backend::net::read_sockaddr::read_sa_family( + self.storage.as_ptr().cast(), + )) + } + } + + /// Returns a raw pointer to the sockaddr. + #[inline] + pub fn as_ptr(&self) -> *const SocketAddrStorage { + self.storage.as_ptr() + } + + /// Returns a raw mutable pointer to the sockaddr. + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut SocketAddrStorage { + self.storage.as_mut_ptr() + } + + /// Returns the length of the encoded sockaddr. + #[inline] + pub fn addr_len(&self) -> SocketAddrLen { + self.len.get() + } +} + +impl PartialEq for SocketAddrAny { + fn eq(&self, other: &Self) -> bool { + self.bytes() == other.bytes() + } +} + +impl Eq for SocketAddrAny {} + +// This just forwards to another `partial_cmp`. +#[allow(clippy::non_canonical_partial_ord_impl)] +impl PartialOrd for SocketAddrAny { + fn partial_cmp(&self, other: &Self) -> Option { + self.bytes().partial_cmp(other.bytes()) + } +} + +impl Ord for SocketAddrAny { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.bytes().cmp(other.bytes()) + } +} + +impl core::hash::Hash for SocketAddrAny { + fn hash(&self, state: &mut H) { + self.bytes().hash(state) + } +} + +impl fmt::Debug for SocketAddrAny { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.address_family() { + AddressFamily::INET => { + if let Ok(addr) = SocketAddrV4::try_from(self.clone()) { + return addr.fmt(f); + } + } + AddressFamily::INET6 => { + if let Ok(addr) = SocketAddrV6::try_from(self.clone()) { + return addr.fmt(f); + } + } + #[cfg(unix)] + AddressFamily::UNIX => { + if let Ok(addr) = SocketAddrUnix::try_from(self.clone()) { + return addr.fmt(f); + } + } + #[cfg(target_os = "linux")] + AddressFamily::XDP => { + if let Ok(addr) = crate::net::xdp::SocketAddrXdp::try_from(self.clone()) { + return addr.fmt(f); + } + } + #[cfg(linux_kernel)] + AddressFamily::NETLINK => { + if let Ok(addr) = crate::net::netlink::SocketAddrNetlink::try_from(self.clone()) { + return addr.fmt(f); + } + } + _ => {} + } + + f.debug_struct("SocketAddrAny") + .field("address_family", &self.address_family()) + .field("namelen", &self.addr_len()) + .finish() + } +} + +// SAFETY: `with_sockaddr` calls `f` with a pointer to its own storage. +unsafe impl SocketAddrArg for SocketAddrAny { + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R { + f(self.as_ptr().cast(), self.addr_len()) + } +} + +impl From for SocketAddrAny { + #[inline] + fn from(from: SocketAddr) -> Self { + from.as_any() + } +} + +impl TryFrom for SocketAddr { + type Error = Errno; + + /// Convert if the address is an IPv4 or IPv6 address. + /// + /// Returns `Err(Errno::AFNOSUPPORT)` if the address family is not IPv4 or + /// IPv6. + #[inline] + fn try_from(value: SocketAddrAny) -> Result { + match value.address_family() { + AddressFamily::INET => read_sockaddr::read_sockaddr_v4(&value).map(SocketAddr::V4), + AddressFamily::INET6 => read_sockaddr::read_sockaddr_v6(&value).map(SocketAddr::V6), + _ => Err(Errno::AFNOSUPPORT), + } + } +} + +impl From for SocketAddrAny { + #[inline] + fn from(from: SocketAddrV4) -> Self { + from.as_any() + } +} + +impl TryFrom for SocketAddrV4 { + type Error = Errno; + + /// Convert if the address is an IPv4 address. + /// + /// Returns `Err(Errno::AFNOSUPPORT)` if the address family is not IPv4. + #[inline] + fn try_from(value: SocketAddrAny) -> Result { + read_sockaddr::read_sockaddr_v4(&value) + } +} + +impl From for SocketAddrAny { + #[inline] + fn from(from: SocketAddrV6) -> Self { + from.as_any() + } +} + +impl TryFrom for SocketAddrV6 { + type Error = Errno; + + /// Convert if the address is an IPv6 address. + /// + /// Returns `Err(Errno::AFNOSUPPORT)` if the address family is not IPv6. + #[inline] + fn try_from(value: SocketAddrAny) -> Result { + read_sockaddr::read_sockaddr_v6(&value) + } +} + +#[cfg(unix)] +impl From for SocketAddrAny { + #[inline] + fn from(from: SocketAddrUnix) -> Self { + from.as_any() + } +} + +#[cfg(unix)] +impl TryFrom for SocketAddrUnix { + type Error = Errno; + + /// Convert if the address is a Unix socket address. + /// + /// Returns `Err(Errno::AFNOSUPPORT)` if the address family is not Unix. + #[inline] + fn try_from(value: SocketAddrAny) -> Result { + read_sockaddr::read_sockaddr_unix(&value) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn any_read() { + let localhost = std::net::Ipv6Addr::LOCALHOST; + let addr = SocketAddrAny::from(SocketAddrV6::new(localhost, 7, 8, 9)); + unsafe { + let same = SocketAddrAny::read(addr.as_ptr(), addr.addr_len()); + assert_eq!(addr, same); + } + } +} diff --git a/vendor/rustix/src/net/socketpair.rs b/vendor/rustix/src/net/socketpair.rs new file mode 100644 index 00000000..29227f96 --- /dev/null +++ b/vendor/rustix/src/net/socketpair.rs @@ -0,0 +1,36 @@ +use crate::fd::OwnedFd; +use crate::net::{AddressFamily, Protocol, SocketFlags, SocketType}; +use crate::{backend, io}; + +/// `socketpair(domain, type_ | accept_flags, protocol)`—Create a pair of +/// sockets that are connected to each other. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/socketpair.html +/// [Linux]: https://man7.org/linux/man-pages/man2/socketpair.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/socketpair.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=socketpair&sektion=2 +/// [NetBSD]: https://man.netbsd.org/socketpair.2 +/// [OpenBSD]: https://man.openbsd.org/socketpair.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=socketpair§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/socketpair +/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Socket-Pairs.html +#[inline] +pub fn socketpair( + domain: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Option, +) -> io::Result<(OwnedFd, OwnedFd)> { + backend::net::syscalls::socketpair(domain, type_, flags, protocol) +} diff --git a/vendor/rustix/src/net/sockopt.rs b/vendor/rustix/src/net/sockopt.rs new file mode 100644 index 00000000..ef8176ae --- /dev/null +++ b/vendor/rustix/src/net/sockopt.rs @@ -0,0 +1,1649 @@ +//! `getsockopt` and `setsockopt` functions. +//! +//! In the rustix API, there is a separate function for each option, so that it +//! can be given an option-specific type signature. +//! +//! # References for all getter functions: +//! +//! - [POSIX `getsockopt`] +//! - [Linux `getsockopt`] +//! - [Winsock `getsockopt`] +//! - [Apple `getsockopt`] +//! - [FreeBSD `getsockopt`] +//! - [NetBSD `getsockopt`] +//! - [OpenBSD `getsockopt`] +//! - [DragonFly BSD `getsockopt`] +//! - [illumos `getsockopt`] +//! - [glibc `getsockopt`] +//! +//! [POSIX `getsockopt`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/getsockopt.html +//! [Linux `getsockopt`]: https://man7.org/linux/man-pages/man2/getsockopt.2.html +//! [Winsock `getsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-getsockopt +//! [Apple `getsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html +//! [FreeBSD `getsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=getsockopt&sektion=2 +//! [NetBSD `getsockopt`]: https://man.netbsd.org/getsockopt.2 +//! [OpenBSD `getsockopt`]: https://man.openbsd.org/getsockopt.2 +//! [DragonFly BSD `getsockopt`]: https://man.dragonflybsd.org/?command=getsockopt§ion=2 +//! [illumos `getsockopt`]: https://illumos.org/man/3SOCKET/getsockopt +//! [glibc `getsockopt`]: https://sourceware.org/glibc/manual/latest/html_node/Socket-Option-Functions.html +//! +//! # References for all `set_*` functions: +//! +//! - [POSIX `setsockopt`] +//! - [Linux `setsockopt`] +//! - [Winsock `setsockopt`] +//! - [Apple `setsockopt`] +//! - [FreeBSD `setsockopt`] +//! - [NetBSD `setsockopt`] +//! - [OpenBSD `setsockopt`] +//! - [DragonFly BSD `setsockopt`] +//! - [illumos `setsockopt`] +//! - [glibc `setsockopt`] +//! +//! [POSIX `setsockopt`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/setsockopt.html +//! [Linux `setsockopt`]: https://man7.org/linux/man-pages/man2/setsockopt.2.html +//! [Winsock `setsockopt`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt +//! [Apple `setsockopt`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html +//! [FreeBSD `setsockopt`]: https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2 +//! [NetBSD `setsockopt`]: https://man.netbsd.org/setsockopt.2 +//! [OpenBSD `setsockopt`]: https://man.openbsd.org/setsockopt.2 +//! [DragonFly BSD `setsockopt`]: https://man.dragonflybsd.org/?command=setsockopt§ion=2 +//! [illumos `setsockopt`]: https://illumos.org/man/3SOCKET/setsockopt +//! [glibc `setsockopt`]: https://sourceware.org/glibc/manual/latest/html_node/Socket-Option-Functions.html +//! +//! # References for `get_socket_*` and `set_socket_*` functions: +//! +//! - [References for all getter functions] +//! - [References for all `set_*` functions] +//! - [POSIX `sys/socket.h`] +//! - [Linux `socket`] +//! - [Winsock `SOL_SOCKET` options] +//! - [glibc `SOL_SOCKET` Options] +//! +//! [POSIX `sys/socket.h`]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html +//! [Linux `socket`]: https://man7.org/linux/man-pages/man7/socket.7.html +//! [Winsock `SOL_SOCKET` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options +//! [glibc `SOL_SOCKET` options]: https://sourceware.org/glibc/manual/latest/html_node/Socket_002dLevel-Options.html +//! +//! # References for `get_ip_*` and `set_ip_*` functions: +//! +//! - [References for all getter functions] +//! - [References for all `set_*` functions] +//! - [POSIX `netinet/in.h`] +//! - [Linux `ip`] +//! - [Winsock `IPPROTO_IP` options] +//! - [Apple `ip`] +//! - [FreeBSD `ip`] +//! - [NetBSD `ip`] +//! - [OpenBSD `ip`] +//! - [DragonFly BSD `ip`] +//! - [illumos `ip`] +//! +//! [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/netinet_in.h.html +//! [Linux `ip`]: https://man7.org/linux/man-pages/man7/ip.7.html +//! [Winsock `IPPROTO_IP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options +//! [Apple `ip`]: https://github.com/apple-oss-distributions/xnu/blob/main/bsd/man/man4/ip.4 +//! [FreeBSD `ip`]: https://man.freebsd.org/cgi/man.cgi?query=ip&sektion=4 +//! [NetBSD `ip`]: https://man.netbsd.org/ip.4 +//! [OpenBSD `ip`]: https://man.openbsd.org/ip.4 +//! [DragonFly BSD `ip`]: https://man.dragonflybsd.org/?command=ip§ion=4 +//! [illumos `ip`]: https://illumos.org/man/4P/ip +//! +//! # References for `get_ipv6_*` and `set_ipv6_*` functions: +//! +//! - [References for all getter functions] +//! - [References for all `set_*` functions] +//! - [POSIX `netinet/in.h`] +//! - [Linux `ipv6`] +//! - [Winsock `IPPROTO_IPV6` options] +//! - [Apple `ip6`] +//! - [FreeBSD `ip6`] +//! - [NetBSD `ip6`] +//! - [OpenBSD `ip6`] +//! - [DragonFly BSD `ip6`] +//! - [illumos `ip6`] +//! +//! [POSIX `netinet/in.h`]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/netinet_in.h.html +//! [Linux `ipv6`]: https://man7.org/linux/man-pages/man7/ipv6.7.html +//! [Winsock `IPPROTO_IPV6` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options +//! [Apple `ip6`]: https://github.com/apple-oss-distributions/xnu/blob/main/bsd/man/man4/ip6.4 +//! [FreeBSD `ip6`]: https://man.freebsd.org/cgi/man.cgi?query=ip6&sektion=4 +//! [NetBSD `ip6`]: https://man.netbsd.org/ip6.4 +//! [OpenBSD `ip6`]: https://man.openbsd.org/ip6.4 +//! [DragonFly BSD `ip6`]: https://man.dragonflybsd.org/?command=ip6§ion=4 +//! [illumos `ip6`]: https://illumos.org/man/4P/ip6 +//! +//! # References for `get_tcp_*` and `set_tcp_*` functions: +//! +//! - [References for all getter functions] +//! - [References for all `set_*` functions] +//! - [POSIX `netinet/tcp.h`] +//! - [Linux `tcp`] +//! - [Winsock `IPPROTO_TCP` options] +//! - [Apple `tcp`] +//! - [FreeBSD `tcp`] +//! - [NetBSD `tcp`] +//! - [OpenBSD `tcp`] +//! - [DragonFly BSD `tcp`] +//! - [illumos `tcp`] +//! +//! [POSIX `netinet/tcp.h`]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/netinet_tcp.h.html +//! [Linux `tcp`]: https://man7.org/linux/man-pages/man7/tcp.7.html +//! [Winsock `IPPROTO_TCP` options]: https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options +//! [Apple `tcp`]: https://github.com/apple-oss-distributions/xnu/blob/main/bsd/man/man4/tcp.4 +//! [FreeBSD `tcp`]: https://man.freebsd.org/cgi/man.cgi?query=tcp&sektion=4 +//! [NetBSD `tcp`]: https://man.netbsd.org/tcp.4 +//! [OpenBSD `tcp`]: https://man.openbsd.org/tcp.4 +//! [DragonFly BSD `tcp`]: https://man.dragonflybsd.org/?command=tcp§ion=4 +//! [illumos `tcp`]: https://illumos.org/man/4P/tcp +//! +//! [References for all getter functions]: #references-for-all-getter-functions +//! [References for all `set_*` functions]: #references-for-all-set_-functions + +#![doc(alias = "getsockopt")] +#![doc(alias = "setsockopt")] + +#[cfg(target_os = "linux")] +use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpStatistics, XdpUmemReg}; +#[cfg(not(any( + apple, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "espidf", + target_os = "haiku", + target_os = "netbsd", + target_os = "nto", + target_os = "vita", +)))] +use crate::net::AddressFamily; +#[cfg(any( + linux_kernel, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "redox", + target_env = "newlib" +))] +use crate::net::Protocol; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +use crate::net::SocketAddrV4; +#[cfg(linux_kernel)] +use crate::net::SocketAddrV6; +use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; +use crate::{backend, io}; +#[cfg(feature = "alloc")] +#[cfg(any( + linux_like, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos" +))] +use alloc::string::String; +use backend::c; +use backend::fd::AsFd; +use core::time::Duration; + +/// Timeout identifier for use with [`set_socket_timeout`] and +/// [`socket_timeout`]. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum Timeout { + /// `SO_RCVTIMEO`—Timeout for receiving. + Recv = c::SO_RCVTIMEO as _, + + /// `SO_SNDTIMEO`—Timeout for sending. + Send = c::SO_SNDTIMEO as _, +} + +/// `getsockopt(fd, SOL_SOCKET, SO_TYPE)`—Returns the type of a socket. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_TYPE")] +pub fn socket_type(fd: Fd) -> io::Result { + backend::net::sockopt::socket_type(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, value)`—Set whether local +/// addresses may be reused in `bind`. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_REUSEADDR")] +pub fn set_socket_reuseaddr(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_socket_reuseaddr(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_REUSEADDR)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_REUSEADDR")] +pub fn socket_reuseaddr(fd: Fd) -> io::Result { + backend::net::sockopt::socket_reuseaddr(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_BROADCAST, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_BROADCAST")] +pub fn set_socket_broadcast(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_socket_broadcast(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_BROADCAST)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_BROADCAST")] +pub fn socket_broadcast(fd: Fd) -> io::Result { + backend::net::sockopt::socket_broadcast(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_LINGER, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_LINGER")] +pub fn set_socket_linger(fd: Fd, value: Option) -> io::Result<()> { + backend::net::sockopt::set_socket_linger(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_LINGER)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_LINGER")] +pub fn socket_linger(fd: Fd) -> io::Result> { + backend::net::sockopt::socket_linger(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_PASSCRED, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "SO_PASSCRED")] +pub fn set_socket_passcred(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_socket_passcred(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_PASSCRED)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "SO_PASSCRED")] +pub fn socket_passcred(fd: Fd) -> io::Result { + backend::net::sockopt::socket_passcred(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, id, value)`—Set the sending or receiving +/// timeout. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_RCVTIMEO")] +#[doc(alias = "SO_SNDTIMEO")] +pub fn set_socket_timeout( + fd: Fd, + id: Timeout, + value: Option, +) -> io::Result<()> { + backend::net::sockopt::set_socket_timeout(fd.as_fd(), id, value) +} + +/// `getsockopt(fd, SOL_SOCKET, id)`—Get the sending or receiving timeout. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_RCVTIMEO")] +#[doc(alias = "SO_SNDTIMEO")] +pub fn socket_timeout(fd: Fd, id: Timeout) -> io::Result> { + backend::net::sockopt::socket_timeout(fd.as_fd(), id) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_ERROR)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_ERROR")] +pub fn socket_error(fd: Fd) -> io::Result> { + backend::net::sockopt::socket_error(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(any(apple, freebsdlike, target_os = "netbsd"))] +#[doc(alias = "SO_NOSIGPIPE")] +#[inline] +pub fn socket_nosigpipe(fd: Fd) -> io::Result { + backend::net::sockopt::socket_nosigpipe(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(any(apple, freebsdlike, target_os = "netbsd"))] +#[doc(alias = "SO_NOSIGPIPE")] +#[inline] +pub fn set_socket_nosigpipe(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_socket_nosigpipe(fd.as_fd(), value) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_KEEPALIVE")] +pub fn set_socket_keepalive(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_socket_keepalive(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_KEEPALIVE)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_KEEPALIVE")] +pub fn socket_keepalive(fd: Fd) -> io::Result { + backend::net::sockopt::socket_keepalive(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_RCVBUF, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_RCVBUF")] +pub fn set_socket_recv_buffer_size(fd: Fd, value: usize) -> io::Result<()> { + backend::net::sockopt::set_socket_recv_buffer_size(fd.as_fd(), value) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(any(linux_kernel, target_os = "fuchsia", target_os = "redox"))] +#[inline] +#[doc(alias = "SO_RCVBUFFORCE")] +pub fn set_socket_recv_buffer_size_force(fd: Fd, value: usize) -> io::Result<()> { + backend::net::sockopt::set_socket_recv_buffer_size_force(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_RCVBUF)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_RCVBUF")] +pub fn socket_recv_buffer_size(fd: Fd) -> io::Result { + backend::net::sockopt::socket_recv_buffer_size(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_SNDBUF, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_SNDBUF")] +pub fn set_socket_send_buffer_size(fd: Fd, value: usize) -> io::Result<()> { + backend::net::sockopt::set_socket_send_buffer_size(fd.as_fd(), value) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(any(linux_kernel, target_os = "fuchsia", target_os = "redox"))] +#[inline] +#[doc(alias = "SO_SNDBUFFORCE")] +pub fn set_socket_send_buffer_size_force(fd: Fd, value: usize) -> io::Result<()> { + backend::net::sockopt::set_socket_send_buffer_size_force(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_SNDBUF)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_SNDBUF")] +pub fn socket_send_buffer_size(fd: Fd) -> io::Result { + backend::net::sockopt::socket_send_buffer_size(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_DOMAIN)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(not(any( + apple, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "netbsd", + target_os = "nto", + target_os = "vita", +)))] +#[inline] +#[doc(alias = "SO_DOMAIN")] +pub fn socket_domain(fd: Fd) -> io::Result { + backend::net::sockopt::socket_domain(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(not(apple))] // Apple platforms declare the constant, but do not actually implement it. +#[inline] +#[doc(alias = "SO_ACCEPTCONN")] +pub fn socket_acceptconn(fd: Fd) -> io::Result { + backend::net::sockopt::socket_acceptconn(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_OOBINLINE")] +pub fn set_socket_oobinline(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_socket_oobinline(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_OOBINLINE)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "SO_OOBINLINE")] +pub fn socket_oobinline(fd: Fd) -> io::Result { + backend::net::sockopt::socket_oobinline(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(not(any(solarish, windows, target_os = "cygwin")))] +#[cfg(not(windows))] +#[inline] +#[doc(alias = "SO_REUSEPORT")] +pub fn set_socket_reuseport(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_socket_reuseport(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_REUSEPORT)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(not(any(solarish, windows, target_os = "cygwin")))] +#[inline] +#[doc(alias = "SO_REUSEPORT")] +pub fn socket_reuseport(fd: Fd) -> io::Result { + backend::net::sockopt::socket_reuseport(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(target_os = "freebsd")] +#[inline] +#[doc(alias = "SO_REUSEPORT_LB")] +pub fn set_socket_reuseport_lb(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_socket_reuseport_lb(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(target_os = "freebsd")] +#[inline] +#[doc(alias = "SO_REUSEPORT_LB")] +pub fn socket_reuseport_lb(fd: Fd) -> io::Result { + backend::net::sockopt::socket_reuseport_lb(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_PROTOCOL)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(any( + linux_kernel, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "redox", + target_env = "newlib" +))] +#[inline] +#[doc(alias = "SO_PROTOCOL")] +pub fn socket_protocol(fd: Fd) -> io::Result> { + backend::net::sockopt::socket_protocol(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_COOKIE)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(target_os = "linux")] +#[inline] +#[doc(alias = "SO_COOKIE")] +pub fn socket_cookie(fd: Fd) -> io::Result { + backend::net::sockopt::socket_cookie(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(target_os = "linux")] +#[inline] +#[doc(alias = "SO_INCOMING_CPU")] +pub fn socket_incoming_cpu(fd: Fd) -> io::Result { + backend::net::sockopt::socket_incoming_cpu(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[cfg(target_os = "linux")] +#[inline] +#[doc(alias = "SO_INCOMING_CPU")] +pub fn set_socket_incoming_cpu(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_socket_incoming_cpu(fd.as_fd(), value) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_TTL, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_socket_-and-set_socket_-functions +#[inline] +#[doc(alias = "IP_TTL")] +pub fn set_ip_ttl(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_ip_ttl(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_TTL)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_TTL")] +pub fn ip_ttl(fd: Fd) -> io::Result { + backend::net::sockopt::ip_ttl(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_V6ONLY")] +pub fn set_ipv6_v6only(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_ipv6_v6only(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_V6ONLY")] +pub fn ipv6_v6only(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_v6only(fd.as_fd()) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_MTU)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[cfg(any(linux_kernel, target_os = "cygwin"))] +#[doc(alias = "IP_MTU")] +pub fn ip_mtu(fd: Fd) -> io::Result { + backend::net::sockopt::ip_mtu(fd.as_fd()) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MTU)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[cfg(any(linux_kernel, target_os = "cygwin"))] +#[doc(alias = "IPV6_MTU")] +pub fn ipv6_mtu(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_mtu(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_MULTICAST_IF")] +pub fn set_ip_multicast_if(fd: Fd, value: &Ipv4Addr) -> io::Result<()> { + backend::net::sockopt::set_ip_multicast_if(fd.as_fd(), value) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, multiaddr, address, +/// ifindex)` +/// +/// This is similar to [`set_ip_multicast_if`] but additionally allows an +/// `ifindex` value to be given. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any( + apple, + freebsdlike, + linux_like, + target_os = "fuchsia", + target_os = "openbsd" +))] +#[inline] +#[doc(alias = "IP_MULTICAST_IF")] +pub fn set_ip_multicast_if_with_ifindex( + fd: Fd, + multiaddr: &Ipv4Addr, + address: &Ipv4Addr, + ifindex: u32, +) -> io::Result<()> { + backend::net::sockopt::set_ip_multicast_if_with_ifindex(fd.as_fd(), multiaddr, address, ifindex) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_MULTICAST_IF")] +pub fn ip_multicast_if(fd: Fd) -> io::Result { + backend::net::sockopt::ip_multicast_if(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IPV6_MULTICAST_IF")] +pub fn set_ipv6_multicast_if(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_ipv6_multicast_if(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IPV6_MULTICAST_IF")] +pub fn ipv6_multicast_if(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_multicast_if(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_MULTICAST_LOOP")] +pub fn set_ip_multicast_loop(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_ip_multicast_loop(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_MULTICAST_LOOP")] +pub fn ip_multicast_loop(fd: Fd) -> io::Result { + backend::net::sockopt::ip_multicast_loop(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_MULTICAST_TTL")] +pub fn set_ip_multicast_ttl(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_ip_multicast_ttl(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_MULTICAST_TTL")] +pub fn ip_multicast_ttl(fd: Fd) -> io::Result { + backend::net::sockopt::ip_multicast_ttl(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_MULTICAST_LOOP")] +pub fn set_ipv6_multicast_loop(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_ipv6_multicast_loop(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_MULTICAST_LOOP")] +pub fn ipv6_multicast_loop(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_multicast_loop(fd.as_fd()) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_UNICAST_HOPS")] +pub fn ipv6_unicast_hops(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_unicast_hops(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_UNICAST_HOPS")] +pub fn set_ipv6_unicast_hops(fd: Fd, value: Option) -> io::Result<()> { + backend::net::sockopt::set_ipv6_unicast_hops(fd.as_fd(), value) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_MULTICAST_HOPS")] +pub fn set_ipv6_multicast_hops(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_ipv6_multicast_hops(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_MULTICAST_HOPS")] +pub fn ipv6_multicast_hops(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_multicast_hops(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, multiaddr, interface)` +/// +/// This is similar to [`set_ip_add_membership`] but always sets the `ifindex` +/// value to zero. See [`set_ip_add_membership_with_ifindex`] instead to also +/// give the `ifindex` value. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_ADD_MEMBERSHIP")] +pub fn set_ip_add_membership( + fd: Fd, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, +) -> io::Result<()> { + backend::net::sockopt::set_ip_add_membership(fd.as_fd(), multiaddr, interface) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, multiaddr, address, +/// ifindex)` +/// +/// This is similar to [`set_ip_add_membership`] but additionally allows an +/// `ifindex` value to be given. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any( + apple, + freebsdlike, + linux_like, + target_os = "fuchsia", + target_os = "openbsd" +))] +#[inline] +#[doc(alias = "IP_ADD_MEMBERSHIP")] +pub fn set_ip_add_membership_with_ifindex( + fd: Fd, + multiaddr: &Ipv4Addr, + address: &Ipv4Addr, + ifindex: u32, +) -> io::Result<()> { + backend::net::sockopt::set_ip_add_membership_with_ifindex( + fd.as_fd(), + multiaddr, + address, + ifindex, + ) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any(apple, freebsdlike, linux_like, solarish, target_os = "aix"))] +#[inline] +#[doc(alias = "IP_ADD_SOURCE_MEMBERSHIP")] +pub fn set_ip_add_source_membership( + fd: Fd, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + sourceaddr: &Ipv4Addr, +) -> io::Result<()> { + backend::net::sockopt::set_ip_add_source_membership( + fd.as_fd(), + multiaddr, + interface, + sourceaddr, + ) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any(apple, freebsdlike, linux_like, solarish, target_os = "aix"))] +#[inline] +#[doc(alias = "IP_DROP_SOURCE_MEMBERSHIP")] +pub fn set_ip_drop_source_membership( + fd: Fd, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + sourceaddr: &Ipv4Addr, +) -> io::Result<()> { + backend::net::sockopt::set_ip_drop_source_membership( + fd.as_fd(), + multiaddr, + interface, + sourceaddr, + ) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, multiaddr, interface)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_JOIN_GROUP")] +#[doc(alias = "IPV6_ADD_MEMBERSHIP")] +pub fn set_ipv6_add_membership( + fd: Fd, + multiaddr: &Ipv6Addr, + interface: u32, +) -> io::Result<()> { + backend::net::sockopt::set_ipv6_add_membership(fd.as_fd(), multiaddr, interface) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, multiaddr, interface)` +/// +/// This is similar to [`set_ip_drop_membership`] but always sets `ifindex` +/// value to zero. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[inline] +#[doc(alias = "IP_DROP_MEMBERSHIP")] +pub fn set_ip_drop_membership( + fd: Fd, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, +) -> io::Result<()> { + backend::net::sockopt::set_ip_drop_membership(fd.as_fd(), multiaddr, interface) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, multiaddr, interface)` +/// +/// This is similar to [`set_ip_drop_membership_with_ifindex`] but additionally +/// allows a `ifindex` value to be given. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any( + apple, + freebsdlike, + linux_like, + target_os = "fuchsia", + target_os = "openbsd" +))] +#[inline] +#[doc(alias = "IP_DROP_MEMBERSHIP")] +pub fn set_ip_drop_membership_with_ifindex( + fd: Fd, + multiaddr: &Ipv4Addr, + address: &Ipv4Addr, + ifindex: u32, +) -> io::Result<()> { + backend::net::sockopt::set_ip_drop_membership_with_ifindex( + fd.as_fd(), + multiaddr, + address, + ifindex, + ) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, multiaddr, interface)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[inline] +#[doc(alias = "IPV6_LEAVE_GROUP")] +#[doc(alias = "IPV6_DROP_MEMBERSHIP")] +pub fn set_ipv6_drop_membership( + fd: Fd, + multiaddr: &Ipv6Addr, + interface: u32, +) -> io::Result<()> { + backend::net::sockopt::set_ipv6_drop_membership(fd.as_fd(), multiaddr, interface) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_TOS, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any( + bsd, + linux_like, + target_os = "aix", + target_os = "fuchsia", + target_os = "haiku", + target_os = "nto", + target_env = "newlib" +))] +#[inline] +#[doc(alias = "IP_TOS")] +pub fn set_ip_tos(fd: Fd, value: u8) -> io::Result<()> { + backend::net::sockopt::set_ip_tos(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_TOS)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any( + bsd, + linux_like, + target_os = "aix", + target_os = "fuchsia", + target_os = "haiku", + target_os = "nto", + target_env = "newlib" +))] +#[inline] +#[doc(alias = "IP_TOS")] +pub fn ip_tos(fd: Fd) -> io::Result { + backend::net::sockopt::ip_tos(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_RECVTOS, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any( + apple, + linux_like, + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", +))] +#[inline] +#[doc(alias = "IP_RECVTOS")] +pub fn set_ip_recvtos(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_ip_recvtos(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_RECVTOS)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ip_-and-set_ip_-functions +#[cfg(any( + apple, + linux_like, + target_os = "cygwin", + target_os = "freebsd", + target_os = "fuchsia", +))] +#[inline] +#[doc(alias = "IP_RECVTOS")] +pub fn ip_recvtos(fd: Fd) -> io::Result { + backend::net::sockopt::ip_recvtos(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_RECVTCLASS, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any( + bsd, + linux_like, + target_os = "aix", + target_os = "fuchsia", + target_os = "nto" +))] +#[inline] +#[doc(alias = "IPV6_RECVTCLASS")] +pub fn set_ipv6_recvtclass(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_ipv6_recvtclass(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_RECVTCLASS)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any( + bsd, + linux_like, + target_os = "aix", + target_os = "fuchsia", + target_os = "nto" +))] +#[inline] +#[doc(alias = "IPV6_RECVTCLASS")] +pub fn ipv6_recvtclass(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_recvtclass(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IP, IP_FREEBIND, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "IP_FREEBIND")] +pub fn set_ip_freebind(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_ip_freebind(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IP, IP_FREEBIND)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "IP_FREEBIND")] +pub fn ip_freebind(fd: Fd) -> io::Result { + backend::net::sockopt::ip_freebind(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_FREEBIND, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "IPV6_FREEBIND")] +pub fn set_ipv6_freebind(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_ipv6_freebind(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_FREEBIND)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "IPV6_FREEBIND")] +pub fn ipv6_freebind(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_freebind(fd.as_fd()) +} + +/// `getsockopt(fd, IPPROTO_IP, SO_ORIGINAL_DST)` +/// +/// Even though this corresponds to a `SO_*` constant, it is an `IPPROTO_IP` +/// option. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "SO_ORIGINAL_DST")] +pub fn ip_original_dst(fd: Fd) -> io::Result { + backend::net::sockopt::ip_original_dst(fd.as_fd()) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST)` +/// +/// Even though this corresponds to a `IP6T_*` constant, it is an +/// `IPPROTO_IPV6` option. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "IP6T_SO_ORIGINAL_DST")] +pub fn ipv6_original_dst(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_original_dst(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(not(any( + solarish, + windows, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" +)))] +#[inline] +#[doc(alias = "IPV6_TCLASS")] +pub fn set_ipv6_tclass(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_ipv6_tclass(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_ipv6_-and-set_ipv6_-functions +#[cfg(not(any( + solarish, + windows, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" +)))] +#[inline] +#[doc(alias = "IPV6_TCLASS")] +pub fn ipv6_tclass(fd: Fd) -> io::Result { + backend::net::sockopt::ipv6_tclass(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[inline] +#[doc(alias = "TCP_NODELAY")] +pub fn set_tcp_nodelay(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_tcp_nodelay(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_NODELAY)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[inline] +#[doc(alias = "TCP_NODELAY")] +pub fn tcp_nodelay(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_nodelay(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(not(any( + target_os = "haiku", + target_os = "nto", + target_os = "openbsd", + target_os = "redox" +)))] +#[inline] +#[doc(alias = "TCP_KEEPCNT")] +pub fn set_tcp_keepcnt(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_tcp_keepcnt(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(not(any( + target_os = "haiku", + target_os = "nto", + target_os = "openbsd", + target_os = "redox" +)))] +#[inline] +#[doc(alias = "TCP_KEEPCNT")] +pub fn tcp_keepcnt(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_keepcnt(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, value)` +/// +/// `TCP_KEEPALIVE` on Apple platforms. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(not(any(target_os = "haiku", target_os = "nto", target_os = "openbsd")))] +#[inline] +#[doc(alias = "TCP_KEEPIDLE")] +pub fn set_tcp_keepidle(fd: Fd, value: Duration) -> io::Result<()> { + backend::net::sockopt::set_tcp_keepidle(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE)` +/// +/// `TCP_KEEPALIVE` on Apple platforms. +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(not(any(target_os = "haiku", target_os = "nto", target_os = "openbsd")))] +#[inline] +#[doc(alias = "TCP_KEEPIDLE")] +pub fn tcp_keepidle(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_keepidle(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(not(any( + target_os = "haiku", + target_os = "nto", + target_os = "openbsd", + target_os = "redox" +)))] +#[inline] +#[doc(alias = "TCP_KEEPINTVL")] +pub fn set_tcp_keepintvl(fd: Fd, value: Duration) -> io::Result<()> { + backend::net::sockopt::set_tcp_keepintvl(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(not(any( + target_os = "haiku", + target_os = "nto", + target_os = "openbsd", + target_os = "redox" +)))] +#[inline] +#[doc(alias = "TCP_KEEPINTVL")] +pub fn tcp_keepintvl(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_keepintvl(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "TCP_USER_TIMEOUT")] +pub fn set_tcp_user_timeout(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_tcp_user_timeout(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "TCP_USER_TIMEOUT")] +pub fn tcp_user_timeout(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_user_timeout(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "TCP_QUICKACK")] +pub fn set_tcp_quickack(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_tcp_quickack(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_QUICKACK)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "TCP_QUICKACK")] +pub fn tcp_quickack(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_quickack(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any( + linux_like, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos" +))] +#[inline] +#[doc(alias = "TCP_CONGESTION")] +pub fn set_tcp_congestion(fd: Fd, value: &str) -> io::Result<()> { + backend::net::sockopt::set_tcp_congestion(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_CONGESTION)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(feature = "alloc")] +#[cfg(any( + linux_like, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos" +))] +#[inline] +#[doc(alias = "TCP_CONGESTION")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub fn tcp_congestion(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_congestion(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "TCP_THIN_LINEAR_TIMEOUTS")] +pub fn set_tcp_thin_linear_timeouts(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_tcp_thin_linear_timeouts(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "TCP_THIN_LINEAR_TIMEOUTS")] +pub fn tcp_thin_linear_timeouts(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_thin_linear_timeouts(fd.as_fd()) +} + +/// `setsockopt(fd, IPPROTO_TCP, TCP_CORK, value)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any(linux_like, solarish, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "TCP_CORK")] +pub fn set_tcp_cork(fd: Fd, value: bool) -> io::Result<()> { + backend::net::sockopt::set_tcp_cork(fd.as_fd(), value) +} + +/// `getsockopt(fd, IPPROTO_TCP, TCP_CORK)` +/// +/// See the [module-level documentation] for more. +/// +/// [module-level documentation]: self#references-for-get_tcp_-and-set_tcp_-functions +#[cfg(any(linux_like, solarish, target_os = "fuchsia"))] +#[inline] +#[doc(alias = "TCP_CORK")] +pub fn tcp_cork(fd: Fd) -> io::Result { + backend::net::sockopt::tcp_cork(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_SOCKET, SO_PEERCRED)`—Get credentials of Unix domain +/// socket peer process. +/// +/// # References +/// - [Linux `unix`] +/// +/// [Linux `unix`]: https://man7.org/linux/man-pages/man7/unix.7.html +#[cfg(linux_kernel)] +#[doc(alias = "SO_PEERCRED")] +pub fn socket_peercred(fd: Fd) -> io::Result { + backend::net::sockopt::socket_peercred(fd.as_fd()) +} + +/// `setsockopt(fd, SOL_XDP, XDP_UMEM_REG, value)` +/// +/// On kernel versions only supporting v1, the flags are ignored. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://www.kernel.org/doc/html/next/networking/af_xdp.html#xdp-umem-reg-setsockopt +#[cfg(target_os = "linux")] +#[doc(alias = "XDP_UMEM_REG")] +pub fn set_xdp_umem_reg(fd: Fd, value: XdpUmemReg) -> io::Result<()> { + backend::net::sockopt::set_xdp_umem_reg(fd.as_fd(), value) +} + +/// `setsockopt(fd, SOL_XDP, XDP_UMEM_FILL_RING, value)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://www.kernel.org/doc/html/next/networking/af_xdp.html#xdp-rx-tx-umem-fill-umem-completion-ring-setsockopts +#[cfg(target_os = "linux")] +#[doc(alias = "XDP_UMEM_FILL_RING")] +pub fn set_xdp_umem_fill_ring_size(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_xdp_umem_fill_ring_size(fd.as_fd(), value) +} + +/// `setsockopt(fd, SOL_XDP, XDP_UMEM_COMPLETION_RING, value)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://www.kernel.org/doc/html/next/networking/af_xdp.html#xdp-rx-tx-umem-fill-umem-completion-ring-setsockopts +#[cfg(target_os = "linux")] +#[doc(alias = "XDP_UMEM_COMPLETION_RING")] +pub fn set_xdp_umem_completion_ring_size(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_xdp_umem_completion_ring_size(fd.as_fd(), value) +} + +/// `setsockopt(fd, SOL_XDP, XDP_TX_RING, value)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://www.kernel.org/doc/html/next/networking/af_xdp.html#xdp-rx-tx-umem-fill-umem-completion-ring-setsockopts +#[cfg(target_os = "linux")] +#[doc(alias = "XDP_TX_RING")] +pub fn set_xdp_tx_ring_size(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_xdp_tx_ring_size(fd.as_fd(), value) +} + +/// `setsockopt(fd, SOL_XDP, XDP_RX_RING, value)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://www.kernel.org/doc/html/next/networking/af_xdp.html#xdp-rx-tx-umem-fill-umem-completion-ring-setsockopts +#[cfg(target_os = "linux")] +#[doc(alias = "XDP_RX_RING")] +pub fn set_xdp_rx_ring_size(fd: Fd, value: u32) -> io::Result<()> { + backend::net::sockopt::set_xdp_rx_ring_size(fd.as_fd(), value) +} + +/// `getsockopt(fd, SOL_XDP, XDP_MMAP_OFFSETS)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://www.kernel.org/doc/html/next/networking/af_xdp.html +#[cfg(target_os = "linux")] +#[doc(alias = "XDP_MMAP_OFFSETS")] +pub fn xdp_mmap_offsets(fd: Fd) -> io::Result { + backend::net::sockopt::xdp_mmap_offsets(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_XDP, XDP_STATISTICS)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://www.kernel.org/doc/html/next/networking/af_xdp.html#xdp-statistics-getsockopt +#[cfg(target_os = "linux")] +#[doc(alias = "XDP_STATISTICS")] +pub fn xdp_statistics(fd: Fd) -> io::Result { + backend::net::sockopt::xdp_statistics(fd.as_fd()) +} + +/// `getsockopt(fd, SOL_XDP, XDP_OPTIONS)` +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://www.kernel.org/doc/html/next/networking/af_xdp.html#xdp-options-getsockopt +#[cfg(target_os = "linux")] +#[doc(alias = "XDP_OPTIONS")] +pub fn xdp_options(fd: Fd) -> io::Result { + backend::net::sockopt::xdp_options(fd.as_fd()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sizes() { + use c::c_int; + + // Backend code needs to cast these to `c_int` so make sure that cast + // isn't lossy. + assert_eq_size!(Timeout, c_int); + } +} diff --git a/vendor/rustix/src/net/types.rs b/vendor/rustix/src/net/types.rs new file mode 100644 index 00000000..057f944d --- /dev/null +++ b/vendor/rustix/src/net/types.rs @@ -0,0 +1,2132 @@ +//! Types and constants for `rustix::net`. + +use crate::backend::c; +use crate::ffi; +use bitflags::bitflags; + +/// A type for holding raw integer socket types. +pub type RawSocketType = u32; + +/// `SOCK_*` constants for use with [`socket`]. +/// +/// [`socket`]: crate::net::socket() +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct SocketType(pub(crate) RawSocketType); + +#[rustfmt::skip] +impl SocketType { + /// `SOCK_STREAM` + pub const STREAM: Self = Self(c::SOCK_STREAM as _); + + /// `SOCK_DGRAM` + pub const DGRAM: Self = Self(c::SOCK_DGRAM as _); + + /// `SOCK_SEQPACKET` + #[cfg(not(any(target_os = "espidf", target_os = "horizon")))] + pub const SEQPACKET: Self = Self(c::SOCK_SEQPACKET as _); + + /// `SOCK_RAW` + #[cfg(not(any(target_os = "espidf", target_os = "horizon")))] + pub const RAW: Self = Self(c::SOCK_RAW as _); + + /// `SOCK_RDM` + #[cfg(not(any( + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox" + )))] + pub const RDM: Self = Self(c::SOCK_RDM as _); + + /// Constructs a `SocketType` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawSocketType) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `SocketType`. + #[inline] + pub const fn as_raw(self) -> RawSocketType { + self.0 + } +} + +/// A type for holding raw integer address families. +pub type RawAddressFamily = crate::ffi::c_ushort; + +/// `AF_*` constants for use with [`socket`], [`socket_with`], and +/// [`socketpair`]. +/// +/// [`socket`]: crate::net::socket() +/// [`socket_with`]: crate::net::socket_with +/// [`socketpair`]: crate::net::socketpair() +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct AddressFamily(pub(crate) RawAddressFamily); + +#[rustfmt::skip] +#[allow(non_upper_case_globals)] +impl AddressFamily { + /// `AF_UNSPEC` + pub const UNSPEC: Self = Self(c::AF_UNSPEC as _); + /// `AF_INET` + /// + /// # References + /// - [Linux] + /// + /// [Linux]: https://man7.org/linux/man-pages/man7/ip.7.html + pub const INET: Self = Self(c::AF_INET as _); + /// `AF_INET6` + /// + /// # References + /// - [Linux] + /// + /// [Linux]: https://man7.org/linux/man-pages/man7/ipv6.7.html + pub const INET6: Self = Self(c::AF_INET6 as _); + /// `AF_NETLINK` + /// + /// # References + /// - [Linux] + /// + /// [Linux]: https://man7.org/linux/man-pages/man7/netlink.7.html + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const NETLINK: Self = Self(c::AF_NETLINK as _); + /// `AF_UNIX`, aka `AF_LOCAL` + #[doc(alias = "LOCAL")] + pub const UNIX: Self = Self(c::AF_UNIX as _); + /// `AF_AX25` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const AX25: Self = Self(c::AF_AX25 as _); + /// `AF_IPX` + #[cfg(not(any( + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "horizon", + target_os = "redox", + target_os = "vita", + )))] + pub const IPX: Self = Self(c::AF_IPX as _); + /// `AF_APPLETALK` + #[cfg(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const APPLETALK: Self = Self(c::AF_APPLETALK as _); + /// `AF_NETROM` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const NETROM: Self = Self(c::AF_NETROM as _); + /// `AF_BRIDGE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const BRIDGE: Self = Self(c::AF_BRIDGE as _); + /// `AF_ATMPVC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const ATMPVC: Self = Self(c::AF_ATMPVC as _); + /// `AF_X25` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const X25: Self = Self(c::AF_X25 as _); + /// `AF_ROSE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const ROSE: Self = Self(c::AF_ROSE as _); + /// `AF_DECnet` + #[cfg(not(any( + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const DECnet: Self = Self(c::AF_DECnet as _); + /// `AF_NETBEUI` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const NETBEUI: Self = Self(c::AF_NETBEUI as _); + /// `AF_SECURITY` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const SECURITY: Self = Self(c::AF_SECURITY as _); + /// `AF_KEY` + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const KEY: Self = Self(c::AF_KEY as _); + /// `AF_PACKET` + /// + /// # References + /// - [Linux] + /// + /// [Linux]: https://man7.org/linux/man-pages/man7/packet.7.html + #[cfg(not(any( + bsd, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const PACKET: Self = Self(c::AF_PACKET as _); + /// `AF_ASH` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const ASH: Self = Self(c::AF_ASH as _); + /// `AF_ECONET` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const ECONET: Self = Self(c::AF_ECONET as _); + /// `AF_ATMSVC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const ATMSVC: Self = Self(c::AF_ATMSVC as _); + /// `AF_RDS` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const RDS: Self = Self(c::AF_RDS as _); + /// `AF_SNA` + #[cfg(not(any( + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const SNA: Self = Self(c::AF_SNA as _); + /// `AF_IRDA` + #[cfg(not(any( + bsd, + solarish, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const IRDA: Self = Self(c::AF_IRDA as _); + /// `AF_PPPOX` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const PPPOX: Self = Self(c::AF_PPPOX as _); + /// `AF_WANPIPE` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const WANPIPE: Self = Self(c::AF_WANPIPE as _); + /// `AF_LLC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const LLC: Self = Self(c::AF_LLC as _); + /// `AF_CAN` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const CAN: Self = Self(c::AF_CAN as _); + /// `AF_TIPC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const TIPC: Self = Self(c::AF_TIPC as _); + /// `AF_BLUETOOTH` + #[cfg(not(any( + apple, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "horizon", + target_os = "hurd", + target_os = "redox", + target_os = "vita", + )))] + pub const BLUETOOTH: Self = Self(c::AF_BLUETOOTH as _); + /// `AF_IUCV` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const IUCV: Self = Self(c::AF_IUCV as _); + /// `AF_RXRPC` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const RXRPC: Self = Self(c::AF_RXRPC as _); + /// `AF_ISDN` + #[cfg(not(any( + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "redox", + target_os = "vita", + )))] + pub const ISDN: Self = Self(c::AF_ISDN as _); + /// `AF_PHONET` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const PHONET: Self = Self(c::AF_PHONET as _); + /// `AF_IEEE802154` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "hurd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const IEEE802154: Self = Self(c::AF_IEEE802154 as _); + /// `AF_802` + #[cfg(solarish)] + pub const EIGHT_ZERO_TWO: Self = Self(c::AF_802 as _); + #[cfg(target_os = "fuchsia")] + /// `AF_ALG` + pub const ALG: Self = Self(c::AF_ALG as _); + #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "nto"))] + /// `AF_ARP` + pub const ARP: Self = Self(c::AF_ARP as _); + /// `AF_ATM` + #[cfg(freebsdlike)] + pub const ATM: Self = Self(c::AF_ATM as _); + /// `AF_CAIF` + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia"))] + pub const CAIF: Self = Self(c::AF_CAIF as _); + /// `AF_CCITT` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "nto"))] + pub const CCITT: Self = Self(c::AF_CCITT as _); + /// `AF_CHAOS` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "nto"))] + pub const CHAOS: Self = Self(c::AF_CHAOS as _); + /// `AF_CNT` + #[cfg(any(bsd, target_os = "nto"))] + pub const CNT: Self = Self(c::AF_CNT as _); + /// `AF_COIP` + #[cfg(any(bsd, target_os = "nto"))] + pub const COIP: Self = Self(c::AF_COIP as _); + /// `AF_DATAKIT` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "nto"))] + pub const DATAKIT: Self = Self(c::AF_DATAKIT as _); + /// `AF_DLI` + #[cfg(any( + bsd, + solarish, + target_os = "aix", + target_os = "haiku", + target_os = "nto" + ))] + pub const DLI: Self = Self(c::AF_DLI as _); + /// `AF_E164` + #[cfg(any(bsd, target_os = "nto"))] + pub const E164: Self = Self(c::AF_E164 as _); + /// `AF_ECMA` + #[cfg(any( + apple, + freebsdlike, + solarish, + target_os = "aix", + target_os = "nto", + target_os = "openbsd" + ))] + pub const ECMA: Self = Self(c::AF_ECMA as _); + /// `AF_ENCAP` + #[cfg(target_os = "openbsd")] + pub const ENCAP: Self = Self(c::AF_ENCAP as _); + /// `AF_FILE` + #[cfg(solarish)] + pub const FILE: Self = Self(c::AF_FILE as _); + /// `AF_GOSIP` + #[cfg(solarish)] + pub const GOSIP: Self = Self(c::AF_GOSIP as _); + /// `AF_HYLINK` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "nto"))] + pub const HYLINK: Self = Self(c::AF_HYLINK as _); + /// `AF_IB` + #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] + pub const IB: Self = Self(c::AF_IB as _); + /// `AF_IMPLINK` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "nto"))] + pub const IMPLINK: Self = Self(c::AF_IMPLINK as _); + /// `AF_IEEE80211` + #[cfg(any(apple, freebsdlike, target_os = "netbsd"))] + pub const IEEE80211: Self = Self(c::AF_IEEE80211 as _); + /// `AF_INET6_SDP` + #[cfg(target_os = "freebsd")] + pub const INET6_SDP: Self = Self(c::AF_INET6_SDP as _); + /// `AF_INET_OFFLOAD` + #[cfg(solarish)] + pub const INET_OFFLOAD: Self = Self(c::AF_INET_OFFLOAD as _); + /// `AF_INET_SDP` + #[cfg(target_os = "freebsd")] + pub const INET_SDP: Self = Self(c::AF_INET_SDP as _); + /// `AF_INTF` + #[cfg(target_os = "aix")] + pub const INTF: Self = Self(c::AF_INTF as _); + /// `AF_ISO` + #[cfg(any(bsd, target_os = "aix", target_os = "nto"))] + pub const ISO: Self = Self(c::AF_ISO as _); + /// `AF_LAT` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "nto"))] + pub const LAT: Self = Self(c::AF_LAT as _); + /// `AF_LINK` + #[cfg(any( + bsd, + solarish, + target_os = "aix", + target_os = "haiku", + target_os = "nto" + ))] + pub const LINK: Self = Self(c::AF_LINK as _); + /// `AF_MPLS` + #[cfg(any( + netbsdlike, + target_os = "dragonfly", + target_os = "emscripten", + target_os = "fuchsia" + ))] + pub const MPLS: Self = Self(c::AF_MPLS as _); + /// `AF_NATM` + #[cfg(any(bsd, target_os = "nto"))] + pub const NATM: Self = Self(c::AF_NATM as _); + /// `AF_NBS` + #[cfg(solarish)] + pub const NBS: Self = Self(c::AF_NBS as _); + /// `AF_NCA` + #[cfg(target_os = "illumos")] + pub const NCA: Self = Self(c::AF_NCA as _); + /// `AF_NDD` + #[cfg(target_os = "aix")] + pub const NDD: Self = Self(c::AF_NDD as _); + /// `AF_NDRV` + #[cfg(apple)] + pub const NDRV: Self = Self(c::AF_NDRV as _); + /// `AF_NETBIOS` + #[cfg(any(apple, freebsdlike))] + pub const NETBIOS: Self = Self(c::AF_NETBIOS as _); + /// `AF_NETGRAPH` + #[cfg(freebsdlike)] + pub const NETGRAPH: Self = Self(c::AF_NETGRAPH as _); + /// `AF_NIT` + #[cfg(solarish)] + pub const NIT: Self = Self(c::AF_NIT as _); + /// `AF_NOTIFY` + #[cfg(target_os = "haiku")] + pub const NOTIFY: Self = Self(c::AF_NOTIFY as _); + /// `AF_NFC` + #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] + pub const NFC: Self = Self(c::AF_NFC as _); + /// `AF_NS` + #[cfg(any(apple, solarish, netbsdlike, target_os = "aix", target_os = "nto"))] + pub const NS: Self = Self(c::AF_NS as _); + /// `AF_OROUTE` + #[cfg(target_os = "netbsd")] + pub const OROUTE: Self = Self(c::AF_OROUTE as _); + /// `AF_OSI` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "nto"))] + pub const OSI: Self = Self(c::AF_OSI as _); + /// `AF_OSINET` + #[cfg(solarish)] + pub const OSINET: Self = Self(c::AF_OSINET as _); + /// `AF_POLICY` + #[cfg(solarish)] + pub const POLICY: Self = Self(c::AF_POLICY as _); + /// `AF_PPP` + #[cfg(apple)] + pub const PPP: Self = Self(c::AF_PPP as _); + /// `AF_PUP` + #[cfg(any(bsd, solarish, target_os = "aix", target_os = "nto"))] + pub const PUP: Self = Self(c::AF_PUP as _); + /// `AF_RIF` + #[cfg(target_os = "aix")] + pub const RIF: Self = Self(c::AF_RIF as _); + /// `AF_ROUTE` + #[cfg(any( + bsd, + solarish, + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + target_os = "nto" + ))] + pub const ROUTE: Self = Self(c::AF_ROUTE as _); + /// `AF_SCLUSTER` + #[cfg(target_os = "freebsd")] + pub const SCLUSTER: Self = Self(c::AF_SCLUSTER as _); + /// `AF_SIP` + #[cfg(any(apple, target_os = "freebsd", target_os = "openbsd"))] + pub const SIP: Self = Self(c::AF_SIP as _); + /// `AF_SLOW` + #[cfg(target_os = "freebsd")] + pub const SLOW: Self = Self(c::AF_SLOW as _); + /// `AF_SYS_CONTROL` + #[cfg(apple)] + pub const SYS_CONTROL: Self = Self(c::AF_SYS_CONTROL as _); + /// `AF_SYSTEM` + #[cfg(apple)] + pub const SYSTEM: Self = Self(c::AF_SYSTEM as _); + /// `AF_TRILL` + #[cfg(solarish)] + pub const TRILL: Self = Self(c::AF_TRILL as _); + /// `AF_UTUN` + #[cfg(apple)] + pub const UTUN: Self = Self(c::AF_UTUN as _); + /// `AF_VSOCK` + #[cfg(any(apple, target_os = "emscripten", target_os = "fuchsia"))] + pub const VSOCK: Self = Self(c::AF_VSOCK as _); + /// `AF_XDP` + #[cfg(target_os = "linux")] + pub const XDP: Self = Self(c::AF_XDP as _); + + /// Constructs a `AddressFamily` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawAddressFamily) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `AddressFamily`. + #[inline] + pub const fn as_raw(self) -> RawAddressFamily { + self.0 + } +} + +/// A type for holding raw integer protocols. +pub type RawProtocol = core::num::NonZeroU32; + +const fn new_raw_protocol(u: u32) -> RawProtocol { + match RawProtocol::new(u) { + Some(p) => p, + None => panic!("new_raw_protocol: protocol must be non-zero"), + } +} + +/// `IPPROTO_*` and other constants for use with [`socket`], [`socket_with`], +/// and [`socketpair`] when a nondefault value is desired. +/// +/// See the [`ipproto`], [`sysproto`], and [`netlink`] modules for possible +/// values. +/// +/// For the default values, such as `IPPROTO_IP` or `NETLINK_ROUTE`, pass +/// `None` as the `protocol` argument in these functions. +/// +/// [`socket`]: crate::net::socket() +/// [`socket_with`]: crate::net::socket_with +/// [`socketpair`]: crate::net::socketpair() +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +#[doc(alias = "IPPROTO_IP")] +#[doc(alias = "NETLINK_ROUTE")] +pub struct Protocol(pub(crate) RawProtocol); + +/// `IPPROTO_*` constants. +/// +/// For `IPPROTO_IP`, pass `None` as the `protocol` argument. +pub mod ipproto { + use super::{new_raw_protocol, Protocol}; + use crate::backend::c; + + /// `IPPROTO_ICMP` + pub const ICMP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_ICMP as _)); + /// `IPPROTO_IGMP` + #[cfg(not(any( + solarish, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "vita" + )))] + pub const IGMP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_IGMP as _)); + /// `IPPROTO_IPIP` + #[cfg(not(any( + solarish, + windows, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const IPIP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_IPIP as _)); + /// `IPPROTO_TCP` + pub const TCP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_TCP as _)); + /// `IPPROTO_EGP` + #[cfg(not(any( + solarish, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const EGP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_EGP as _)); + /// `IPPROTO_PUP` + #[cfg(not(any( + solarish, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "vita" + )))] + pub const PUP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_PUP as _)); + /// `IPPROTO_UDP` + pub const UDP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_UDP as _)); + /// `IPPROTO_IDP` + #[cfg(not(any( + solarish, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "vita" + )))] + pub const IDP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_IDP as _)); + /// `IPPROTO_TP` + #[cfg(not(any( + solarish, + windows, + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita", + )))] + pub const TP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_TP as _)); + /// `IPPROTO_DCCP` + #[cfg(not(any( + apple, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "dragonfly", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "nto", + target_os = "openbsd", + target_os = "redox", + target_os = "vita", + )))] + pub const DCCP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_DCCP as _)); + /// `IPPROTO_IPV6` + pub const IPV6: Protocol = Protocol(new_raw_protocol(c::IPPROTO_IPV6 as _)); + /// `IPPROTO_RSVP` + #[cfg(not(any( + solarish, + windows, + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita", + )))] + pub const RSVP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_RSVP as _)); + /// `IPPROTO_GRE` + #[cfg(not(any( + solarish, + windows, + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita", + )))] + pub const GRE: Protocol = Protocol(new_raw_protocol(c::IPPROTO_GRE as _)); + /// `IPPROTO_ESP` + #[cfg(not(any( + solarish, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const ESP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_ESP as _)); + /// `IPPROTO_AH` + #[cfg(not(any( + solarish, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const AH: Protocol = Protocol(new_raw_protocol(c::IPPROTO_AH as _)); + /// `IPPROTO_MTP` + #[cfg(not(any( + solarish, + netbsdlike, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const MTP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_MTP as _)); + /// `IPPROTO_BEETPH` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const BEETPH: Protocol = Protocol(new_raw_protocol(c::IPPROTO_BEETPH as _)); + /// `IPPROTO_ENCAP` + #[cfg(not(any( + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita", + )))] + pub const ENCAP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_ENCAP as _)); + /// `IPPROTO_PIM` + #[cfg(not(any( + solarish, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita", + )))] + pub const PIM: Protocol = Protocol(new_raw_protocol(c::IPPROTO_PIM as _)); + /// `IPPROTO_COMP` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const COMP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_COMP as _)); + /// `IPPROTO_SCTP` + #[cfg(not(any( + solarish, + target_os = "cygwin", + target_os = "dragonfly", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "openbsd", + target_os = "redox", + target_os = "vita", + )))] + pub const SCTP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_SCTP as _)); + /// `IPPROTO_UDPLITE` + #[cfg(not(any( + apple, + netbsdlike, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "dragonfly", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const UDPLITE: Protocol = Protocol(new_raw_protocol(c::IPPROTO_UDPLITE as _)); + /// `IPPROTO_MPLS` + #[cfg(not(any( + apple, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "dragonfly", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "netbsd", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const MPLS: Protocol = Protocol(new_raw_protocol(c::IPPROTO_MPLS as _)); + /// `IPPROTO_ETHERNET` + #[cfg(linux_kernel)] + pub const ETHERNET: Protocol = Protocol(new_raw_protocol(c::IPPROTO_ETHERNET as _)); + /// `IPPROTO_RAW` + #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))] + pub const RAW: Protocol = Protocol(new_raw_protocol(c::IPPROTO_RAW as _)); + /// `IPPROTO_MPTCP` + #[cfg(not(any( + bsd, + solarish, + windows, + target_os = "aix", + target_os = "cygwin", + target_os = "emscripten", + target_os = "espidf", + target_os = "fuchsia", + target_os = "haiku", + target_os = "horizon", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const MPTCP: Protocol = Protocol(new_raw_protocol(c::IPPROTO_MPTCP as _)); + /// `IPPROTO_FRAGMENT` + #[cfg(not(any( + solarish, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const FRAGMENT: Protocol = Protocol(new_raw_protocol(c::IPPROTO_FRAGMENT as _)); + /// `IPPROTO_ICMPV6` + pub const ICMPV6: Protocol = Protocol(new_raw_protocol(c::IPPROTO_ICMPV6 as _)); + /// `IPPROTO_MH` + #[cfg(not(any( + apple, + netbsdlike, + solarish, + windows, + target_os = "cygwin", + target_os = "dragonfly", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "nto", + target_os = "redox", + target_os = "vita", + )))] + pub const MH: Protocol = Protocol(new_raw_protocol(c::IPPROTO_MH as _)); + /// `IPPROTO_ROUTING` + #[cfg(not(any( + solarish, + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "redox", + target_os = "vita" + )))] + pub const ROUTING: Protocol = Protocol(new_raw_protocol(c::IPPROTO_ROUTING as _)); +} + +/// `SYSPROTO_*` constants. +pub mod sysproto { + #[cfg(apple)] + use { + super::{new_raw_protocol, Protocol}, + crate::backend::c, + }; + + /// `SYSPROTO_EVENT` + #[cfg(apple)] + pub const EVENT: Protocol = Protocol(new_raw_protocol(c::SYSPROTO_EVENT as _)); + + /// `SYSPROTO_CONTROL` + #[cfg(apple)] + pub const CONTROL: Protocol = Protocol(new_raw_protocol(c::SYSPROTO_CONTROL as _)); +} + +/// `NETLINK_*` constants. +/// +/// For `NETLINK_ROUTE`, pass `None` as the `protocol` argument. +pub mod netlink { + #[cfg(linux_kernel)] + use { + super::{new_raw_protocol, Protocol}, + crate::backend::c, + crate::backend::net::read_sockaddr::read_sockaddr_netlink, + crate::net::{ + addr::{call_with_sockaddr, SocketAddrArg, SocketAddrLen, SocketAddrOpaque}, + SocketAddrAny, + }, + core::mem, + }; + + /// `NETLINK_UNUSED` + #[cfg(linux_kernel)] + pub const UNUSED: Protocol = Protocol(new_raw_protocol(c::NETLINK_UNUSED as _)); + /// `NETLINK_USERSOCK` + #[cfg(linux_kernel)] + pub const USERSOCK: Protocol = Protocol(new_raw_protocol(c::NETLINK_USERSOCK as _)); + /// `NETLINK_FIREWALL` + #[cfg(linux_kernel)] + pub const FIREWALL: Protocol = Protocol(new_raw_protocol(c::NETLINK_FIREWALL as _)); + /// `NETLINK_SOCK_DIAG` + #[cfg(linux_kernel)] + pub const SOCK_DIAG: Protocol = Protocol(new_raw_protocol(c::NETLINK_SOCK_DIAG as _)); + /// `NETLINK_NFLOG` + #[cfg(linux_kernel)] + pub const NFLOG: Protocol = Protocol(new_raw_protocol(c::NETLINK_NFLOG as _)); + /// `NETLINK_XFRM` + #[cfg(linux_kernel)] + pub const XFRM: Protocol = Protocol(new_raw_protocol(c::NETLINK_XFRM as _)); + /// `NETLINK_SELINUX` + #[cfg(linux_kernel)] + pub const SELINUX: Protocol = Protocol(new_raw_protocol(c::NETLINK_SELINUX as _)); + /// `NETLINK_ISCSI` + #[cfg(linux_kernel)] + pub const ISCSI: Protocol = Protocol(new_raw_protocol(c::NETLINK_ISCSI as _)); + /// `NETLINK_AUDIT` + #[cfg(linux_kernel)] + pub const AUDIT: Protocol = Protocol(new_raw_protocol(c::NETLINK_AUDIT as _)); + /// `NETLINK_FIB_LOOKUP` + #[cfg(linux_kernel)] + pub const FIB_LOOKUP: Protocol = Protocol(new_raw_protocol(c::NETLINK_FIB_LOOKUP as _)); + /// `NETLINK_CONNECTOR` + #[cfg(linux_kernel)] + pub const CONNECTOR: Protocol = Protocol(new_raw_protocol(c::NETLINK_CONNECTOR as _)); + /// `NETLINK_NETFILTER` + #[cfg(linux_kernel)] + pub const NETFILTER: Protocol = Protocol(new_raw_protocol(c::NETLINK_NETFILTER as _)); + /// `NETLINK_IP6_FW` + #[cfg(linux_kernel)] + pub const IP6_FW: Protocol = Protocol(new_raw_protocol(c::NETLINK_IP6_FW as _)); + /// `NETLINK_DNRTMSG` + #[cfg(linux_kernel)] + pub const DNRTMSG: Protocol = Protocol(new_raw_protocol(c::NETLINK_DNRTMSG as _)); + /// `NETLINK_KOBJECT_UEVENT` + #[cfg(linux_kernel)] + pub const KOBJECT_UEVENT: Protocol = Protocol(new_raw_protocol(c::NETLINK_KOBJECT_UEVENT as _)); + /// `NETLINK_GENERIC` + // This is defined on FreeBSD too, but it has the value 0, so it doesn't + // fit in or `NonZeroU32`. It's unclear whether FreeBSD intends + // `NETLINK_GENERIC` to be the default when Linux has `NETLINK_ROUTE` as + // the default. + #[cfg(linux_kernel)] + pub const GENERIC: Protocol = Protocol(new_raw_protocol(c::NETLINK_GENERIC as _)); + /// `NETLINK_SCSITRANSPORT` + #[cfg(linux_kernel)] + pub const SCSITRANSPORT: Protocol = Protocol(new_raw_protocol(c::NETLINK_SCSITRANSPORT as _)); + /// `NETLINK_ECRYPTFS` + #[cfg(linux_kernel)] + pub const ECRYPTFS: Protocol = Protocol(new_raw_protocol(c::NETLINK_ECRYPTFS as _)); + /// `NETLINK_RDMA` + #[cfg(linux_kernel)] + pub const RDMA: Protocol = Protocol(new_raw_protocol(c::NETLINK_RDMA as _)); + /// `NETLINK_CRYPTO` + #[cfg(linux_kernel)] + pub const CRYPTO: Protocol = Protocol(new_raw_protocol(c::NETLINK_CRYPTO as _)); + /// `NETLINK_INET_DIAG` + #[cfg(linux_kernel)] + pub const INET_DIAG: Protocol = Protocol(new_raw_protocol(c::NETLINK_INET_DIAG as _)); + + /// A Netlink socket address. + /// + /// Used to bind to a Netlink socket. + /// + /// Not ABI compatible with `struct sockaddr_nl` + #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] + #[cfg(linux_kernel)] + pub struct SocketAddrNetlink { + /// Port ID + pid: u32, + + /// Multicast groups mask + groups: u32, + } + + #[cfg(linux_kernel)] + impl SocketAddrNetlink { + /// Construct a netlink address + #[inline] + pub const fn new(pid: u32, groups: u32) -> Self { + Self { pid, groups } + } + + /// Return port id. + #[inline] + pub const fn pid(&self) -> u32 { + self.pid + } + + /// Set port id. + #[inline] + pub fn set_pid(&mut self, pid: u32) { + self.pid = pid; + } + + /// Return multicast groups mask. + #[inline] + pub const fn groups(&self) -> u32 { + self.groups + } + + /// Set multicast groups mask. + #[inline] + pub fn set_groups(&mut self, groups: u32) { + self.groups = groups; + } + } + + #[cfg(linux_kernel)] + #[allow(unsafe_code)] + // SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which + // handles calling `f` with the needed preconditions. + unsafe impl SocketAddrArg for SocketAddrNetlink { + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R { + let mut addr: c::sockaddr_nl = mem::zeroed(); + addr.nl_family = c::AF_NETLINK as _; + addr.nl_pid = self.pid; + addr.nl_groups = self.groups; + call_with_sockaddr(&addr, f) + } + } + + #[cfg(linux_kernel)] + impl From for SocketAddrAny { + #[inline] + fn from(from: SocketAddrNetlink) -> Self { + from.as_any() + } + } + + #[cfg(linux_kernel)] + impl TryFrom for SocketAddrNetlink { + type Error = crate::io::Errno; + + fn try_from(addr: SocketAddrAny) -> Result { + read_sockaddr_netlink(&addr) + } + } +} + +/// `ETH_P_*` constants. +// These are translated into 16-bit big-endian form because that's what the +// [`AddressFamily::PACKET`] address family [expects]. +// +// [expects]: https://man7.org/linux/man-pages/man7/packet.7.html +pub mod eth { + #[cfg(linux_kernel)] + use { + super::{new_raw_protocol, Protocol}, + crate::backend::c, + }; + + /// `ETH_P_LOOP` + #[cfg(linux_kernel)] + pub const LOOP: Protocol = Protocol(new_raw_protocol((c::ETH_P_LOOP as u16).to_be() as u32)); + /// `ETH_P_PUP` + #[cfg(linux_kernel)] + pub const PUP: Protocol = Protocol(new_raw_protocol((c::ETH_P_PUP as u16).to_be() as u32)); + /// `ETH_P_PUPAT` + #[cfg(linux_kernel)] + pub const PUPAT: Protocol = Protocol(new_raw_protocol((c::ETH_P_PUPAT as u16).to_be() as u32)); + /// `ETH_P_TSN` + #[cfg(linux_kernel)] + pub const TSN: Protocol = Protocol(new_raw_protocol((c::ETH_P_TSN as u16).to_be() as u32)); + /// `ETH_P_ERSPAN2` + #[cfg(linux_kernel)] + pub const ERSPAN2: Protocol = + Protocol(new_raw_protocol((c::ETH_P_ERSPAN2 as u16).to_be() as u32)); + /// `ETH_P_IP` + #[cfg(linux_kernel)] + pub const IP: Protocol = Protocol(new_raw_protocol((c::ETH_P_IP as u16).to_be() as u32)); + /// `ETH_P_X25` + #[cfg(linux_kernel)] + pub const X25: Protocol = Protocol(new_raw_protocol((c::ETH_P_X25 as u16).to_be() as u32)); + /// `ETH_P_ARP` + #[cfg(linux_kernel)] + pub const ARP: Protocol = Protocol(new_raw_protocol((c::ETH_P_ARP as u16).to_be() as u32)); + /// `ETH_P_BPQ` + #[cfg(linux_kernel)] + pub const BPQ: Protocol = Protocol(new_raw_protocol((c::ETH_P_BPQ as u16).to_be() as u32)); + /// `ETH_P_IEEEPUP` + #[cfg(linux_kernel)] + pub const IEEEPUP: Protocol = + Protocol(new_raw_protocol((c::ETH_P_IEEEPUP as u16).to_be() as u32)); + /// `ETH_P_IEEEPUPAT` + #[cfg(linux_kernel)] + pub const IEEEPUPAT: Protocol = + Protocol(new_raw_protocol((c::ETH_P_IEEEPUPAT as u16).to_be() as u32)); + /// `ETH_P_BATMAN` + #[cfg(linux_kernel)] + pub const BATMAN: Protocol = + Protocol(new_raw_protocol((c::ETH_P_BATMAN as u16).to_be() as u32)); + /// `ETH_P_DEC` + #[cfg(linux_kernel)] + pub const DEC: Protocol = Protocol(new_raw_protocol((c::ETH_P_DEC as u16).to_be() as u32)); + /// `ETH_P_DNA_DL` + #[cfg(linux_kernel)] + pub const DNA_DL: Protocol = + Protocol(new_raw_protocol((c::ETH_P_DNA_DL as u16).to_be() as u32)); + /// `ETH_P_DNA_RC` + #[cfg(linux_kernel)] + pub const DNA_RC: Protocol = + Protocol(new_raw_protocol((c::ETH_P_DNA_RC as u16).to_be() as u32)); + /// `ETH_P_DNA_RT` + #[cfg(linux_kernel)] + pub const DNA_RT: Protocol = + Protocol(new_raw_protocol((c::ETH_P_DNA_RT as u16).to_be() as u32)); + /// `ETH_P_LAT` + #[cfg(linux_kernel)] + pub const LAT: Protocol = Protocol(new_raw_protocol((c::ETH_P_LAT as u16).to_be() as u32)); + /// `ETH_P_DIAG` + #[cfg(linux_kernel)] + pub const DIAG: Protocol = Protocol(new_raw_protocol((c::ETH_P_DIAG as u16).to_be() as u32)); + /// `ETH_P_CUST` + #[cfg(linux_kernel)] + pub const CUST: Protocol = Protocol(new_raw_protocol((c::ETH_P_CUST as u16).to_be() as u32)); + /// `ETH_P_SCA` + #[cfg(linux_kernel)] + pub const SCA: Protocol = Protocol(new_raw_protocol((c::ETH_P_SCA as u16).to_be() as u32)); + /// `ETH_P_TEB` + #[cfg(linux_kernel)] + pub const TEB: Protocol = Protocol(new_raw_protocol((c::ETH_P_TEB as u16).to_be() as u32)); + /// `ETH_P_RARP` + #[cfg(linux_kernel)] + pub const RARP: Protocol = Protocol(new_raw_protocol((c::ETH_P_RARP as u16).to_be() as u32)); + /// `ETH_P_ATALK` + #[cfg(linux_kernel)] + pub const ATALK: Protocol = Protocol(new_raw_protocol((c::ETH_P_ATALK as u16).to_be() as u32)); + /// `ETH_P_AARP` + #[cfg(linux_kernel)] + pub const AARP: Protocol = Protocol(new_raw_protocol((c::ETH_P_AARP as u16).to_be() as u32)); + /// `ETH_P_8021Q` + #[cfg(linux_kernel)] + pub const P_8021Q: Protocol = + Protocol(new_raw_protocol((c::ETH_P_8021Q as u16).to_be() as u32)); + /// `ETH_P_ERSPAN` + #[cfg(linux_kernel)] + pub const ERSPAN: Protocol = + Protocol(new_raw_protocol((c::ETH_P_ERSPAN as u16).to_be() as u32)); + /// `ETH_P_IPX` + #[cfg(linux_kernel)] + pub const IPX: Protocol = Protocol(new_raw_protocol((c::ETH_P_IPX as u16).to_be() as u32)); + /// `ETH_P_IPV6` + #[cfg(linux_kernel)] + pub const IPV6: Protocol = Protocol(new_raw_protocol((c::ETH_P_IPV6 as u16).to_be() as u32)); + /// `ETH_P_PAUSE` + #[cfg(linux_kernel)] + pub const PAUSE: Protocol = Protocol(new_raw_protocol((c::ETH_P_PAUSE as u16).to_be() as u32)); + /// `ETH_P_SLOW` + #[cfg(linux_kernel)] + pub const SLOW: Protocol = Protocol(new_raw_protocol((c::ETH_P_SLOW as u16).to_be() as u32)); + /// `ETH_P_WCCP` + #[cfg(linux_kernel)] + pub const WCCP: Protocol = Protocol(new_raw_protocol((c::ETH_P_WCCP as u16).to_be() as u32)); + /// `ETH_P_MPLS_UC` + #[cfg(linux_kernel)] + pub const MPLS_UC: Protocol = + Protocol(new_raw_protocol((c::ETH_P_MPLS_UC as u16).to_be() as u32)); + /// `ETH_P_MPLS_MC` + #[cfg(linux_kernel)] + pub const MPLS_MC: Protocol = + Protocol(new_raw_protocol((c::ETH_P_MPLS_MC as u16).to_be() as u32)); + /// `ETH_P_ATMMPOA` + #[cfg(linux_kernel)] + pub const ATMMPOA: Protocol = + Protocol(new_raw_protocol((c::ETH_P_ATMMPOA as u16).to_be() as u32)); + /// `ETH_P_PPP_DISC` + #[cfg(linux_kernel)] + pub const PPP_DISC: Protocol = + Protocol(new_raw_protocol((c::ETH_P_PPP_DISC as u16).to_be() as u32)); + /// `ETH_P_PPP_SES` + #[cfg(linux_kernel)] + pub const PPP_SES: Protocol = + Protocol(new_raw_protocol((c::ETH_P_PPP_SES as u16).to_be() as u32)); + /// `ETH_P_LINK_CTL` + #[cfg(linux_kernel)] + pub const LINK_CTL: Protocol = + Protocol(new_raw_protocol((c::ETH_P_LINK_CTL as u16).to_be() as u32)); + /// `ETH_P_ATMFATE` + #[cfg(linux_kernel)] + pub const ATMFATE: Protocol = + Protocol(new_raw_protocol((c::ETH_P_ATMFATE as u16).to_be() as u32)); + /// `ETH_P_PAE` + #[cfg(linux_kernel)] + pub const PAE: Protocol = Protocol(new_raw_protocol((c::ETH_P_PAE as u16).to_be() as u32)); + /// `ETH_P_PROFINET` + #[cfg(linux_kernel)] + pub const PROFINET: Protocol = + Protocol(new_raw_protocol((c::ETH_P_PROFINET as u16).to_be() as u32)); + /// `ETH_P_REALTEK` + #[cfg(linux_kernel)] + pub const REALTEK: Protocol = + Protocol(new_raw_protocol((c::ETH_P_REALTEK as u16).to_be() as u32)); + /// `ETH_P_AOE` + #[cfg(linux_kernel)] + pub const AOE: Protocol = Protocol(new_raw_protocol((c::ETH_P_AOE as u16).to_be() as u32)); + /// `ETH_P_ETHERCAT` + #[cfg(linux_kernel)] + pub const ETHERCAT: Protocol = + Protocol(new_raw_protocol((c::ETH_P_ETHERCAT as u16).to_be() as u32)); + /// `ETH_P_8021AD` + #[cfg(linux_kernel)] + pub const P_8021AD: Protocol = + Protocol(new_raw_protocol((c::ETH_P_8021AD as u16).to_be() as u32)); + /// `ETH_P_802_EX1` + #[cfg(linux_kernel)] + pub const P_802_EX1: Protocol = + Protocol(new_raw_protocol((c::ETH_P_802_EX1 as u16).to_be() as u32)); + /// `ETH_P_PREAUTH` + #[cfg(linux_kernel)] + pub const PREAUTH: Protocol = + Protocol(new_raw_protocol((c::ETH_P_PREAUTH as u16).to_be() as u32)); + /// `ETH_P_TIPC` + #[cfg(linux_kernel)] + pub const TIPC: Protocol = Protocol(new_raw_protocol((c::ETH_P_TIPC as u16).to_be() as u32)); + /// `ETH_P_LLDP` + #[cfg(linux_kernel)] + pub const LLDP: Protocol = Protocol(new_raw_protocol((c::ETH_P_LLDP as u16).to_be() as u32)); + /// `ETH_P_MRP` + #[cfg(linux_kernel)] + pub const MRP: Protocol = Protocol(new_raw_protocol((c::ETH_P_MRP as u16).to_be() as u32)); + /// `ETH_P_MACSEC` + #[cfg(linux_kernel)] + pub const MACSEC: Protocol = + Protocol(new_raw_protocol((c::ETH_P_MACSEC as u16).to_be() as u32)); + /// `ETH_P_8021AH` + #[cfg(linux_kernel)] + pub const P_8021AH: Protocol = + Protocol(new_raw_protocol((c::ETH_P_8021AH as u16).to_be() as u32)); + /// `ETH_P_MVRP` + #[cfg(linux_kernel)] + pub const MVRP: Protocol = Protocol(new_raw_protocol((c::ETH_P_MVRP as u16).to_be() as u32)); + /// `ETH_P_1588` + #[cfg(linux_kernel)] + pub const P_1588: Protocol = Protocol(new_raw_protocol((c::ETH_P_1588 as u16).to_be() as u32)); + /// `ETH_P_NCSI` + #[cfg(linux_kernel)] + pub const NCSI: Protocol = Protocol(new_raw_protocol((c::ETH_P_NCSI as u16).to_be() as u32)); + /// `ETH_P_PRP` + #[cfg(linux_kernel)] + pub const PRP: Protocol = Protocol(new_raw_protocol((c::ETH_P_PRP as u16).to_be() as u32)); + /// `ETH_P_CFM` + #[cfg(linux_kernel)] + pub const CFM: Protocol = Protocol(new_raw_protocol((c::ETH_P_CFM as u16).to_be() as u32)); + /// `ETH_P_FCOE` + #[cfg(linux_kernel)] + pub const FCOE: Protocol = Protocol(new_raw_protocol((c::ETH_P_FCOE as u16).to_be() as u32)); + /// `ETH_P_IBOE` + #[cfg(linux_kernel)] + pub const IBOE: Protocol = Protocol(new_raw_protocol((c::ETH_P_IBOE as u16).to_be() as u32)); + /// `ETH_P_TDLS` + #[cfg(linux_kernel)] + pub const TDLS: Protocol = Protocol(new_raw_protocol((c::ETH_P_TDLS as u16).to_be() as u32)); + /// `ETH_P_FIP` + #[cfg(linux_kernel)] + pub const FIP: Protocol = Protocol(new_raw_protocol((c::ETH_P_FIP as u16).to_be() as u32)); + /// `ETH_P_80221` + #[cfg(linux_kernel)] + pub const P_80221: Protocol = + Protocol(new_raw_protocol((c::ETH_P_80221 as u16).to_be() as u32)); + /// `ETH_P_HSR` + #[cfg(linux_kernel)] + pub const HSR: Protocol = Protocol(new_raw_protocol((c::ETH_P_HSR as u16).to_be() as u32)); + /// `ETH_P_NSH` + #[cfg(linux_kernel)] + pub const NSH: Protocol = Protocol(new_raw_protocol((c::ETH_P_NSH as u16).to_be() as u32)); + /// `ETH_P_LOOPBACK` + #[cfg(linux_kernel)] + pub const LOOPBACK: Protocol = + Protocol(new_raw_protocol((c::ETH_P_LOOPBACK as u16).to_be() as u32)); + /// `ETH_P_QINQ1` + #[cfg(linux_kernel)] + pub const QINQ1: Protocol = Protocol(new_raw_protocol((c::ETH_P_QINQ1 as u16).to_be() as u32)); + /// `ETH_P_QINQ2` + #[cfg(linux_kernel)] + pub const QINQ2: Protocol = Protocol(new_raw_protocol((c::ETH_P_QINQ2 as u16).to_be() as u32)); + /// `ETH_P_QINQ3` + #[cfg(linux_kernel)] + pub const QINQ3: Protocol = Protocol(new_raw_protocol((c::ETH_P_QINQ3 as u16).to_be() as u32)); + /// `ETH_P_EDSA` + #[cfg(linux_kernel)] + pub const EDSA: Protocol = Protocol(new_raw_protocol((c::ETH_P_EDSA as u16).to_be() as u32)); + /// `ETH_P_DSA_8021Q` + #[cfg(linux_kernel)] + pub const DSA_8021Q: Protocol = + Protocol(new_raw_protocol((c::ETH_P_DSA_8021Q as u16).to_be() as u32)); + /// `ETH_P_DSA_A5PSW` + #[cfg(linux_kernel)] + pub const DSA_A5PSW: Protocol = + Protocol(new_raw_protocol((c::ETH_P_DSA_A5PSW as u16).to_be() as u32)); + /// `ETH_P_IFE` + #[cfg(linux_kernel)] + pub const IFE: Protocol = Protocol(new_raw_protocol((c::ETH_P_IFE as u16).to_be() as u32)); + /// `ETH_P_AF_IUCV` + #[cfg(linux_kernel)] + pub const AF_IUCV: Protocol = + Protocol(new_raw_protocol((c::ETH_P_AF_IUCV as u16).to_be() as u32)); + /// `ETH_P_802_3_MIN` + #[cfg(linux_kernel)] + pub const P_802_3_MIN: Protocol = + Protocol(new_raw_protocol((c::ETH_P_802_3_MIN as u16).to_be() as u32)); + /// `ETH_P_802_3` + #[cfg(linux_kernel)] + pub const P_802_3: Protocol = + Protocol(new_raw_protocol((c::ETH_P_802_3 as u16).to_be() as u32)); + /// `ETH_P_AX25` + #[cfg(linux_kernel)] + pub const AX25: Protocol = Protocol(new_raw_protocol((c::ETH_P_AX25 as u16).to_be() as u32)); + /// `ETH_P_ALL` + #[cfg(linux_kernel)] + pub const ALL: Protocol = Protocol(new_raw_protocol((c::ETH_P_ALL as u16).to_be() as u32)); + /// `ETH_P_802_2` + #[cfg(linux_kernel)] + pub const P_802_2: Protocol = + Protocol(new_raw_protocol((c::ETH_P_802_2 as u16).to_be() as u32)); + /// `ETH_P_SNAP` + #[cfg(linux_kernel)] + pub const SNAP: Protocol = Protocol(new_raw_protocol((c::ETH_P_SNAP as u16).to_be() as u32)); + /// `ETH_P_DDCMP` + #[cfg(linux_kernel)] + pub const DDCMP: Protocol = Protocol(new_raw_protocol((c::ETH_P_DDCMP as u16).to_be() as u32)); + /// `ETH_P_WAN_PPP` + #[cfg(linux_kernel)] + pub const WAN_PPP: Protocol = + Protocol(new_raw_protocol((c::ETH_P_WAN_PPP as u16).to_be() as u32)); + /// `ETH_P_PPP_MP` + #[cfg(linux_kernel)] + pub const PPP_MP: Protocol = + Protocol(new_raw_protocol((c::ETH_P_PPP_MP as u16).to_be() as u32)); + /// `ETH_P_LOCALTALK` + #[cfg(linux_kernel)] + pub const LOCALTALK: Protocol = + Protocol(new_raw_protocol((c::ETH_P_LOCALTALK as u16).to_be() as u32)); + /// `ETH_P_CAN` + #[cfg(linux_kernel)] + pub const CAN: Protocol = Protocol(new_raw_protocol((c::ETH_P_CAN as u16).to_be() as u32)); + /// `ETH_P_CANFD` + #[cfg(linux_kernel)] + pub const CANFD: Protocol = Protocol(new_raw_protocol((c::ETH_P_CANFD as u16).to_be() as u32)); + /// `ETH_P_CANXL` + #[cfg(linux_kernel)] + pub const CANXL: Protocol = Protocol(new_raw_protocol((c::ETH_P_CANXL as u16).to_be() as u32)); + /// `ETH_P_PPPTALK` + #[cfg(linux_kernel)] + pub const PPPTALK: Protocol = + Protocol(new_raw_protocol((c::ETH_P_PPPTALK as u16).to_be() as u32)); + /// `ETH_P_TR_802_2` + #[cfg(linux_kernel)] + pub const TR_802_2: Protocol = + Protocol(new_raw_protocol((c::ETH_P_TR_802_2 as u16).to_be() as u32)); + /// `ETH_P_MOBITEX` + #[cfg(linux_kernel)] + pub const MOBITEX: Protocol = + Protocol(new_raw_protocol((c::ETH_P_MOBITEX as u16).to_be() as u32)); + /// `ETH_P_CONTROL` + #[cfg(linux_kernel)] + pub const CONTROL: Protocol = + Protocol(new_raw_protocol((c::ETH_P_CONTROL as u16).to_be() as u32)); + /// `ETH_P_IRDA` + #[cfg(linux_kernel)] + pub const IRDA: Protocol = Protocol(new_raw_protocol((c::ETH_P_IRDA as u16).to_be() as u32)); + /// `ETH_P_ECONET` + #[cfg(linux_kernel)] + pub const ECONET: Protocol = + Protocol(new_raw_protocol((c::ETH_P_ECONET as u16).to_be() as u32)); + /// `ETH_P_HDLC` + #[cfg(linux_kernel)] + pub const HDLC: Protocol = Protocol(new_raw_protocol((c::ETH_P_HDLC as u16).to_be() as u32)); + /// `ETH_P_ARCNET` + #[cfg(linux_kernel)] + pub const ARCNET: Protocol = + Protocol(new_raw_protocol((c::ETH_P_ARCNET as u16).to_be() as u32)); + /// `ETH_P_DSA` + #[cfg(linux_kernel)] + pub const DSA: Protocol = Protocol(new_raw_protocol((c::ETH_P_DSA as u16).to_be() as u32)); + /// `ETH_P_TRAILER` + #[cfg(linux_kernel)] + pub const TRAILER: Protocol = + Protocol(new_raw_protocol((c::ETH_P_TRAILER as u16).to_be() as u32)); + /// `ETH_P_PHONET` + #[cfg(linux_kernel)] + pub const PHONET: Protocol = + Protocol(new_raw_protocol((c::ETH_P_PHONET as u16).to_be() as u32)); + /// `ETH_P_IEEE802154` + #[cfg(linux_kernel)] + pub const IEEE802154: Protocol = + Protocol(new_raw_protocol((c::ETH_P_IEEE802154 as u16).to_be() as u32)); + /// `ETH_P_CAIF` + #[cfg(linux_kernel)] + pub const CAIF: Protocol = Protocol(new_raw_protocol((c::ETH_P_CAIF as u16).to_be() as u32)); + /// `ETH_P_XDSA` + #[cfg(linux_kernel)] + pub const XDSA: Protocol = Protocol(new_raw_protocol((c::ETH_P_XDSA as u16).to_be() as u32)); + /// `ETH_P_MAP` + #[cfg(linux_kernel)] + pub const MAP: Protocol = Protocol(new_raw_protocol((c::ETH_P_MAP as u16).to_be() as u32)); + /// `ETH_P_MCTP` + #[cfg(linux_kernel)] + pub const MCTP: Protocol = Protocol(new_raw_protocol((c::ETH_P_MCTP as u16).to_be() as u32)); +} + +#[rustfmt::skip] +impl Protocol { + /// Constructs a `Protocol` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawProtocol) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `Protocol`. + #[inline] + pub const fn as_raw(self) -> RawProtocol { + self.0 + } +} + +/// `SHUT_*` constants for use with [`shutdown`]. +/// +/// [`shutdown`]: crate::net::shutdown +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum Shutdown { + /// `SHUT_RD`—Disable further read operations. + Read = c::SHUT_RD as _, + /// `SHUT_WR`—Disable further write operations. + Write = c::SHUT_WR as _, + /// `SHUT_RDWR`—Disable further read and write operations. + Both = c::SHUT_RDWR as _, +} + +bitflags! { + /// `SOCK_*` constants for use with [`socket_with`], [`accept_with`] and + /// [`acceptfrom_with`]. + /// + /// [`socket_with`]: crate::net::socket_with + /// [`accept_with`]: crate::net::accept_with + /// [`acceptfrom_with`]: crate::net::acceptfrom_with + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct SocketFlags: ffi::c_uint { + /// `SOCK_NONBLOCK` + #[cfg(not(any( + apple, + windows, + target_os = "aix", + target_os = "espidf", + target_os = "haiku", + target_os = "horizon", + target_os = "nto", + target_os = "vita", + )))] + const NONBLOCK = bitcast!(c::SOCK_NONBLOCK); + + /// `SOCK_CLOEXEC` + #[cfg(not(any(apple, windows, target_os = "aix", target_os = "haiku")))] + const CLOEXEC = bitcast!(c::SOCK_CLOEXEC); + + // This deliberately lacks a `const _ = !0`, so that users can use + // `from_bits_truncate` to extract the `SocketFlags` from a flags + // value that also includes a `SocketType`. + } +} + +/// `AF_XDP` related types and constants. +#[cfg(target_os = "linux")] +pub mod xdp { + use crate::backend::net::read_sockaddr::read_sockaddr_xdp; + use crate::fd::{AsRawFd, BorrowedFd}; + use crate::net::addr::{call_with_sockaddr, SocketAddrArg, SocketAddrLen, SocketAddrOpaque}; + use crate::net::SocketAddrAny; + + use super::{bitflags, c}; + + bitflags! { + /// `XDP_OPTIONS_*` constants returned by [`get_xdp_options`]. + /// + /// [`get_xdp_options`]: crate::net::sockopt::get_xdp_options + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpOptionsFlags: u32 { + /// `XDP_OPTIONS_ZEROCOPY` + const XDP_OPTIONS_ZEROCOPY = bitcast!(c::XDP_OPTIONS_ZEROCOPY); + } + } + + // Constant needs to be cast because bindgen does generate a `u32` but the + // struct expects a `u16`. + // + bitflags! { + /// `XDP_*` constants for use in [`SocketAddrXdp`]. + #[repr(transparent)] + #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] + pub struct SocketAddrXdpFlags: u16 { + /// `XDP_SHARED_UMEM` + const XDP_SHARED_UMEM = bitcast!(c::XDP_SHARED_UMEM as u16); + /// `XDP_COPY` + const XDP_COPY = bitcast!(c::XDP_COPY as u16); + /// `XDP_COPY` + const XDP_ZEROCOPY = bitcast!(c::XDP_ZEROCOPY as u16); + /// `XDP_USE_NEED_WAKEUP` + const XDP_USE_NEED_WAKEUP = bitcast!(c::XDP_USE_NEED_WAKEUP as u16); + // requires kernel 6.6 + /// `XDP_USE_SG` + const XDP_USE_SG = bitcast!(c::XDP_USE_SG as u16); + } + } + + bitflags! { + /// `XDP_RING_*` constants for use in fill and/or Tx ring. + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpRingFlags: u32 { + /// `XDP_RING_NEED_WAKEUP` + const XDP_RING_NEED_WAKEUP = bitcast!(c::XDP_RING_NEED_WAKEUP); + } + } + + bitflags! { + /// `XDP_UMEM_*` constants for use in [`XdpUmemReg`]. + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpUmemRegFlags: u32 { + /// `XDP_UMEM_UNALIGNED_CHUNK_FLAG` + const XDP_UMEM_UNALIGNED_CHUNK_FLAG = bitcast!(c::XDP_UMEM_UNALIGNED_CHUNK_FLAG); + } + } + + /// A XDP socket address. + /// + /// Used to bind to XDP socket. + /// + /// Not ABI compatible with `struct sockaddr_xdp`. + /// + /// To add a shared UMEM file descriptor, use + /// [`SocketAddrXdpWithSharedUmem`]. + // + #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] + pub struct SocketAddrXdp { + /// Flags. + sxdp_flags: SocketAddrXdpFlags, + /// Interface index. + sxdp_ifindex: u32, + /// Queue ID. + sxdp_queue_id: u32, + } + + impl SocketAddrXdp { + /// Construct a new XDP address. + #[inline] + pub const fn new(flags: SocketAddrXdpFlags, interface_index: u32, queue_id: u32) -> Self { + Self { + sxdp_flags: flags, + sxdp_ifindex: interface_index, + sxdp_queue_id: queue_id, + } + } + + /// Return flags. + #[inline] + pub fn flags(&self) -> SocketAddrXdpFlags { + self.sxdp_flags + } + + /// Set flags. + #[inline] + pub fn set_flags(&mut self, flags: SocketAddrXdpFlags) { + self.sxdp_flags = flags; + } + + /// Return interface index. + #[inline] + pub fn interface_index(&self) -> u32 { + self.sxdp_ifindex + } + + /// Set interface index. + #[inline] + pub fn set_interface_index(&mut self, interface_index: u32) { + self.sxdp_ifindex = interface_index; + } + + /// Return queue ID. + #[inline] + pub fn queue_id(&self) -> u32 { + self.sxdp_queue_id + } + + /// Set queue ID. + #[inline] + pub fn set_queue_id(&mut self, queue_id: u32) { + self.sxdp_queue_id = queue_id; + } + } + + #[allow(unsafe_code)] + // SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which + // handles calling `f` with the needed preconditions. + unsafe impl SocketAddrArg for SocketAddrXdp { + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R { + let addr = c::sockaddr_xdp { + sxdp_family: c::AF_XDP as _, + sxdp_flags: self.flags().bits(), + sxdp_ifindex: self.interface_index(), + sxdp_queue_id: self.queue_id(), + sxdp_shared_umem_fd: !0, + }; + + call_with_sockaddr(&addr, f) + } + } + + impl From for SocketAddrAny { + #[inline] + fn from(from: SocketAddrXdp) -> Self { + from.as_any() + } + } + + impl TryFrom for SocketAddrXdp { + type Error = crate::io::Errno; + + fn try_from(addr: SocketAddrAny) -> Result { + read_sockaddr_xdp(&addr) + } + } + + /// An XDP socket address with a shared UMEM file descriptor. + /// + /// This implements `SocketAddrArg` so that it can be passed to [`bind`]. + /// + /// [`bind`]: crate::net::bind + #[derive(Debug)] + pub struct SocketAddrXdpWithSharedUmem<'a> { + /// XDP address. + pub addr: SocketAddrXdp, + /// Shared UMEM file descriptor. + pub shared_umem_fd: BorrowedFd<'a>, + } + + #[allow(unsafe_code)] + // SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which + // handles calling `f` with the needed preconditions. + unsafe impl<'a> SocketAddrArg for SocketAddrXdpWithSharedUmem<'a> { + unsafe fn with_sockaddr( + &self, + f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, + ) -> R { + let addr = c::sockaddr_xdp { + sxdp_family: c::AF_XDP as _, + sxdp_flags: self.addr.flags().bits(), + sxdp_ifindex: self.addr.interface_index(), + sxdp_queue_id: self.addr.queue_id(), + sxdp_shared_umem_fd: self.shared_umem_fd.as_raw_fd() as u32, + }; + + call_with_sockaddr(&addr, f) + } + } + + /// XDP ring offset. + /// + /// Used to mmap rings from kernel. + /// + /// Not ABI compatible with `struct xdp_ring_offset`. + // + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpRingOffset { + /// Producer offset. + pub producer: u64, + /// Consumer offset. + pub consumer: u64, + /// Descriptors offset. + pub desc: u64, + /// Flags offset. + /// + /// Is `None` if the kernel version (<5.4) does not yet support flags. + pub flags: Option, + } + + /// XDP mmap offsets. + /// + /// Not ABI compatible with `struct xdp_mmap_offsets` + // + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpMmapOffsets { + /// Rx ring offsets. + pub rx: XdpRingOffset, + /// Tx ring offsets. + pub tx: XdpRingOffset, + /// Fill ring offsets. + pub fr: XdpRingOffset, + /// Completion ring offsets. + pub cr: XdpRingOffset, + } + + /// XDP umem registration. + /// + /// `struct xdp_umem_reg` + // + #[repr(C)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpUmemReg { + /// Start address of UMEM. + pub addr: u64, + /// Umem length in bytes. + pub len: u64, + /// Chunk size in bytes. + pub chunk_size: u32, + /// Headroom in bytes. + pub headroom: u32, + /// Flags. + /// + /// Requires kernel version 5.4. + pub flags: XdpUmemRegFlags, + /// `AF_XDP` TX metadata length + /// + /// Requires kernel version 6.8. + pub tx_metadata_len: u32, + } + + /// XDP statistics. + /// + /// Not ABI compatible with `struct xdp_statistics` + // + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpStatistics { + /// Rx dropped. + pub rx_dropped: u64, + /// Rx invalid descriptors. + pub rx_invalid_descs: u64, + /// Tx invalid descriptors. + pub tx_invalid_descs: u64, + /// Rx ring full. + /// + /// Is `None` if the kernel version (<5.9) does not yet support flags. + pub rx_ring_full: Option, + /// Rx fill ring empty descriptors. + /// + /// Is `None` if the kernel version (<5.9) does not yet support flags. + pub rx_fill_ring_empty_descs: Option, + /// Tx ring empty descriptors. + /// + /// Is `None` if the kernel version (<5.9) does not yet support flags. + pub tx_ring_empty_descs: Option, + } + + /// XDP options. + /// + /// Requires kernel version 5.3. + /// `struct xdp_options` + // + #[repr(C)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpOptions { + /// Flags. + pub flags: XdpOptionsFlags, + } + + /// XDP rx/tx frame descriptor. + /// + /// `struct xdp_desc` + // + #[repr(C)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpDesc { + /// Offset from the start of the UMEM. + pub addr: u64, + /// Length of packet in bytes. + pub len: u32, + /// Options. + pub options: XdpDescOptions, + } + + #[cfg(target_os = "linux")] + bitflags! { + /// `XDP_*` constants for use in [`XdpDesc`]. + /// + /// Requires kernel version 6.6. + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct XdpDescOptions: u32 { + /// `XDP_PKT_CONTD` + const XDP_PKT_CONTD = bitcast!(c::XDP_PKT_CONTD); + } + } + + /// Offset for mmapping rx ring. + pub const XDP_PGOFF_RX_RING: u64 = c::XDP_PGOFF_RX_RING as u64; + /// Offset for mmapping tx ring. + pub const XDP_PGOFF_TX_RING: u64 = c::XDP_PGOFF_TX_RING as u64; + /// Offset for mmapping fill ring. + pub const XDP_UMEM_PGOFF_FILL_RING: u64 = c::XDP_UMEM_PGOFF_FILL_RING; + /// Offset for mmapping completion ring. + pub const XDP_UMEM_PGOFF_COMPLETION_RING: u64 = c::XDP_UMEM_PGOFF_COMPLETION_RING; + + /// Offset used to shift the [`XdpDesc`] addr to the right to extract the + /// address offset in unaligned mode. + pub const XSK_UNALIGNED_BUF_OFFSET_SHIFT: u64 = c::XSK_UNALIGNED_BUF_OFFSET_SHIFT as u64; + /// Mask used to binary `and` the [`XdpDesc`] addr to extract the address + /// without the offset carried in the upper 16 bits of the address in + /// unaligned mode. + pub const XSK_UNALIGNED_BUF_ADDR_MASK: u64 = c::XSK_UNALIGNED_BUF_ADDR_MASK; +} + +/// UNIX credentials of socket peer, for use with [`get_socket_peercred`] +/// [`SendAncillaryMessage::ScmCredentials`] and +/// [`RecvAncillaryMessage::ScmCredentials`]. +/// +/// [`get_socket_peercred`]: crate::net::sockopt::socket_peercred +/// [`SendAncillaryMessage::ScmCredentials`]: crate::net::SendAncillaryMessage::ScmCredentials +/// [`RecvAncillaryMessage::ScmCredentials`]: crate::net::RecvAncillaryMessage::ScmCredentials +#[cfg(linux_kernel)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(C)] +pub struct UCred { + /// Process ID of peer + pub pid: crate::pid::Pid, + /// User ID of peer + pub uid: crate::ugid::Uid, + /// Group ID of peer + pub gid: crate::ugid::Gid, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sizes() { + #[cfg(target_os = "linux")] + use crate::backend::c; + use crate::ffi::c_int; + use crate::net::addr::SocketAddrStorage; + use core::mem::transmute; + + // Backend code needs to cast these to `c_int` so make sure that cast isn't + // lossy. + assert_eq_size!(RawProtocol, c_int); + assert_eq_size!(Protocol, c_int); + assert_eq_size!(Option, c_int); + assert_eq_size!(Option, c_int); + assert_eq_size!(RawSocketType, c_int); + assert_eq_size!(SocketType, c_int); + assert_eq_size!(SocketFlags, c_int); + assert_eq_size!(SocketAddrStorage, c::sockaddr_storage); + + // Rustix doesn't depend on `Option` matching the ABI of a raw + // integer for correctness, but it should work nonetheless. + #[allow(unsafe_code)] + unsafe { + let t: Option = None; + assert_eq!(0_u32, transmute::, u32>(t)); + + let t: Option = Some(Protocol::from_raw(RawProtocol::new(4567).unwrap())); + assert_eq!(4567_u32, transmute::, u32>(t)); + } + + #[cfg(linux_kernel)] + assert_eq_size!(UCred, libc::ucred); + + #[cfg(target_os = "linux")] + assert_eq_size!(super::xdp::XdpUmemReg, c::xdp_umem_reg); + #[cfg(target_os = "linux")] + assert_eq_size!(super::xdp::XdpOptions, c::xdp_options); + #[cfg(target_os = "linux")] + assert_eq_size!(super::xdp::XdpDesc, c::xdp_desc); + } +} diff --git a/vendor/rustix/src/net/wsa.rs b/vendor/rustix/src/net/wsa.rs new file mode 100644 index 00000000..0ad4db5e --- /dev/null +++ b/vendor/rustix/src/net/wsa.rs @@ -0,0 +1,49 @@ +use crate::io; +use core::mem::MaybeUninit; +use windows_sys::Win32::Networking::WinSock::{WSACleanup, WSAGetLastError, WSAStartup, WSADATA}; + +/// `WSAStartup()`—Initialize process-wide Windows support for sockets. +/// +/// On Windows, it's necessary to initialize the sockets subsystem before +/// using sockets APIs. The function performs the necessary initialization. +/// +/// # References +/// - [Winsock] +/// +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastartup +pub fn wsa_startup() -> io::Result { + // Request version 2.2, which has been the latest version since far older + // versions of Windows than we support here. For more information about + // the version, see [here]. + // + // [here]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastartup#remarks + let version = 0x202; + let mut data = MaybeUninit::uninit(); + unsafe { + let ret = WSAStartup(version, data.as_mut_ptr()); + if ret == 0 { + Ok(data.assume_init()) + } else { + Err(io::Errno::from_raw_os_error(WSAGetLastError())) + } + } +} + +/// `WSACleanup()`—Clean up process-wide Windows support for sockets. +/// +/// In a program where `init` is called, if sockets are no longer necessary, +/// this function releases associated resources. +/// +/// # References +/// - [Winsock] +/// +/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsacleanup +pub fn wsa_cleanup() -> io::Result<()> { + unsafe { + if WSACleanup() == 0 { + Ok(()) + } else { + Err(io::Errno::from_raw_os_error(WSAGetLastError())) + } + } +} -- cgit v1.2.3