summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/net
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
committermo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
commit8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch)
tree22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/rustix/src/net
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/rustix/src/net')
-rw-r--r--vendor/rustix/src/net/addr.rs182
-rw-r--r--vendor/rustix/src/net/mod.rs35
-rw-r--r--vendor/rustix/src/net/netdevice.rs107
-rw-r--r--vendor/rustix/src/net/send_recv/mod.rs192
-rw-r--r--vendor/rustix/src/net/send_recv/msg.rs961
-rw-r--r--vendor/rustix/src/net/socket.rs461
-rw-r--r--vendor/rustix/src/net/socket_addr_any.rs344
-rw-r--r--vendor/rustix/src/net/socketpair.rs36
-rw-r--r--vendor/rustix/src/net/sockopt.rs1649
-rw-r--r--vendor/rustix/src/net/types.rs2132
-rw-r--r--vendor/rustix/src/net/wsa.rs49
11 files changed, 6148 insertions, 0 deletions
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<R>(
+ &self,
+ f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
+ ) -> R;
+
+ /// Convert to `SocketAddrAny`.
+ fn as_any(&self) -> SocketAddrAny {
+ let mut storage = MaybeUninit::<SocketAddrStorage>::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<SocketAddrStorage>()`
+ /// 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::<u8>(), storage.cast::<u8>(), 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<A, R>(
+ addr: &A,
+ f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
+) -> R {
+ let ptr = as_ptr(addr).cast();
+ let len = size_of::<A>() as SocketAddrLen;
+ f(ptr, len)
+}
+
+// SAFETY: This just forwards to the inner `SocketAddrArg` implementations.
+unsafe impl SocketAddrArg for SocketAddr {
+ unsafe fn with_sockaddr<R>(
+ &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<R>(
+ &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<R>(
+ &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<R>(
+ &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::<SocketAddrLen>()
+ );
+
+ assert!(size_of::<SocketAddrLen>() <= size_of::<usize>());
+ }
+}
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: AsFd>(fd: Fd, if_name: &str) -> io::Result<u32> {
+ 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: AsFd>(fd: Fd, index: u32) -> io::Result<String> {
+ 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::<u32>()
+ .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::<u32>()
+ .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&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/recv
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Receiving-Data.html
+#[inline]
+#[allow(clippy::type_complexity)]
+pub fn recv<Fd: AsFd, Buf: Buffer<u8>>(
+ fd: Fd,
+ mut buf: Buf,
+ flags: RecvFlags,
+) -> io::Result<(Buf::Output, usize)> {
+ let (ptr, len) = buf.parts_mut();
+ // SAFETY: `recv` behaves.
+ let recv_len = unsafe { backend::net::syscalls::recv(fd.as_fd(), (ptr, len), flags)? };
+ // If the `TRUNC` flag is set, the returned `length` may be longer than the
+ // buffer length.
+ let min_len = min(len, recv_len);
+ // SAFETY: `recv` behaves.
+ unsafe { Ok((buf.assume_init(min_len), recv_len)) }
+}
+
+/// `send(fd, buf, flags)`—Writes data to a socket.
+///
+/// # References
+/// - [Beej's Guide to Network Programming]
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+/// - [Winsock]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+/// - [DragonFly BSD]
+/// - [illumos]
+/// - [glibc]
+///
+/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendrecv
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/send.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/send.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/send.2.html
+/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=send&sektion=2
+/// [NetBSD]: https://man.netbsd.org/send.2
+/// [OpenBSD]: https://man.openbsd.org/send.2
+/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=send&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/send
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Data.html
+#[inline]
+pub fn send<Fd: AsFd>(fd: Fd, buf: &[u8], flags: SendFlags) -> io::Result<usize> {
+ backend::net::syscalls::send(fd.as_fd(), buf, flags)
+}
+
+/// `recvfrom(fd, buf, flags, addr, len)`—Reads data from a socket and
+/// returns the sender address.
+///
+/// In addition to the `Buffer::Output` return value, this also returns the
+/// number of bytes received before any truncation due to the
+/// [`RecvFlags::TRUNC`] flag.
+///
+/// # References
+/// - [Beej's Guide to Network Programming]
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+/// - [Winsock]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+/// - [DragonFly BSD]
+/// - [illumos]
+/// - [glibc]
+///
+/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/recvfrom.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/recvfrom.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvfrom.2.html
+/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvfrom&sektion=2
+/// [NetBSD]: https://man.netbsd.org/recvfrom.2
+/// [OpenBSD]: https://man.openbsd.org/recvfrom.2
+/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvfrom&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/recvfrom
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Receiving-Datagrams.html
+#[inline]
+pub fn recvfrom<Fd: AsFd, Buf: Buffer<u8>>(
+ fd: Fd,
+ mut buf: Buf,
+ flags: RecvFlags,
+) -> io::Result<(Buf::Output, usize, Option<SocketAddrAny>)> {
+ let (ptr, len) = buf.parts_mut();
+ // SAFETY: `recvfrom` behaves.
+ let (recv_len, addr) =
+ unsafe { backend::net::syscalls::recvfrom(fd.as_fd(), (ptr, len), flags)? };
+ // If the `TRUNC` flag is set, the returned `length` may be longer than the
+ // buffer length.
+ let min_len = min(len, recv_len);
+ // SAFETY: `recvfrom` behaves.
+ unsafe { Ok((buf.assume_init(min_len), recv_len, addr)) }
+}
+
+/// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific IP
+/// address.
+///
+/// # References
+/// - [Beej's Guide to Network Programming]
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+/// - [Winsock]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+/// - [DragonFly BSD]
+/// - [illumos]
+/// - [glibc]
+///
+/// [Beej's Guide to Network Programming]: https://beej.us/guide/bgnet/html/split/system-calls-or-bust.html#sendtorecv
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendto.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/sendto.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendto.2.html
+/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2
+/// [NetBSD]: https://man.netbsd.org/sendto.2
+/// [OpenBSD]: https://man.openbsd.org/sendto.2
+/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/sendto
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Sending-Datagrams.html
+pub fn sendto<Fd: AsFd>(
+ fd: Fd,
+ buf: &[u8],
+ flags: SendFlags,
+ addr: &impl SocketAddrArg,
+) -> io::Result<usize> {
+ backend::net::syscalls::sendto(fd.as_fd(), buf, flags, addr)
+}
diff --git a/vendor/rustix/src/net/send_recv/msg.rs b/vendor/rustix/src/net/send_recv/msg.rs
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<u8>] = space.as_slice();
+/// ```
+///
+/// Allocate a buffer for credentials:
+/// ```
+/// # #[cfg(linux_kernel)]
+/// # {
+/// # use std::mem::MaybeUninit;
+/// # use rustix::cmsg_space;
+/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
+/// # let _: &[MaybeUninit<u8>] = space.as_slice();
+/// # }
+/// ```
+///
+/// Allocate a buffer for two file descriptors and credentials:
+/// ```
+/// # #[cfg(linux_kernel)]
+/// # {
+/// # use std::mem::MaybeUninit;
+/// # use rustix::cmsg_space;
+/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
+/// # let _: &[MaybeUninit<u8>] = space.as_slice();
+/// # }
+/// ```
+#[macro_export]
+macro_rules! cmsg_space {
+ // Base Rules
+ (ScmRights($len:expr)) => {
+ $crate::net::__cmsg_space(
+ $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(),
+ )
+ };
+ (ScmCredentials($len:expr)) => {
+ $crate::net::__cmsg_space(
+ $len * ::core::mem::size_of::<$crate::net::UCred>(),
+ )
+ };
+
+ // Combo Rules
+ ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{
+ // We only have to add `cmsghdr` alignment once; all other times we can
+ // use `cmsg_aligned_space`.
+ let sum = $crate::cmsg_space!($firstid($firstex));
+ $(
+ let sum = sum + $crate::cmsg_aligned_space!($restid($restex));
+ )*
+ sum
+ }};
+}
+
+/// Like `cmsg_space`, but doesn't add padding for `cmsghdr` alignment.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! cmsg_aligned_space {
+ // Base Rules
+ (ScmRights($len:expr)) => {
+ $crate::net::__cmsg_aligned_space(
+ $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(),
+ )
+ };
+ (ScmCredentials($len:expr)) => {
+ $crate::net::__cmsg_aligned_space(
+ $len * ::core::mem::size_of::<$crate::net::UCred>(),
+ )
+ };
+
+ // Combo Rules
+ ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{
+ let sum = cmsg_aligned_space!($firstid($firstex));
+ $(
+ let sum = sum + cmsg_aligned_space!($restid($restex));
+ )*
+ sum
+ }};
+}
+
+/// Helper function for [`cmsg_space`].
+#[doc(hidden)]
+pub const fn __cmsg_space(len: usize) -> usize {
+ // Add `align_of::<c::cmsghdr>()` so that we can align the user-provided
+ // `&[u8]` to the required alignment boundary.
+ let len = len + align_of::<c::cmsghdr>();
+
+ __cmsg_aligned_space(len)
+}
+
+/// Helper function for [`cmsg_aligned_space`].
+#[doc(hidden)]
+pub const fn __cmsg_aligned_space(len: usize) -> usize {
+ // Convert `len` to `u32` for `CMSG_SPACE`. This would be `try_into()` if
+ // we could call that in a `const fn`.
+ let converted_len = len as u32;
+ if converted_len as usize != len {
+ unreachable!(); // `CMSG_SPACE` size overflow
+ }
+
+ unsafe { c::CMSG_SPACE(converted_len) as usize }
+}
+
+/// Ancillary message for [`sendmsg`] and [`sendmsg_addr`].
+#[non_exhaustive]
+pub enum SendAncillaryMessage<'slice, 'fd> {
+ /// Send file descriptors.
+ #[doc(alias = "SCM_RIGHTS")]
+ ScmRights(&'slice [BorrowedFd<'fd>]),
+ /// Send process credentials.
+ #[cfg(linux_kernel)]
+ #[doc(alias = "SCM_CREDENTIAL")]
+ ScmCredentials(UCred),
+}
+
+impl SendAncillaryMessage<'_, '_> {
+ /// Get the maximum size of an ancillary message.
+ ///
+ /// This can be used to determine the size of the buffer to allocate for a
+ /// [`SendAncillaryBuffer::new`] with one message.
+ pub const fn size(&self) -> usize {
+ match self {
+ Self::ScmRights(slice) => cmsg_space!(ScmRights(slice.len())),
+ #[cfg(linux_kernel)]
+ Self::ScmCredentials(_) => cmsg_space!(ScmCredentials(1)),
+ }
+ }
+}
+
+/// Ancillary message for [`recvmsg`].
+#[non_exhaustive]
+pub enum RecvAncillaryMessage<'a> {
+ /// Received file descriptors.
+ #[doc(alias = "SCM_RIGHTS")]
+ ScmRights(AncillaryIter<'a, OwnedFd>),
+ /// Received process credentials.
+ #[cfg(linux_kernel)]
+ #[doc(alias = "SCM_CREDENTIALS")]
+ ScmCredentials(UCred),
+}
+
+/// Buffer for sending ancillary messages with [`sendmsg`] and
+/// [`sendmsg_addr`].
+///
+/// Use the [`push`] function to add messages to send.
+///
+/// [`push`]: SendAncillaryBuffer::push
+pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> {
+ /// Raw byte buffer for messages.
+ buffer: &'buf mut [MaybeUninit<u8>],
+
+ /// The amount of the buffer that is used.
+ length: usize,
+
+ /// Phantom data for lifetime of `&'slice [BorrowedFd<'fd>]`.
+ _phantom: PhantomData<&'slice [BorrowedFd<'fd>]>,
+}
+
+impl<'buf> From<&'buf mut [MaybeUninit<u8>]> for SendAncillaryBuffer<'buf, '_, '_> {
+ fn from(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
+ Self::new(buffer)
+ }
+}
+
+impl Default for SendAncillaryBuffer<'_, '_, '_> {
+ fn default() -> Self {
+ Self {
+ buffer: &mut [],
+ length: 0,
+ _phantom: PhantomData,
+ }
+ }
+}
+
+impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> {
+ /// Create a new, empty `SendAncillaryBuffer` from a raw byte buffer.
+ ///
+ /// The buffer size may be computed with [`cmsg_space`], or it may be
+ /// zero for an empty buffer, however in that case, consider `default()`
+ /// instead, or even using [`send`] instead of `sendmsg`.
+ ///
+ /// # Examples
+ ///
+ /// Allocate a buffer for a single file descriptor:
+ /// ```
+ /// # use std::mem::MaybeUninit;
+ /// # use rustix::cmsg_space;
+ /// # use rustix::net::SendAncillaryBuffer;
+ /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
+ /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
+ /// ```
+ ///
+ /// Allocate a buffer for credentials:
+ /// ```
+ /// # #[cfg(linux_kernel)]
+ /// # {
+ /// # use std::mem::MaybeUninit;
+ /// # use rustix::cmsg_space;
+ /// # use rustix::net::SendAncillaryBuffer;
+ /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
+ /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
+ /// # }
+ /// ```
+ ///
+ /// Allocate a buffer for two file descriptors and credentials:
+ /// ```
+ /// # #[cfg(linux_kernel)]
+ /// # {
+ /// # use std::mem::MaybeUninit;
+ /// # use rustix::cmsg_space;
+ /// # use rustix::net::SendAncillaryBuffer;
+ /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
+ /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
+ /// # }
+ /// ```
+ ///
+ /// [`send`]: crate::net::send
+ #[inline]
+ pub fn new(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
+ Self {
+ buffer: align_for_cmsghdr(buffer),
+ length: 0,
+ _phantom: PhantomData,
+ }
+ }
+
+ /// Returns a pointer to the message data.
+ pub(crate) fn as_control_ptr(&mut self) -> *mut u8 {
+ // When the length is zero, we may be using a `&[]` address, which may
+ // be an invalid but non-null pointer, and on some platforms, that
+ // causes `sendmsg` to fail with `EFAULT` or `EINVAL`
+ #[cfg(not(linux_kernel))]
+ if self.length == 0 {
+ return core::ptr::null_mut();
+ }
+
+ self.buffer.as_mut_ptr().cast()
+ }
+
+ /// Returns the length of the message data.
+ pub(crate) fn control_len(&self) -> usize {
+ self.length
+ }
+
+ /// Delete all messages from the buffer.
+ pub fn clear(&mut self) {
+ self.length = 0;
+ }
+
+ /// Add an ancillary message to the buffer.
+ ///
+ /// Returns `true` if the message was added successfully.
+ pub fn push(&mut self, msg: SendAncillaryMessage<'slice, 'fd>) -> bool {
+ match msg {
+ SendAncillaryMessage::ScmRights(fds) => {
+ let fds_bytes =
+ unsafe { slice::from_raw_parts(fds.as_ptr().cast::<u8>(), size_of_val(fds)) };
+ self.push_ancillary(fds_bytes, c::SOL_SOCKET as _, c::SCM_RIGHTS as _)
+ }
+ #[cfg(linux_kernel)]
+ SendAncillaryMessage::ScmCredentials(ucred) => {
+ let ucred_bytes = unsafe {
+ slice::from_raw_parts(addr_of!(ucred).cast::<u8>(), size_of_val(&ucred))
+ };
+ self.push_ancillary(ucred_bytes, c::SOL_SOCKET as _, c::SCM_CREDENTIALS as _)
+ }
+ }
+ }
+
+ /// Pushes an ancillary message to the buffer.
+ fn push_ancillary(&mut self, source: &[u8], cmsg_level: c::c_int, cmsg_type: c::c_int) -> bool {
+ macro_rules! leap {
+ ($e:expr) => {{
+ match ($e) {
+ Some(x) => x,
+ None => return false,
+ }
+ }};
+ }
+
+ // Calculate the length of the message.
+ let source_len = leap!(u32::try_from(source.len()).ok());
+
+ // Calculate the new length of the buffer.
+ let additional_space = unsafe { c::CMSG_SPACE(source_len) };
+ let new_length = leap!(self.length.checked_add(additional_space as usize));
+ let buffer = leap!(self.buffer.get_mut(..new_length));
+
+ // Fill the new part of the buffer with zeroes.
+ buffer[self.length..new_length].fill(MaybeUninit::new(0));
+ self.length = new_length;
+
+ // Get the last header in the buffer.
+ let last_header = leap!(messages::Messages::new(buffer).last());
+
+ // Set the header fields.
+ last_header.cmsg_len = unsafe { c::CMSG_LEN(source_len) } as _;
+ last_header.cmsg_level = cmsg_level;
+ last_header.cmsg_type = cmsg_type;
+
+ // Get the pointer to the payload and copy the data.
+ unsafe {
+ let payload = c::CMSG_DATA(last_header);
+ ptr::copy_nonoverlapping(source.as_ptr(), payload, source_len as usize);
+ }
+
+ true
+ }
+}
+
+impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>>
+ for SendAncillaryBuffer<'_, 'slice, 'fd>
+{
+ fn extend<T: IntoIterator<Item = SendAncillaryMessage<'slice, 'fd>>>(&mut self, iter: T) {
+ // TODO: This could be optimized to add every message in one go.
+ iter.into_iter().all(|msg| self.push(msg));
+ }
+}
+
+/// Buffer for receiving ancillary messages with [`recvmsg`].
+///
+/// Use the [`drain`] function to iterate over the received messages.
+///
+/// [`drain`]: RecvAncillaryBuffer::drain
+#[derive(Default)]
+pub struct RecvAncillaryBuffer<'buf> {
+ /// Raw byte buffer for messages.
+ buffer: &'buf mut [MaybeUninit<u8>],
+
+ /// The portion of the buffer we've read from already.
+ read: usize,
+
+ /// The amount of the buffer that is used.
+ length: usize,
+}
+
+impl<'buf> From<&'buf mut [MaybeUninit<u8>]> for RecvAncillaryBuffer<'buf> {
+ fn from(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
+ Self::new(buffer)
+ }
+}
+
+impl<'buf> RecvAncillaryBuffer<'buf> {
+ /// Create a new, empty `RecvAncillaryBuffer` from a raw byte buffer.
+ ///
+ /// The buffer size may be computed with [`cmsg_space`], or it may be
+ /// zero for an empty buffer, however in that case, consider `default()`
+ /// instead, or even using [`recv`] instead of `recvmsg`.
+ ///
+ /// # Examples
+ ///
+ /// Allocate a buffer for a single file descriptor:
+ /// ```
+ /// # use std::mem::MaybeUninit;
+ /// # use rustix::cmsg_space;
+ /// # use rustix::net::RecvAncillaryBuffer;
+ /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
+ /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
+ /// ```
+ ///
+ /// Allocate a buffer for credentials:
+ /// ```
+ /// # #[cfg(linux_kernel)]
+ /// # {
+ /// # use std::mem::MaybeUninit;
+ /// # use rustix::cmsg_space;
+ /// # use rustix::net::RecvAncillaryBuffer;
+ /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
+ /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
+ /// # }
+ /// ```
+ ///
+ /// Allocate a buffer for two file descriptors and credentials:
+ /// ```
+ /// # #[cfg(linux_kernel)]
+ /// # {
+ /// # use std::mem::MaybeUninit;
+ /// # use rustix::cmsg_space;
+ /// # use rustix::net::RecvAncillaryBuffer;
+ /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
+ /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
+ /// # }
+ /// ```
+ ///
+ /// [`recv`]: crate::net::recv
+ #[inline]
+ pub fn new(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
+ Self {
+ buffer: align_for_cmsghdr(buffer),
+ read: 0,
+ length: 0,
+ }
+ }
+
+ /// Returns a pointer to the message data.
+ pub(crate) fn as_control_ptr(&mut self) -> *mut u8 {
+ // When the length is zero, we may be using a `&[]` address, which may
+ // be an invalid but non-null pointer, and on some platforms, that
+ // causes `sendmsg` to fail with `EFAULT` or `EINVAL`
+ #[cfg(not(linux_kernel))]
+ if self.buffer.is_empty() {
+ return core::ptr::null_mut();
+ }
+
+ self.buffer.as_mut_ptr().cast()
+ }
+
+ /// Returns the length of the message data.
+ pub(crate) fn control_len(&self) -> usize {
+ self.buffer.len()
+ }
+
+ /// Set the length of the message data.
+ ///
+ /// # Safety
+ ///
+ /// The buffer must be filled with valid message data.
+ pub(crate) unsafe fn set_control_len(&mut self, len: usize) {
+ self.length = len;
+ self.read = 0;
+ }
+
+ /// Delete all messages from the buffer.
+ pub(crate) fn clear(&mut self) {
+ self.drain().for_each(drop);
+ }
+
+ /// Drain all messages from the buffer.
+ pub fn drain(&mut self) -> AncillaryDrain<'_> {
+ AncillaryDrain {
+ messages: messages::Messages::new(&mut self.buffer[self.read..][..self.length]),
+ read_and_length: Some((&mut self.read, &mut self.length)),
+ }
+ }
+}
+
+impl Drop for RecvAncillaryBuffer<'_> {
+ fn drop(&mut self) {
+ self.clear();
+ }
+}
+
+/// Return a slice of `buffer` starting at the first `cmsghdr` alignment
+/// boundary.
+#[inline]
+fn align_for_cmsghdr(buffer: &mut [MaybeUninit<u8>]) -> &mut [MaybeUninit<u8>] {
+ // If the buffer is empty, we won't be writing anything into it, so it
+ // doesn't need to be aligned.
+ if buffer.is_empty() {
+ return buffer;
+ }
+
+ let align = align_of::<c::cmsghdr>();
+ let addr = buffer.as_ptr() as usize;
+ let adjusted = (addr + (align - 1)) & align.wrapping_neg();
+ &mut buffer[adjusted - addr..]
+}
+
+/// An iterator that drains messages from a [`RecvAncillaryBuffer`].
+pub struct AncillaryDrain<'buf> {
+ /// Inner iterator over messages.
+ messages: messages::Messages<'buf>,
+
+ /// Increment the number of messages we've read.
+ /// Decrement the total length.
+ read_and_length: Option<(&'buf mut usize, &'buf mut usize)>,
+}
+
+impl<'buf> AncillaryDrain<'buf> {
+ /// Create an iterator for control messages that were received without
+ /// [`RecvAncillaryBuffer`].
+ ///
+ /// # Safety
+ ///
+ /// The buffer must contain valid message data (or be empty).
+ pub unsafe fn parse(buffer: &'buf mut [u8]) -> Self {
+ Self {
+ messages: messages::Messages::new(buffer),
+ read_and_length: None,
+ }
+ }
+
+ fn advance(
+ read_and_length: &mut Option<(&'buf mut usize, &'buf mut usize)>,
+ msg: &c::cmsghdr,
+ ) -> Option<RecvAncillaryMessage<'buf>> {
+ // Advance the `read` pointer.
+ if let Some((read, length)) = read_and_length {
+ let msg_len = msg.cmsg_len as usize;
+ **read += msg_len;
+ **length -= msg_len;
+ }
+
+ Self::cvt_msg(msg)
+ }
+
+ /// A closure that converts a message into a [`RecvAncillaryMessage`].
+ fn cvt_msg(msg: &c::cmsghdr) -> Option<RecvAncillaryMessage<'buf>> {
+ unsafe {
+ // Get a pointer to the payload.
+ let payload = c::CMSG_DATA(msg);
+ let payload_len = msg.cmsg_len as usize - c::CMSG_LEN(0) as usize;
+
+ // Get a mutable slice of the payload.
+ let payload: &'buf mut [u8] = slice::from_raw_parts_mut(payload, payload_len);
+
+ // Determine what type it is.
+ let (level, msg_type) = (msg.cmsg_level, msg.cmsg_type);
+ match (level as _, msg_type as _) {
+ (c::SOL_SOCKET, c::SCM_RIGHTS) => {
+ // Create an iterator that reads out the file descriptors.
+ let fds = AncillaryIter::new(payload);
+
+ Some(RecvAncillaryMessage::ScmRights(fds))
+ }
+ #[cfg(linux_kernel)]
+ (c::SOL_SOCKET, c::SCM_CREDENTIALS) => {
+ if payload_len >= size_of::<UCred>() {
+ let ucred = payload.as_ptr().cast::<UCred>().read_unaligned();
+ Some(RecvAncillaryMessage::ScmCredentials(ucred))
+ } else {
+ None
+ }
+ }
+ _ => None,
+ }
+ }
+ }
+}
+
+impl<'buf> Iterator for AncillaryDrain<'buf> {
+ type Item = RecvAncillaryMessage<'buf>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.messages
+ .find_map(|ev| Self::advance(&mut self.read_and_length, ev))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (_, max) = self.messages.size_hint();
+ (0, max)
+ }
+
+ fn fold<B, F>(mut self, init: B, f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B,
+ {
+ self.messages
+ .filter_map(|ev| Self::advance(&mut self.read_and_length, ev))
+ .fold(init, f)
+ }
+
+ fn count(mut self) -> usize {
+ self.messages
+ .filter_map(|ev| Self::advance(&mut self.read_and_length, ev))
+ .count()
+ }
+
+ fn last(mut self) -> Option<Self::Item>
+ where
+ Self: Sized,
+ {
+ self.messages
+ .filter_map(|ev| Self::advance(&mut self.read_and_length, ev))
+ .last()
+ }
+
+ fn collect<B: FromIterator<Self::Item>>(mut self) -> B
+ where
+ Self: Sized,
+ {
+ self.messages
+ .filter_map(|ev| Self::advance(&mut self.read_and_length, ev))
+ .collect()
+ }
+}
+
+impl FusedIterator for AncillaryDrain<'_> {}
+
+/// An ABI-compatible wrapper for `mmsghdr`, for sending multiple messages with
+/// [sendmmsg].
+#[cfg(target_os = "linux")]
+#[repr(transparent)]
+pub struct MMsgHdr<'a> {
+ raw: c::mmsghdr,
+ _phantom: PhantomData<&'a mut ()>,
+}
+
+#[cfg(target_os = "linux")]
+impl<'a> MMsgHdr<'a> {
+ /// Constructs a new message with no destination address.
+ pub fn new(iov: &'a [IoSlice<'_>], control: &'a mut SendAncillaryBuffer<'_, '_, '_>) -> Self {
+ Self::wrap(noaddr_msghdr(iov, control))
+ }
+
+ /// Constructs a new message to a specific address.
+ ///
+ /// This requires a `SocketAddrAny` instead of using `impl SocketAddrArg`;
+ /// to obtain a `SocketAddrAny`, use [`SocketAddrArg::as_any`].
+ pub fn new_with_addr(
+ addr: &'a SocketAddrAny,
+ iov: &'a [IoSlice<'_>],
+ control: &'a mut SendAncillaryBuffer<'_, '_, '_>,
+ ) -> Self {
+ // The reason we use `SocketAddrAny` instead of `SocketAddrArg` here,
+ // and avoid `use_msghdr`, is that we need a pointer that will remain
+ // valid for the duration of the `'a` lifetime. `SocketAddrAny` can
+ // give us a pointer directly, so we use that.
+ let mut msghdr = noaddr_msghdr(iov, control);
+ msghdr.msg_name = addr.as_ptr() as _;
+ msghdr.msg_namelen = bitcast!(addr.addr_len());
+
+ Self::wrap(msghdr)
+ }
+
+ fn wrap(msg_hdr: c::msghdr) -> Self {
+ Self {
+ raw: c::mmsghdr {
+ msg_hdr,
+ msg_len: 0,
+ },
+ _phantom: PhantomData,
+ }
+ }
+
+ /// Returns the number of bytes sent. This will return 0 until after a
+ /// successful call to [sendmmsg].
+ pub fn bytes_sent(&self) -> usize {
+ self.raw.msg_len as usize
+ }
+}
+
+/// `sendmsg(msghdr)`—Sends a message on a socket.
+///
+/// This function is for use on connected sockets, as it doesn't have a way to
+/// specify an address. See [`sendmsg_addr`] to send messages on unconnected
+/// sockets.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+/// - [DragonFly BSD]
+/// - [illumos]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
+/// [NetBSD]: https://man.netbsd.org/sendmsg.2
+/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
+/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
+#[inline]
+pub fn sendmsg<Fd: AsFd>(
+ socket: Fd,
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+ flags: SendFlags,
+) -> io::Result<usize> {
+ backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags)
+}
+
+/// `sendmsg(msghdr)`—Sends a message on a socket to a specific address.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+/// - [DragonFly BSD]
+/// - [illumos]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
+/// [NetBSD]: https://man.netbsd.org/sendmsg.2
+/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
+/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
+#[inline]
+pub fn sendmsg_addr<Fd: AsFd>(
+ socket: Fd,
+ addr: &impl SocketAddrArg,
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+ flags: SendFlags,
+) -> io::Result<usize> {
+ backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags)
+}
+
+/// `sendmmsg(msghdr)`—Sends multiple messages on a socket.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/sendmmsg.2.html
+#[inline]
+#[cfg(target_os = "linux")]
+pub fn sendmmsg<Fd: AsFd>(
+ socket: Fd,
+ msgs: &mut [MMsgHdr<'_>],
+ flags: SendFlags,
+) -> io::Result<usize> {
+ backend::net::syscalls::sendmmsg(socket.as_fd(), msgs, flags)
+}
+
+/// `recvmsg(msghdr)`—Receives a message from a socket.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+/// - [DragonFly BSD]
+/// - [illumos]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/recvmsg.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/recvmsg.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvmsg.2.html
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvmsg&sektion=2
+/// [NetBSD]: https://man.netbsd.org/recvmsg.2
+/// [OpenBSD]: https://man.openbsd.org/recvmsg.2
+/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvmsg&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/recvmsg
+#[inline]
+pub fn recvmsg<Fd: AsFd>(
+ socket: Fd,
+ iov: &mut [IoSliceMut<'_>],
+ control: &mut RecvAncillaryBuffer<'_>,
+ flags: RecvFlags,
+) -> io::Result<RecvMsg> {
+ backend::net::syscalls::recvmsg(socket.as_fd(), iov, control, flags)
+}
+
+/// The result of a successful [`recvmsg`] call.
+#[derive(Debug, Clone)]
+pub struct RecvMsg {
+ /// The number of bytes received.
+ ///
+ /// When `RecvFlags::TRUNC` is in use, this may be greater than the length
+ /// of the buffer, as it reflects the number of bytes received before
+ /// truncation into the buffer.
+ pub bytes: usize,
+
+ /// The flags received.
+ pub flags: ReturnFlags,
+
+ /// The address of the socket we received from, if any.
+ pub address: Option<SocketAddrAny>,
+}
+
+/// An iterator over data in an ancillary buffer.
+pub struct AncillaryIter<'data, T> {
+ /// The data we're iterating over.
+ data: &'data mut [u8],
+
+ /// The raw data we're removing.
+ _marker: PhantomData<T>,
+}
+
+impl<'data, T> AncillaryIter<'data, T> {
+ /// Create a new iterator over data in an ancillary buffer.
+ ///
+ /// # Safety
+ ///
+ /// The buffer must contain valid ancillary data.
+ unsafe fn new(data: &'data mut [u8]) -> Self {
+ assert_eq!(data.len() % size_of::<T>(), 0);
+
+ Self {
+ data,
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl<'data, T> Drop for AncillaryIter<'data, T> {
+ fn drop(&mut self) {
+ self.for_each(drop);
+ }
+}
+
+impl<T> Iterator for AncillaryIter<'_, T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // See if there is a next item.
+ if self.data.len() < size_of::<T>() {
+ return None;
+ }
+
+ // Get the next item.
+ let item = unsafe { self.data.as_ptr().cast::<T>().read_unaligned() };
+
+ // Move forward.
+ let data = take(&mut self.data);
+ self.data = &mut data[size_of::<T>()..];
+
+ Some(item)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
+}
+
+impl<T> FusedIterator for AncillaryIter<'_, T> {}
+
+impl<T> ExactSizeIterator for AncillaryIter<'_, T> {
+ fn len(&self) -> usize {
+ self.data.len() / size_of::<T>()
+ }
+}
+
+impl<T> DoubleEndedIterator for AncillaryIter<'_, T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ // See if there is a next item.
+ if self.data.len() < size_of::<T>() {
+ return None;
+ }
+
+ // Get the next item.
+ let item = unsafe {
+ let ptr = self.data.as_ptr().add(self.data.len() - size_of::<T>());
+ ptr.cast::<T>().read_unaligned()
+ };
+
+ // Move forward.
+ let len = self.data.len();
+ let data = take(&mut self.data);
+ self.data = &mut data[..len - size_of::<T>()];
+
+ Some(item)
+ }
+}
+
+mod messages {
+ use crate::backend::c;
+ use crate::backend::net::msghdr;
+ use core::iter::FusedIterator;
+ use core::marker::PhantomData;
+ use core::mem::MaybeUninit;
+ use core::ptr::NonNull;
+
+ /// An iterator over the messages in an ancillary buffer.
+ pub(super) struct Messages<'buf> {
+ /// The message header we're using to iterate over the messages.
+ msghdr: c::msghdr,
+
+ /// The current pointer to the next message header to return.
+ ///
+ /// This has a lifetime of `'buf`.
+ header: Option<NonNull<c::cmsghdr>>,
+
+ /// Capture the original lifetime of the buffer.
+ _buffer: PhantomData<&'buf mut [MaybeUninit<u8>]>,
+ }
+
+ pub(super) trait AllowedMsgBufType {}
+ impl AllowedMsgBufType for u8 {}
+ impl AllowedMsgBufType for MaybeUninit<u8> {}
+
+ impl<'buf> Messages<'buf> {
+ /// Create a new iterator over messages from a byte buffer.
+ pub(super) fn new(buf: &'buf mut [impl AllowedMsgBufType]) -> Self {
+ let mut msghdr = msghdr::zero_msghdr();
+ msghdr.msg_control = buf.as_mut_ptr().cast();
+ msghdr.msg_controllen = buf.len().try_into().expect("buffer too large for msghdr");
+
+ // Get the first header.
+ let header = NonNull::new(unsafe { c::CMSG_FIRSTHDR(&msghdr) });
+
+ Self {
+ msghdr,
+ header,
+ _buffer: PhantomData,
+ }
+ }
+ }
+
+ impl<'a> Iterator for Messages<'a> {
+ type Item = &'a mut c::cmsghdr;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ // Get the current header.
+ let header = self.header?;
+
+ // Get the next header.
+ self.header = NonNull::new(unsafe { c::CMSG_NXTHDR(&self.msghdr, header.as_ptr()) });
+
+ // If the headers are equal, we're done.
+ if Some(header) == self.header {
+ self.header = None;
+ }
+
+ // SAFETY: The lifetime of `header` is tied to this.
+ Some(unsafe { &mut *header.as_ptr() })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.header.is_some() {
+ // The remaining buffer *could* be filled with zero-length
+ // messages.
+ let max_size = unsafe { c::CMSG_LEN(0) } as usize;
+ let remaining_count = self.msghdr.msg_controllen as usize / max_size;
+ (1, Some(remaining_count))
+ } else {
+ (0, Some(0))
+ }
+ }
+ }
+
+ impl FusedIterator for Messages<'_> {}
+}
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&section=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<Protocol>,
+) -> io::Result<OwnedFd> {
+ 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&section=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<Protocol>,
+) -> io::Result<OwnedFd> {
+ 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&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/bind
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Setting-Address.html
+pub fn bind<Fd: AsFd>(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&section=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<Fd: AsFd>(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&section=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<Fd: AsFd>(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&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/listen
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Listening.html
+#[inline]
+pub fn listen<Fd: AsFd>(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&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/accept
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Accepting-Connections.html
+#[inline]
+pub fn accept<Fd: AsFd>(sockfd: Fd) -> io::Result<OwnedFd> {
+ 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&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/accept4
+#[inline]
+#[doc(alias = "accept4")]
+pub fn accept_with<Fd: AsFd>(sockfd: Fd, flags: SocketFlags) -> io::Result<OwnedFd> {
+ 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&section=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<Fd: AsFd>(sockfd: Fd) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> {
+ 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&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/accept4
+#[inline]
+#[doc(alias = "accept4")]
+pub fn acceptfrom_with<Fd: AsFd>(
+ sockfd: Fd,
+ flags: SocketFlags,
+) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> {
+ 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&section=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<Fd: AsFd>(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&section=2
+/// [illumos]: https://illumos.org/man/3SOCKET/getsockname
+/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Reading-Address.html
+#[inline]
+pub fn getsockname<Fd: AsFd>(sockfd: Fd) -> io::Result<SocketAddrAny> {
+ 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&section=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<Fd: AsFd>(sockfd: Fd) -> io::Result<Option<SocketAddrAny>> {
+ 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<SocketAddrStorage>,
+}
+
+impl SocketAddrBuf {
+ #[inline]
+ pub(crate) const fn new() -> Self {
+ Self {
+ len: size_of::<SocketAddrStorage>() as c::socklen_t,
+ storage: MaybeUninit::<SocketAddrStorage>::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<SocketAddrAny>`].
+ ///
+ /// 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<SocketAddrAny> {
+ 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::<backend::c::sa_family_t>()`
+ // - `len` is at most `size_of::<SocketAddrStorage>()`
+ // - The first `len` bytes of `storage` are initialized.
+ pub(crate) len: NonZeroU32,
+ pub(crate) storage: MaybeUninit<SocketAddrStorage>,
+}
+
+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<SocketAddrStorage>, len: SocketAddrLen) -> Self {
+ assert!(len as usize >= size_of::<read_sockaddr::sockaddr_header>());
+ assert!(len as usize <= size_of::<SocketAddrStorage>());
+ 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::<read_sockaddr::sockaddr_header>());
+ assert!(len as usize <= size_of::<SocketAddrStorage>());
+ let mut storage = MaybeUninit::<SocketAddrStorage>::uninit();
+ core::ptr::copy_nonoverlapping(
+ ptr.cast::<u8>(),
+ storage.as_mut_ptr().cast::<u8>(),
+ 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<Self> 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<Self> for SocketAddrAny {
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ 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<H: core::hash::Hasher>(&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<R>(
+ &self,
+ f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
+ ) -> R {
+ f(self.as_ptr().cast(), self.addr_len())
+ }
+}
+
+impl From<SocketAddr> for SocketAddrAny {
+ #[inline]
+ fn from(from: SocketAddr) -> Self {
+ from.as_any()
+ }
+}
+
+impl TryFrom<SocketAddrAny> 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<Self, Self::Error> {
+ 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<SocketAddrV4> for SocketAddrAny {
+ #[inline]
+ fn from(from: SocketAddrV4) -> Self {
+ from.as_any()
+ }
+}
+
+impl TryFrom<SocketAddrAny> 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<Self, Self::Error> {
+ read_sockaddr::read_sockaddr_v4(&value)
+ }
+}
+
+impl From<SocketAddrV6> for SocketAddrAny {
+ #[inline]
+ fn from(from: SocketAddrV6) -> Self {
+ from.as_any()
+ }
+}
+
+impl TryFrom<SocketAddrAny> 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<Self, Self::Error> {
+ read_sockaddr::read_sockaddr_v6(&value)
+ }
+}
+
+#[cfg(unix)]
+impl From<SocketAddrUnix> for SocketAddrAny {
+ #[inline]
+ fn from(from: SocketAddrUnix) -> Self {
+ from.as_any()
+ }
+}
+
+#[cfg(unix)]
+impl TryFrom<SocketAddrAny> 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<Self, Self::Error> {
+ 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&section=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<Protocol>,
+) -> 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&section=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&section=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&section=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&section=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&section=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: AsFd>(fd: Fd) -> io::Result<SocketType> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(fd: Fd, value: Option<Duration>) -> 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: AsFd>(fd: Fd) -> io::Result<Option<Duration>> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(
+ fd: Fd,
+ id: Timeout,
+ value: Option<Duration>,
+) -> 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: AsFd>(fd: Fd, id: Timeout) -> io::Result<Option<Duration>> {
+ 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: AsFd>(fd: Fd) -> io::Result<Result<(), io::Errno>> {
+ 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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<usize> {
+ 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: AsFd>(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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<usize> {
+ 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: AsFd>(fd: Fd) -> io::Result<AddressFamily> {
+ 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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(fd: Fd) -> io::Result<Option<Protocol>> {
+ 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: AsFd>(fd: Fd) -> io::Result<u64> {
+ 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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(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: AsFd>(
+ 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: AsFd>(fd: Fd) -> io::Result<Ipv4Addr> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(fd: Fd) -> io::Result<u8> {
+ 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: AsFd>(fd: Fd, value: Option<u8>) -> 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(
+ 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: AsFd>(
+ 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: AsFd>(
+ 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: AsFd>(
+ 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: AsFd>(
+ 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: AsFd>(
+ 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: AsFd>(
+ 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: AsFd>(
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<u8> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(fd: Fd) -> io::Result<SocketAddrV4> {
+ 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: AsFd>(fd: Fd) -> io::Result<SocketAddrV6> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<Duration> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<Duration> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<u32> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<String> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<bool> {
+ 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: AsFd>(fd: Fd) -> io::Result<super::UCred> {
+ 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: AsFd>(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: AsFd>(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: AsFd>(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: AsFd>(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: AsFd>(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: AsFd>(fd: Fd) -> io::Result<XdpMmapOffsets> {
+ 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: AsFd>(fd: Fd) -> io::Result<XdpStatistics> {
+ 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: AsFd>(fd: Fd) -> io::Result<XdpOptionsFlags> {
+ 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<R>(
+ &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<SocketAddrNetlink> for SocketAddrAny {
+ #[inline]
+ fn from(from: SocketAddrNetlink) -> Self {
+ from.as_any()
+ }
+ }
+
+ #[cfg(linux_kernel)]
+ impl TryFrom<SocketAddrAny> for SocketAddrNetlink {
+ type Error = crate::io::Errno;
+
+ fn try_from(addr: SocketAddrAny) -> Result<Self, Self::Error> {
+ 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`.
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/if_xdp.h?h=v6.13#n15>
+ 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`].
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/if_xdp.h?h=v6.13#n48>
+ #[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<R>(
+ &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<SocketAddrXdp> for SocketAddrAny {
+ #[inline]
+ fn from(from: SocketAddrXdp) -> Self {
+ from.as_any()
+ }
+ }
+
+ impl TryFrom<SocketAddrAny> for SocketAddrXdp {
+ type Error = crate::io::Errno;
+
+ fn try_from(addr: SocketAddrAny) -> Result<Self, Self::Error> {
+ 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<R>(
+ &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`.
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/if_xdp.h?h=v6.13#n59>
+ #[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<u64>,
+ }
+
+ /// XDP mmap offsets.
+ ///
+ /// Not ABI compatible with `struct xdp_mmap_offsets`
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/if_xdp.h?h=v6.13#n66>
+ #[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`
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/if_xdp.h?h=v6.13#n79>
+ #[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`
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/if_xdp.h?h=v6.13#n92>
+ #[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<u64>,
+ /// 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<u64>,
+ /// Tx ring empty descriptors.
+ ///
+ /// Is `None` if the kernel version (<5.9) does not yet support flags.
+ pub tx_ring_empty_descs: Option<u64>,
+ }
+
+ /// XDP options.
+ ///
+ /// Requires kernel version 5.3.
+ /// `struct xdp_options`
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/if_xdp.h?h=v6.13#n101>
+ #[repr(C)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct XdpOptions {
+ /// Flags.
+ pub flags: XdpOptionsFlags,
+ }
+
+ /// XDP rx/tx frame descriptor.
+ ///
+ /// `struct xdp_desc`
+ // <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/if_xdp.h?h=v6.13#n154>
+ #[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<RawProtocol>, c_int);
+ assert_eq_size!(Option<Protocol>, 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<Protocol>` matching the ABI of a raw
+ // integer for correctness, but it should work nonetheless.
+ #[allow(unsafe_code)]
+ unsafe {
+ let t: Option<Protocol> = None;
+ assert_eq!(0_u32, transmute::<Option<Protocol>, u32>(t));
+
+ let t: Option<Protocol> = Some(Protocol::from_raw(RawProtocol::new(4567).unwrap()));
+ assert_eq!(4567_u32, transmute::<Option<Protocol>, 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<WSADATA> {
+ // 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()))
+ }
+ }
+}