summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/backend/linux_raw/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/backend/linux_raw/net
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/rustix/src/backend/linux_raw/net')
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/addr.rs300
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/mod.rs8
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/msghdr.rs125
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/netdevice.rs70
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs155
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/send_recv.rs87
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/sockopt.rs1099
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/syscalls.rs731
-rw-r--r--vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs31
9 files changed, 2606 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/linux_raw/net/addr.rs b/vendor/rustix/src/backend/linux_raw/net/addr.rs
new file mode 100644
index 00000000..7138b571
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/addr.rs
@@ -0,0 +1,300 @@
+//! Socket address utilities.
+//!
+//! # Safety
+//!
+//! This file uses `CStr::from_bytes_with_nul_unchecked` on a string it knows
+//! to be NUL-terminated.
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+use crate::ffi::CStr;
+use crate::net::addr::SocketAddrLen;
+use crate::net::AddressFamily;
+use crate::{io, path};
+use core::cmp::Ordering;
+use core::hash::{Hash, Hasher};
+use core::{fmt, slice};
+#[cfg(feature = "alloc")]
+use {crate::ffi::CString, alloc::borrow::Cow, alloc::vec::Vec};
+
+/// `struct sockaddr_un`
+#[derive(Clone)]
+#[doc(alias = "sockaddr_un")]
+pub struct SocketAddrUnix {
+ pub(crate) unix: c::sockaddr_un,
+ len: c::socklen_t,
+}
+
+impl SocketAddrUnix {
+ /// Construct a new Unix-domain address from a filesystem path.
+ #[inline]
+ pub fn new<P: path::Arg>(path: P) -> io::Result<Self> {
+ path.into_with_c_str(Self::_new)
+ }
+
+ #[inline]
+ fn _new(path: &CStr) -> io::Result<Self> {
+ let mut unix = Self::init();
+ let mut bytes = path.to_bytes_with_nul();
+ if bytes.len() > unix.sun_path.len() {
+ bytes = path.to_bytes(); // without NUL
+ if bytes.len() > unix.sun_path.len() {
+ return Err(io::Errno::NAMETOOLONG);
+ }
+ }
+ for (i, b) in bytes.iter().enumerate() {
+ unix.sun_path[i] = bitcast!(*b);
+ }
+ let len = offsetof_sun_path() + bytes.len();
+ let len = len.try_into().unwrap();
+ Ok(Self { unix, len })
+ }
+
+ /// Construct a new abstract Unix-domain address from a byte slice.
+ #[inline]
+ pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> {
+ let mut unix = Self::init();
+ let id = &mut unix.sun_path[1..];
+
+ // SAFETY: Convert `&mut [c_char]` to `&mut [u8]`.
+ let id = unsafe { slice::from_raw_parts_mut(id.as_mut_ptr().cast::<u8>(), id.len()) };
+
+ if let Some(id) = id.get_mut(..name.len()) {
+ id.copy_from_slice(name);
+ let len = offsetof_sun_path() + 1 + name.len();
+ let len = len.try_into().unwrap();
+ Ok(Self { unix, len })
+ } else {
+ Err(io::Errno::NAMETOOLONG)
+ }
+ }
+
+ /// Construct a new unnamed address.
+ ///
+ /// The kernel will assign an abstract Unix-domain address to the socket
+ /// when you call [`bind`][crate::net::bind]. You can inspect the assigned
+ /// name with [`getsockname`][crate::net::getsockname].
+ ///
+ /// # References
+ /// - [Linux]
+ ///
+ /// [Linux]: https://www.man7.org/linux/man-pages/man7/unix.7.html
+ #[inline]
+ pub fn new_unnamed() -> Self {
+ Self {
+ unix: Self::init(),
+ len: offsetof_sun_path() as SocketAddrLen,
+ }
+ }
+
+ const fn init() -> c::sockaddr_un {
+ c::sockaddr_un {
+ sun_family: c::AF_UNIX as _,
+ sun_path: [0; 108],
+ }
+ }
+
+ /// For a filesystem path address, return the path.
+ #[inline]
+ #[cfg(feature = "alloc")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
+ pub fn path(&self) -> Option<Cow<'_, CStr>> {
+ let bytes = self.bytes()?;
+ if !bytes.is_empty() && bytes[0] != 0 {
+ if self.unix.sun_path.len() == bytes.len() {
+ // SAFETY: There are no NULs contained in bytes.
+ unsafe { Self::path_with_termination(bytes) }
+ } else {
+ // SAFETY: `from_bytes_with_nul_unchecked` since the string is
+ // NUL-terminated.
+ Some(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }.into())
+ }
+ } else {
+ None
+ }
+ }
+
+ /// If the `sun_path` field is not NUL-terminated, terminate it.
+ ///
+ /// SAFETY: The input `bytes` must not contain any NULs.
+ #[cfg(feature = "alloc")]
+ #[cold]
+ unsafe fn path_with_termination(bytes: &[u8]) -> Option<Cow<'_, CStr>> {
+ let mut owned = Vec::with_capacity(bytes.len() + 1);
+ owned.extend_from_slice(bytes);
+ owned.push(b'\0');
+ // SAFETY: `from_vec_with_nul_unchecked` since the string is
+ // NUL-terminated and `bytes` does not contain any NULs.
+ Some(Cow::Owned(
+ CString::from_vec_with_nul_unchecked(owned).into(),
+ ))
+ }
+
+ /// For a filesystem path address, return the path as a byte sequence,
+ /// excluding the NUL terminator.
+ #[inline]
+ pub fn path_bytes(&self) -> Option<&[u8]> {
+ let bytes = self.bytes()?;
+ if !bytes.is_empty() && bytes[0] != 0 {
+ if self.unix.sun_path.len() == self.len() - offsetof_sun_path() {
+ // There is no NUL terminator.
+ Some(bytes)
+ } else {
+ // Remove the NUL terminator.
+ Some(&bytes[..bytes.len() - 1])
+ }
+ } else {
+ None
+ }
+ }
+
+ /// For an abstract address, return the identifier.
+ #[inline]
+ pub fn abstract_name(&self) -> Option<&[u8]> {
+ if let [0, bytes @ ..] = self.bytes()? {
+ Some(bytes)
+ } else {
+ None
+ }
+ }
+
+ /// `true` if the socket address is unnamed.
+ #[inline]
+ pub fn is_unnamed(&self) -> bool {
+ self.bytes() == Some(&[])
+ }
+
+ #[inline]
+ pub(crate) fn addr_len(&self) -> SocketAddrLen {
+ bitcast!(self.len)
+ }
+
+ #[inline]
+ pub(crate) fn len(&self) -> usize {
+ self.addr_len() as usize
+ }
+
+ #[inline]
+ fn bytes(&self) -> Option<&[u8]> {
+ let len = self.len();
+ if len != 0 {
+ let bytes = &self.unix.sun_path[..len - offsetof_sun_path()];
+ // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`.
+ Some(unsafe { slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len()) })
+ } else {
+ None
+ }
+ }
+}
+
+impl PartialEq for SocketAddrUnix {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ let self_len = self.len() - offsetof_sun_path();
+ let other_len = other.len() - offsetof_sun_path();
+ self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len])
+ }
+}
+
+impl Eq for SocketAddrUnix {}
+
+impl PartialOrd for SocketAddrUnix {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for SocketAddrUnix {
+ #[inline]
+ fn cmp(&self, other: &Self) -> Ordering {
+ let self_len = self.len() - offsetof_sun_path();
+ let other_len = other.len() - offsetof_sun_path();
+ self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len])
+ }
+}
+
+impl Hash for SocketAddrUnix {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let self_len = self.len() - offsetof_sun_path();
+ self.unix.sun_path[..self_len].hash(state)
+ }
+}
+
+impl fmt::Debug for SocketAddrUnix {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ #[cfg(feature = "alloc")]
+ if let Some(path) = self.path() {
+ return path.fmt(f);
+ }
+ if let Some(bytes) = self.path_bytes() {
+ if let Ok(s) = core::str::from_utf8(bytes) {
+ return s.fmt(f);
+ }
+ return bytes.fmt(f);
+ }
+ if let Some(name) = self.abstract_name() {
+ return name.fmt(f);
+ }
+ "(unnamed)".fmt(f)
+ }
+}
+
+/// `struct sockaddr_storage`
+///
+/// This type is guaranteed to be large enough to hold any encoded socket
+/// address.
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+#[doc(alias = "sockaddr_storage")]
+pub struct SocketAddrStorage(c::sockaddr_storage);
+
+// SAFETY: Bindgen adds a union with a raw pointer for alignment but it's never
+// used. `sockaddr_storage` is just a bunch of bytes and it doesn't hold
+// pointers.
+unsafe impl Send for SocketAddrStorage {}
+
+// SAFETY: Same as with `Send`.
+unsafe impl Sync for SocketAddrStorage {}
+
+impl SocketAddrStorage {
+ /// Return a socket addr storage initialized to all zero bytes. The
+ /// `sa_family` is set to [`AddressFamily::UNSPEC`].
+ pub fn zeroed() -> Self {
+ assert_eq!(c::AF_UNSPEC, 0);
+ // SAFETY: `sockaddr_storage` is meant to be zero-initializable.
+ unsafe { core::mem::zeroed() }
+ }
+
+ /// Return the `sa_family` of this socket address.
+ pub fn family(&self) -> AddressFamily {
+ // SAFETY: `self.0` is a `sockaddr_storage` so it has enough space.
+ unsafe {
+ AddressFamily::from_raw(crate::backend::net::read_sockaddr::read_sa_family(
+ crate::utils::as_ptr(&self.0).cast::<c::sockaddr>(),
+ ))
+ }
+ }
+
+ /// Clear the `sa_family` of this socket address to
+ /// [`AddressFamily::UNSPEC`].
+ pub fn clear_family(&mut self) {
+ // SAFETY: `self.0` is a `sockaddr_storage` so it has enough space.
+ unsafe {
+ crate::backend::net::read_sockaddr::initialize_family_to_unspec(
+ crate::utils::as_mut_ptr(&mut self.0).cast::<c::sockaddr>(),
+ )
+ }
+ }
+}
+
+/// Return the offset of the `sun_path` field of `sockaddr_un`.
+#[inline]
+pub(crate) fn offsetof_sun_path() -> usize {
+ let z = c::sockaddr_un {
+ sun_family: 0_u16,
+ sun_path: [0; 108],
+ };
+ (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize)
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/mod.rs b/vendor/rustix/src/backend/linux_raw/net/mod.rs
new file mode 100644
index 00000000..169954f2
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/mod.rs
@@ -0,0 +1,8 @@
+pub(crate) mod addr;
+pub(crate) mod msghdr;
+pub(crate) mod netdevice;
+pub(crate) mod read_sockaddr;
+pub(crate) mod send_recv;
+pub(crate) mod sockopt;
+pub(crate) mod syscalls;
+pub(crate) mod write_sockaddr;
diff --git a/vendor/rustix/src/backend/linux_raw/net/msghdr.rs b/vendor/rustix/src/backend/linux_raw/net/msghdr.rs
new file mode 100644
index 00000000..0343e18c
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/msghdr.rs
@@ -0,0 +1,125 @@
+//! Utilities for dealing with message headers.
+//!
+//! These take closures rather than returning a `c::msghdr` directly because
+//! the message headers may reference stack-local data.
+
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::net::addr::SocketAddrArg;
+use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrBuf};
+
+use core::ptr::null_mut;
+
+fn msg_iov_len(len: usize) -> c::size_t {
+ // This cast cannot overflow.
+ len as c::size_t
+}
+
+fn msg_control_len(len: usize) -> c::size_t {
+ // Same as above.
+ len as c::size_t
+}
+
+/// Create a message header intended to receive a datagram.
+///
+/// # Safety
+///
+/// If `f` dereferences the pointers in the `msghdr`, it must do so only within
+/// the bounds indicated by the associated lengths in the `msghdr`.
+///
+/// And, if `f` returns `Ok`, it must have updated the `msg_controllen` field
+/// of the `msghdr` to indicate how many bytes it initialized.
+pub(crate) unsafe fn with_recv_msghdr<R>(
+ name: &mut SocketAddrBuf,
+ iov: &mut [IoSliceMut<'_>],
+ control: &mut RecvAncillaryBuffer<'_>,
+ f: impl FnOnce(&mut c::msghdr) -> io::Result<R>,
+) -> io::Result<R> {
+ control.clear();
+
+ let mut msghdr = c::msghdr {
+ msg_name: name.storage.as_mut_ptr().cast(),
+ msg_namelen: bitcast!(name.len),
+ msg_iov: iov.as_mut_ptr().cast(),
+ msg_iovlen: msg_iov_len(iov.len()),
+ msg_control: control.as_control_ptr().cast(),
+ msg_controllen: msg_control_len(control.control_len()),
+ msg_flags: 0,
+ };
+
+ let res = f(&mut msghdr);
+
+ // Reset the control length.
+ if res.is_ok() {
+ // SAFETY: `f` returned `Ok`, so our safety condition requires `f` to
+ // have initialized `msg_controllen` bytes.
+ control.set_control_len(msghdr.msg_controllen as usize);
+ }
+
+ name.len = bitcast!(msghdr.msg_namelen);
+
+ res
+}
+
+/// Create a message header intended to send without an address.
+///
+/// The returned `msghdr` will contain raw pointers to the memory
+/// referenced by `iov` and `control`.
+pub(crate) fn noaddr_msghdr(
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+) -> c::msghdr {
+ c::msghdr {
+ msg_name: null_mut(),
+ msg_namelen: 0,
+ msg_iov: iov.as_ptr() as _,
+ msg_iovlen: msg_iov_len(iov.len()),
+ msg_control: control.as_control_ptr().cast(),
+ msg_controllen: msg_control_len(control.control_len()),
+ msg_flags: 0,
+ }
+}
+
+/// Create a message header intended to send with the specified address.
+///
+/// This creates a `c::msghdr` and calls a function `f` on it. The `msghdr`'s
+/// raw pointers may point to temporaries, so this function should avoid
+/// storing the pointers anywhere that would outlive the function call.
+///
+/// # Safety
+///
+/// If `f` dereferences the pointers in the `msghdr`, it must do so only within
+/// the bounds indicated by the associated lengths in the `msghdr`.
+pub(crate) unsafe fn with_msghdr<R>(
+ addr: &impl SocketAddrArg,
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+ f: impl FnOnce(&c::msghdr) -> R,
+) -> R {
+ addr.with_sockaddr(|addr_ptr, addr_len| {
+ // Pass a reference to the `c::msghdr` instead of passing it by value
+ // because it may contain pointers to temporary objects that won't live
+ // beyond the call to `with_sockaddr`.
+ let mut msghdr = noaddr_msghdr(iov, control);
+ msghdr.msg_name = addr_ptr as _;
+ msghdr.msg_namelen = bitcast!(addr_len);
+
+ f(&msghdr)
+ })
+}
+
+/// Create a zero-initialized message header struct value.
+pub(crate) fn zero_msghdr() -> c::msghdr {
+ c::msghdr {
+ msg_name: null_mut(),
+ msg_namelen: 0,
+ msg_iov: null_mut(),
+ msg_iovlen: 0,
+ msg_control: null_mut(),
+ msg_controllen: 0,
+ msg_flags: 0,
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/netdevice.rs b/vendor/rustix/src/backend/linux_raw/net/netdevice.rs
new file mode 100644
index 00000000..d3c2a964
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/netdevice.rs
@@ -0,0 +1,70 @@
+//! Wrappers for netdevice ioctls.
+
+#![allow(unsafe_code)]
+
+use crate::backend::io::syscalls::ioctl;
+use crate::fd::BorrowedFd;
+use crate::io;
+use core::ptr::addr_of_mut;
+use core::{slice, str};
+use linux_raw_sys::ctypes::c_char;
+use linux_raw_sys::ioctl::SIOCGIFINDEX;
+#[cfg(feature = "alloc")]
+use linux_raw_sys::ioctl::SIOCGIFNAME;
+use linux_raw_sys::net::{ifreq, ifreq__bindgen_ty_1, ifreq__bindgen_ty_2, IFNAMSIZ};
+#[cfg(feature = "alloc")]
+use {alloc::borrow::ToOwned, alloc::string::String};
+
+pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result<u32> {
+ let if_name_bytes = if_name.as_bytes();
+ if if_name_bytes.len() >= IFNAMSIZ as usize {
+ return Err(io::Errno::NODEV);
+ }
+ if if_name_bytes.contains(&0) {
+ return Err(io::Errno::NODEV);
+ }
+
+ // SAFETY: Convert `&[u8]` to `&[c_char]`.
+ let if_name_bytes = unsafe {
+ slice::from_raw_parts(if_name_bytes.as_ptr().cast::<c_char>(), if_name_bytes.len())
+ };
+
+ let mut ifreq = ifreq {
+ ifr_ifrn: ifreq__bindgen_ty_1 { ifrn_name: [0; 16] },
+ ifr_ifru: ifreq__bindgen_ty_2 { ifru_ivalue: 0 },
+ };
+ unsafe { ifreq.ifr_ifrn.ifrn_name[..if_name_bytes.len()].copy_from_slice(if_name_bytes) };
+
+ unsafe { ioctl(fd, SIOCGIFINDEX, addr_of_mut!(ifreq).cast()) }?;
+ let index = unsafe { ifreq.ifr_ifru.ifru_ivalue };
+ Ok(index as u32)
+}
+
+#[cfg(feature = "alloc")]
+pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<String> {
+ let mut ifreq = ifreq {
+ ifr_ifrn: ifreq__bindgen_ty_1 { ifrn_name: [0; 16] },
+ ifr_ifru: ifreq__bindgen_ty_2 {
+ ifru_ivalue: index as _,
+ },
+ };
+
+ unsafe { ioctl(fd, SIOCGIFNAME, addr_of_mut!(ifreq).cast()) }?;
+
+ if let Some(nul_byte) = unsafe { ifreq.ifr_ifrn.ifrn_name }
+ .iter()
+ .position(|ch| *ch == 0)
+ {
+ let ifrn_name = unsafe { &ifreq.ifr_ifrn.ifrn_name[..nul_byte] };
+
+ // SAFETY: Convert `&[c_char]` to `&[u8]`.
+ let ifrn_name =
+ unsafe { slice::from_raw_parts(ifrn_name.as_ptr().cast::<u8>(), ifrn_name.len()) };
+
+ str::from_utf8(ifrn_name)
+ .map_err(|_| io::Errno::ILSEQ)
+ .map(ToOwned::to_owned)
+ } else {
+ Err(io::Errno::INVAL)
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs b/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs
new file mode 100644
index 00000000..f18cd483
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs
@@ -0,0 +1,155 @@
+//! The BSD sockets API requires us to read the `sa_family` field before we can
+//! interpret the rest of a `sockaddr` produced by the kernel.
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+use crate::io::Errno;
+use crate::net::addr::SocketAddrLen;
+use crate::net::netlink::SocketAddrNetlink;
+#[cfg(target_os = "linux")]
+use crate::net::xdp::{SocketAddrXdp, SocketAddrXdpFlags};
+use crate::net::{
+ AddressFamily, Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6,
+};
+use core::mem::size_of;
+use core::slice;
+
+// This must match the header of `sockaddr`.
+#[repr(C)]
+pub(crate) struct sockaddr_header {
+ sa_family: u16,
+}
+
+/// Read the `sa_family` field from a socket address returned from the OS.
+///
+/// # Safety
+///
+/// `storage` must point to a least an initialized `sockaddr_header`.
+#[inline]
+pub(crate) const unsafe fn read_sa_family(storage: *const c::sockaddr) -> u16 {
+ // Assert that we know the layout of `sockaddr`.
+ let _ = c::sockaddr {
+ __storage: c::sockaddr_storage {
+ __bindgen_anon_1: linux_raw_sys::net::__kernel_sockaddr_storage__bindgen_ty_1 {
+ __bindgen_anon_1:
+ linux_raw_sys::net::__kernel_sockaddr_storage__bindgen_ty_1__bindgen_ty_1 {
+ ss_family: 0_u16,
+ __data: [0; 126_usize],
+ },
+ },
+ },
+ };
+
+ (*storage.cast::<sockaddr_header>()).sa_family
+}
+
+/// Set the `sa_family` field of a socket address to `AF_UNSPEC`, so that we
+/// can test for `AF_UNSPEC` to test whether it was stored to.
+///
+/// # Safety
+///
+/// `storage` must point to a least an initialized `sockaddr_header`.
+#[inline]
+pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr) {
+ (*storage.cast::<sockaddr_header>()).sa_family = c::AF_UNSPEC as _;
+}
+
+/// Check if a socket address returned from the OS is considered non-empty.
+#[inline]
+pub(crate) unsafe fn sockaddr_nonempty(_storage: *const c::sockaddr, len: SocketAddrLen) -> bool {
+ len != 0
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_v4(addr: &SocketAddrAny) -> Result<SocketAddrV4, Errno> {
+ if addr.address_family() != AddressFamily::INET {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_in>());
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_in>() };
+ Ok(SocketAddrV4::new(
+ Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)),
+ u16::from_be(decode.sin_port),
+ ))
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_v6(addr: &SocketAddrAny) -> Result<SocketAddrV6, Errno> {
+ if addr.address_family() != AddressFamily::INET6 {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_in6>());
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_in6>() };
+ Ok(SocketAddrV6::new(
+ Ipv6Addr::from(unsafe { decode.sin6_addr.in6_u.u6_addr8 }),
+ u16::from_be(decode.sin6_port),
+ u32::from_be(decode.sin6_flowinfo),
+ decode.sin6_scope_id,
+ ))
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_unix(addr: &SocketAddrAny) -> Result<SocketAddrUnix, Errno> {
+ if addr.address_family() != AddressFamily::UNIX {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ let offsetof_sun_path = super::addr::offsetof_sun_path();
+ let len = addr.addr_len() as usize;
+
+ assert!(len >= offsetof_sun_path);
+
+ if len == offsetof_sun_path {
+ SocketAddrUnix::new(&[][..])
+ } else {
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_un>() };
+
+ // On Linux check for Linux's [abstract namespace].
+ //
+ // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html
+ if decode.sun_path[0] == 0 {
+ let bytes = &decode.sun_path[1..len - offsetof_sun_path];
+
+ // SAFETY: Convert `&[c_char]` to `&[u8]`.
+ let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<u8>(), bytes.len()) };
+
+ return SocketAddrUnix::new_abstract_name(bytes);
+ }
+
+ // Otherwise we expect a NUL-terminated filesystem path.
+ let bytes = &decode.sun_path[..len - 1 - offsetof_sun_path];
+
+ // SAFETY: Convert `&[c_char]` to `&[u8]`.
+ let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<u8>(), bytes.len()) };
+
+ assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0);
+ SocketAddrUnix::new(bytes)
+ }
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_xdp(addr: &SocketAddrAny) -> Result<SocketAddrXdp, Errno> {
+ if addr.address_family() != AddressFamily::XDP {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_xdp>());
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_xdp>() };
+
+ // This ignores the `sxdp_shared_umem_fd` field, which is only expected to
+ // be significant in `bind` calls, and not returned from `acceptfrom` or
+ // `recvmsg` or similar.
+ Ok(SocketAddrXdp::new(
+ SocketAddrXdpFlags::from_bits_retain(decode.sxdp_flags),
+ u32::from_be(decode.sxdp_ifindex),
+ u32::from_be(decode.sxdp_queue_id),
+ ))
+}
+
+#[inline]
+pub(crate) fn read_sockaddr_netlink(addr: &SocketAddrAny) -> Result<SocketAddrNetlink, Errno> {
+ if addr.address_family() != AddressFamily::NETLINK {
+ return Err(Errno::AFNOSUPPORT);
+ }
+ assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_nl>());
+ let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_nl>() };
+ Ok(SocketAddrNetlink::new(decode.nl_pid, decode.nl_groups))
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/send_recv.rs b/vendor/rustix/src/backend/linux_raw/net/send_recv.rs
new file mode 100644
index 00000000..3262d01f
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/send_recv.rs
@@ -0,0 +1,87 @@
+use crate::backend::c;
+use bitflags::bitflags;
+
+bitflags! {
+ /// `MSG_*` flags for use with [`send`], [`sendto`], and related
+ /// functions.
+ ///
+ /// [`send`]: crate::net::send
+ /// [`sendto`]: crate::net::sendto
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct SendFlags: u32 {
+ /// `MSG_CONFIRM`
+ const CONFIRM = c::MSG_CONFIRM;
+ /// `MSG_DONTROUTE`
+ const DONTROUTE = c::MSG_DONTROUTE;
+ /// `MSG_DONTWAIT`
+ const DONTWAIT = c::MSG_DONTWAIT;
+ /// `MSG_EOR`
+ const EOR = c::MSG_EOR;
+ /// `MSG_MORE`
+ const MORE = c::MSG_MORE;
+ /// `MSG_NOSIGNAL`
+ const NOSIGNAL = c::MSG_NOSIGNAL;
+ /// `MSG_OOB`
+ const OOB = c::MSG_OOB;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MSG_*` flags for use with [`recv`], [`recvfrom`], and related
+ /// functions.
+ ///
+ /// [`recv`]: crate::net::recv
+ /// [`recvfrom`]: crate::net::recvfrom
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct RecvFlags: u32 {
+ /// `MSG_CMSG_CLOEXEC`
+ const CMSG_CLOEXEC = c::MSG_CMSG_CLOEXEC;
+ /// `MSG_DONTWAIT`
+ const DONTWAIT = c::MSG_DONTWAIT;
+ /// `MSG_ERRQUEUE`
+ const ERRQUEUE = c::MSG_ERRQUEUE;
+ /// `MSG_OOB`
+ const OOB = c::MSG_OOB;
+ /// `MSG_PEEK`
+ const PEEK = c::MSG_PEEK;
+ /// `MSG_TRUNC`
+ const TRUNC = c::MSG_TRUNC;
+ /// `MSG_WAITALL`
+ const WAITALL = c::MSG_WAITALL;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+bitflags! {
+ /// `MSG_*` flags returned from [`recvmsg`], in the `flags` field of
+ /// [`RecvMsg`]
+ ///
+ /// [`recvmsg`]: crate::net::recvmsg
+ /// [`RecvMsg`]: crate::net::RecvMsg
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct ReturnFlags: u32 {
+ /// `MSG_OOB`
+ const OOB = c::MSG_OOB;
+ /// `MSG_EOR`
+ const EOR = c::MSG_EOR;
+ /// `MSG_TRUNC`
+ const TRUNC = c::MSG_TRUNC;
+ /// `MSG_CTRUNC`
+ const CTRUNC = c::MSG_CTRUNC;
+ /// `MSG_ERRQUEUE`
+ const ERRQUEUE = c::MSG_ERRQUEUE;
+ /// `MSG_CMSG_CLOEXEC`
+ const CMSG_CLOEXEC = c::MSG_CMSG_CLOEXEC;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/sockopt.rs b/vendor/rustix/src/backend/linux_raw/net/sockopt.rs
new file mode 100644
index 00000000..3e5ea1fd
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/sockopt.rs
@@ -0,0 +1,1099 @@
+//! linux_raw syscalls supporting `rustix::net::sockopt`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use crate::backend::c;
+use crate::backend::conv::{by_mut, c_uint, ret, socklen_t};
+use crate::fd::BorrowedFd;
+#[cfg(feature = "alloc")]
+use crate::ffi::CStr;
+use crate::io;
+use crate::net::sockopt::Timeout;
+#[cfg(target_os = "linux")]
+use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
+use crate::net::{
+ AddressFamily, Ipv4Addr, Ipv6Addr, Protocol, RawProtocol, SocketAddrBuf, SocketAddrV4,
+ SocketAddrV6, SocketType, UCred,
+};
+#[cfg(feature = "alloc")]
+use alloc::borrow::ToOwned as _;
+#[cfg(feature = "alloc")]
+use alloc::string::String;
+use core::mem::{size_of, MaybeUninit};
+use core::time::Duration;
+use linux_raw_sys::general::{__kernel_old_timeval, __kernel_sock_timeval};
+use linux_raw_sys::net::{IPV6_MTU, IPV6_MULTICAST_IF, IP_MTU, IP_MULTICAST_IF};
+#[cfg(target_os = "linux")]
+use linux_raw_sys::xdp::{xdp_mmap_offsets, xdp_statistics, xdp_statistics_v1};
+#[cfg(target_arch = "x86")]
+use {
+ crate::backend::conv::{slice_just_addr, x86_sys},
+ crate::backend::reg::{ArgReg, SocketArg},
+ linux_raw_sys::net::{SYS_GETSOCKOPT, SYS_SETSOCKOPT},
+};
+
+#[inline]
+fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> {
+ let mut optlen: c::socklen_t = size_of::<T>().try_into().unwrap();
+ debug_assert!(
+ optlen as usize >= size_of::<c::c_int>(),
+ "Socket APIs don't ever use `bool` directly"
+ );
+
+ let mut value = MaybeUninit::<T>::uninit();
+ getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?;
+
+ assert_eq!(
+ optlen as usize,
+ size_of::<T>(),
+ "unexpected getsockopt size"
+ );
+
+ unsafe { Ok(value.assume_init()) }
+}
+
+#[inline]
+fn getsockopt_raw<T>(
+ fd: BorrowedFd<'_>,
+ level: u32,
+ optname: u32,
+ value: &mut MaybeUninit<T>,
+ optlen: &mut c::socklen_t,
+) -> io::Result<()> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret(syscall!(
+ __NR_getsockopt,
+ fd,
+ c_uint(level),
+ c_uint(optname),
+ value,
+ by_mut(optlen)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_GETSOCKOPT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ c_uint(level),
+ c_uint(optname),
+ value.into(),
+ by_mut(optlen),
+ ])
+ ))
+ }
+}
+
+#[inline]
+fn setsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32, value: T) -> io::Result<()> {
+ let optlen = size_of::<T>().try_into().unwrap();
+ debug_assert!(
+ optlen as usize >= size_of::<c::c_int>(),
+ "Socket APIs don't ever use `bool` directly"
+ );
+ setsockopt_raw(fd, level, optname, &value, optlen)
+}
+
+#[inline]
+fn setsockopt_raw<T>(
+ fd: BorrowedFd<'_>,
+ level: u32,
+ optname: u32,
+ ptr: *const T,
+ optlen: c::socklen_t,
+) -> io::Result<()> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_setsockopt,
+ fd,
+ c_uint(level),
+ c_uint(optname),
+ ptr,
+ socklen_t(optlen)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_SETSOCKOPT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ c_uint(level),
+ c_uint(optname),
+ ptr.into(),
+ socklen_t(optlen),
+ ])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_TYPE)
+}
+
+#[inline]
+pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR, from_bool(reuseaddr))
+}
+
+#[inline]
+pub(crate) fn socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST, from_bool(broadcast))
+}
+
+#[inline]
+pub(crate) fn socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_linger(fd: BorrowedFd<'_>, linger: Option<Duration>) -> io::Result<()> {
+ // Convert `linger` to seconds, rounding up.
+ let l_linger = if let Some(linger) = linger {
+ duration_to_secs(linger)?
+ } else {
+ 0
+ };
+ let linger = c::linger {
+ l_onoff: c::c_int::from(linger.is_some()),
+ l_linger,
+ };
+ setsockopt(fd, c::SOL_SOCKET, c::SO_LINGER, linger)
+}
+
+#[inline]
+pub(crate) fn socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> {
+ let linger: c::linger = getsockopt(fd, c::SOL_SOCKET, c::SO_LINGER)?;
+ Ok((linger.l_onoff != 0).then(|| Duration::from_secs(linger.l_linger as u64)))
+}
+
+#[inline]
+pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED, from_bool(passcred))
+}
+
+#[inline]
+pub(crate) fn socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_timeout(
+ fd: BorrowedFd<'_>,
+ id: Timeout,
+ timeout: Option<Duration>,
+) -> io::Result<()> {
+ let time = duration_to_linux_sock_timeval(timeout)?;
+ let optname = match id {
+ Timeout::Recv => c::SO_RCVTIMEO_NEW,
+ Timeout::Send => c::SO_SNDTIMEO_NEW,
+ };
+ match setsockopt(fd, c::SOL_SOCKET, optname, time) {
+ Err(io::Errno::NOPROTOOPT) if c::SO_RCVTIMEO_NEW != c::SO_RCVTIMEO_OLD => {
+ set_socket_timeout_old(fd, id, timeout)
+ }
+ otherwise => otherwise,
+ }
+}
+
+/// Same as `set_socket_timeout` but uses `__kernel_old_timeval` instead of
+/// `__kernel_sock_timeval` and `_OLD` constants instead of `_NEW`.
+fn set_socket_timeout_old(
+ fd: BorrowedFd<'_>,
+ id: Timeout,
+ timeout: Option<Duration>,
+) -> io::Result<()> {
+ let time = duration_to_linux_old_timeval(timeout)?;
+ let optname = match id {
+ Timeout::Recv => c::SO_RCVTIMEO_OLD,
+ Timeout::Send => c::SO_SNDTIMEO_OLD,
+ };
+ setsockopt(fd, c::SOL_SOCKET, optname, time)
+}
+
+#[inline]
+pub(crate) fn socket_timeout(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
+ let optname = match id {
+ Timeout::Recv => c::SO_RCVTIMEO_NEW,
+ Timeout::Send => c::SO_SNDTIMEO_NEW,
+ };
+ let time: __kernel_sock_timeval = match getsockopt(fd, c::SOL_SOCKET, optname) {
+ Err(io::Errno::NOPROTOOPT) if c::SO_RCVTIMEO_NEW != c::SO_RCVTIMEO_OLD => {
+ return socket_timeout_old(fd, id)
+ }
+ otherwise => otherwise?,
+ };
+ Ok(duration_from_linux_sock_timeval(time))
+}
+
+/// Same as `get_socket_timeout` but uses `__kernel_old_timeval` instead of
+/// `__kernel_sock_timeval` and `_OLD` constants instead of `_NEW`.
+fn socket_timeout_old(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
+ let optname = match id {
+ Timeout::Recv => c::SO_RCVTIMEO_OLD,
+ Timeout::Send => c::SO_SNDTIMEO_OLD,
+ };
+ let time: __kernel_old_timeval = getsockopt(fd, c::SOL_SOCKET, optname)?;
+ Ok(duration_from_linux_old_timeval(time))
+}
+
+/// Convert a `__linux_sock_timeval` to a Rust `Option<Duration>`.
+#[inline]
+fn duration_from_linux_sock_timeval(time: __kernel_sock_timeval) -> Option<Duration> {
+ if time.tv_sec == 0 && time.tv_usec == 0 {
+ None
+ } else {
+ Some(Duration::from_secs(time.tv_sec as u64) + Duration::from_micros(time.tv_usec as u64))
+ }
+}
+
+/// Like `duration_from_linux_sock_timeval` but uses Linux's old 32-bit
+/// `__kernel_old_timeval`.
+fn duration_from_linux_old_timeval(time: __kernel_old_timeval) -> Option<Duration> {
+ if time.tv_sec == 0 && time.tv_usec == 0 {
+ None
+ } else {
+ Some(Duration::from_secs(time.tv_sec as u64) + Duration::from_micros(time.tv_usec as u64))
+ }
+}
+
+/// Convert a Rust `Option<Duration>` to a `__kernel_sock_timeval`.
+#[inline]
+fn duration_to_linux_sock_timeval(timeout: Option<Duration>) -> io::Result<__kernel_sock_timeval> {
+ Ok(match timeout {
+ Some(timeout) => {
+ if timeout == Duration::ZERO {
+ return Err(io::Errno::INVAL);
+ }
+ // `subsec_micros` rounds down, so we use `subsec_nanos` and
+ // manually round up.
+ let mut timeout = __kernel_sock_timeval {
+ tv_sec: timeout.as_secs().try_into().unwrap_or(i64::MAX),
+ tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => __kernel_sock_timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ },
+ })
+}
+
+/// Like `duration_to_linux_sock_timeval` but uses Linux's old 32-bit
+/// `__kernel_old_timeval`.
+fn duration_to_linux_old_timeval(timeout: Option<Duration>) -> io::Result<__kernel_old_timeval> {
+ Ok(match timeout {
+ Some(timeout) => {
+ if timeout == Duration::ZERO {
+ return Err(io::Errno::INVAL);
+ }
+
+ // `subsec_micros` rounds down, so we use `subsec_nanos` and
+ // manually round up.
+ let mut timeout = __kernel_old_timeval {
+ tv_sec: timeout.as_secs().try_into().unwrap_or(c::c_long::MAX),
+ tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => __kernel_old_timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ },
+ })
+}
+
+#[inline]
+pub(crate) fn socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> {
+ let err: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_ERROR)?;
+ Ok(if err == 0 {
+ Ok(())
+ } else {
+ Err(io::Errno::from_raw_os_error(err))
+ })
+}
+
+#[inline]
+pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE, from_bool(keepalive))
+}
+
+#[inline]
+pub(crate) fn socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
+ setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF, size)
+}
+
+#[inline]
+pub(crate) fn set_socket_recv_buffer_size_force(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
+ setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUFFORCE, size)
+}
+
+#[inline]
+pub(crate) fn socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF).map(|size: u32| size as usize)
+}
+
+#[inline]
+pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
+ setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF, size)
+}
+
+#[inline]
+pub(crate) fn set_socket_send_buffer_size_force(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
+ let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
+ setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUFFORCE, size)
+}
+
+#[inline]
+pub(crate) fn socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF).map(|size: u32| size as usize)
+}
+
+#[inline]
+pub(crate) fn socket_domain(fd: BorrowedFd<'_>) -> io::Result<AddressFamily> {
+ let domain: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_DOMAIN)?;
+ Ok(AddressFamily(
+ domain.try_into().map_err(|_| io::Errno::OPNOTSUPP)?,
+ ))
+}
+
+#[inline]
+pub(crate) fn socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_ACCEPTCONN).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_oobinline(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn socket_oobinline(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_socket_reuseport(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn socket_reuseport(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn socket_protocol(fd: BorrowedFd<'_>) -> io::Result<Option<Protocol>> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_PROTOCOL)
+ .map(|raw: u32| RawProtocol::new(raw).map(Protocol::from_raw))
+}
+
+#[inline]
+pub(crate) fn socket_cookie(fd: BorrowedFd<'_>) -> io::Result<u64> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_COOKIE)
+}
+
+#[inline]
+pub(crate) fn socket_incoming_cpu(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU)
+}
+
+#[inline]
+pub(crate) fn set_socket_incoming_cpu(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU, value)
+}
+
+#[inline]
+pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_TTL, ttl)
+}
+
+#[inline]
+pub(crate) fn ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_TTL)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY, from_bool(only_v6))
+}
+
+#[inline]
+pub(crate) fn ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn ip_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IP, IP_MTU)
+}
+
+#[inline]
+pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU)
+}
+
+#[inline]
+pub(crate) fn set_ip_multicast_if_with_ifindex(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ address: &Ipv4Addr,
+ ifindex: u32,
+) -> io::Result<()> {
+ let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
+ setsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF, mreqn)
+}
+
+#[inline]
+pub(crate) fn set_ip_multicast_if(fd: BorrowedFd<'_>, value: &Ipv4Addr) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF, to_imr_addr(value))
+}
+
+#[inline]
+pub(crate) fn ip_multicast_if(fd: BorrowedFd<'_>) -> io::Result<Ipv4Addr> {
+ getsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF).map(from_in_addr)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_multicast_if(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, IPV6_MULTICAST_IF, value as c::c_int)
+}
+
+#[inline]
+pub(crate) fn ipv6_multicast_if(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IPV6, IPV6_MULTICAST_IF)
+}
+
+#[inline]
+pub(crate) fn set_ip_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> {
+ setsockopt(
+ fd,
+ c::IPPROTO_IP,
+ c::IP_MULTICAST_LOOP,
+ from_bool(multicast_loop),
+ )
+}
+
+#[inline]
+pub(crate) fn ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_LOOP).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl)
+}
+
+#[inline]
+pub(crate) fn ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> {
+ setsockopt(
+ fd,
+ c::IPPROTO_IPV6,
+ c::IPV6_MULTICAST_LOOP,
+ from_bool(multicast_loop),
+ )
+}
+
+#[inline]
+pub(crate) fn ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_multicast_hops(fd: BorrowedFd<'_>, multicast_hops: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS, multicast_hops)
+}
+
+#[inline]
+pub(crate) fn ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS)
+}
+
+#[inline]
+pub(crate) fn set_ip_add_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+) -> io::Result<()> {
+ let mreq = to_ip_mreq(multiaddr, interface);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
+}
+
+#[inline]
+pub(crate) fn set_ip_add_membership_with_ifindex(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ address: &Ipv4Addr,
+ ifindex: u32,
+) -> io::Result<()> {
+ let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreqn)
+}
+
+#[inline]
+pub(crate) fn set_ip_add_source_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+ sourceaddr: &Ipv4Addr,
+) -> io::Result<()> {
+ let mreq_source = to_imr_source(multiaddr, interface, sourceaddr);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_SOURCE_MEMBERSHIP, mreq_source)
+}
+
+#[inline]
+pub(crate) fn set_ip_drop_source_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+ sourceaddr: &Ipv4Addr,
+) -> io::Result<()> {
+ let mreq_source = to_imr_source(multiaddr, interface, sourceaddr);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_SOURCE_MEMBERSHIP, mreq_source)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_add_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv6Addr,
+ interface: u32,
+) -> io::Result<()> {
+ let mreq = to_ipv6mr(multiaddr, interface);
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_ADD_MEMBERSHIP, mreq)
+}
+
+#[inline]
+pub(crate) fn set_ip_drop_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+) -> io::Result<()> {
+ let mreq = to_ip_mreq(multiaddr, interface);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
+}
+
+#[inline]
+pub(crate) fn set_ip_drop_membership_with_ifindex(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv4Addr,
+ address: &Ipv4Addr,
+ ifindex: u32,
+) -> io::Result<()> {
+ let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
+ setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreqn)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_drop_membership(
+ fd: BorrowedFd<'_>,
+ multiaddr: &Ipv6Addr,
+ interface: u32,
+) -> io::Result<()> {
+ let mreq = to_ipv6mr(multiaddr, interface);
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_DROP_MEMBERSHIP, mreq)
+}
+
+#[inline]
+pub(crate) fn ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> {
+ let hops = match hops {
+ Some(hops) => hops.into(),
+ None => -1,
+ };
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, hops)
+}
+
+#[inline]
+pub(crate) fn set_ip_tos(fd: BorrowedFd<'_>, value: u8) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_TOS, i32::from(value))
+}
+
+#[inline]
+pub(crate) fn ip_tos(fd: BorrowedFd<'_>) -> io::Result<u8> {
+ let value: i32 = getsockopt(fd, c::IPPROTO_IP, c::IP_TOS)?;
+ Ok(value as u8)
+}
+
+#[inline]
+pub(crate) fn set_ip_recvtos(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn ip_recvtos(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_recvtclass(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn ipv6_recvtclass(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_ip_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn ip_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_ipv6_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn ipv6_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn ip_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV4> {
+ let level = c::IPPROTO_IP;
+ let optname = c::SO_ORIGINAL_DST;
+ let mut addr = SocketAddrBuf::new();
+
+ getsockopt_raw(fd, level, optname, &mut addr.storage, &mut addr.len)?;
+
+ Ok(unsafe { addr.into_any() }.try_into().unwrap())
+}
+
+#[inline]
+pub(crate) fn ipv6_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV6> {
+ let level = c::IPPROTO_IPV6;
+ let optname = c::IP6T_SO_ORIGINAL_DST;
+ let mut addr = SocketAddrBuf::new();
+
+ getsockopt_raw(fd, level, optname, &mut addr.storage, &mut addr.len)?;
+
+ Ok(unsafe { addr.into_any() }.try_into().unwrap())
+}
+
+#[inline]
+pub(crate) fn set_ipv6_tclass(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS, value)
+}
+
+#[inline]
+pub(crate) fn ipv6_tclass(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS)
+}
+
+#[inline]
+pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY, from_bool(nodelay))
+}
+
+#[inline]
+pub(crate) fn tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT, count)
+}
+
+#[inline]
+pub(crate) fn tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT)
+}
+
+#[inline]
+pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
+ let secs: c::c_uint = duration_to_secs(duration)?;
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPIDLE, secs)
+}
+
+#[inline]
+pub(crate) fn tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> {
+ let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPIDLE)?;
+ Ok(Duration::from_secs(secs.into()))
+}
+
+#[inline]
+pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
+ let secs: c::c_uint = duration_to_secs(duration)?;
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL, secs)
+}
+
+#[inline]
+pub(crate) fn tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> {
+ let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL)?;
+ Ok(Duration::from_secs(secs.into()))
+}
+
+#[inline]
+pub(crate) fn set_tcp_user_timeout(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT, value)
+}
+
+#[inline]
+pub(crate) fn tcp_user_timeout(fd: BorrowedFd<'_>) -> io::Result<u32> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT)
+}
+
+#[inline]
+pub(crate) fn set_tcp_quickack(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn tcp_quickack(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_tcp_congestion(fd: BorrowedFd<'_>, value: &str) -> io::Result<()> {
+ let level = c::IPPROTO_TCP;
+ let optname = c::TCP_CONGESTION;
+ let optlen = value.len().try_into().unwrap();
+ setsockopt_raw(fd, level, optname, value.as_ptr(), optlen)
+}
+
+#[cfg(feature = "alloc")]
+#[inline]
+pub(crate) fn tcp_congestion(fd: BorrowedFd<'_>) -> io::Result<String> {
+ const OPTLEN: c::socklen_t = 16;
+
+ let level = c::IPPROTO_TCP;
+ let optname = c::TCP_CONGESTION;
+ let mut value = MaybeUninit::<[MaybeUninit<u8>; OPTLEN as usize]>::uninit();
+ let mut optlen = OPTLEN;
+ getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?;
+ unsafe {
+ let value = value.assume_init();
+ let slice: &[u8] = core::mem::transmute(&value[..optlen as usize]);
+ assert!(slice.contains(&b'\0'));
+ Ok(
+ core::str::from_utf8(CStr::from_ptr(slice.as_ptr().cast()).to_bytes())
+ .unwrap()
+ .to_owned(),
+ )
+ }
+}
+
+#[inline]
+pub(crate) fn set_tcp_thin_linear_timeouts(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(
+ fd,
+ c::IPPROTO_TCP,
+ c::TCP_THIN_LINEAR_TIMEOUTS,
+ from_bool(value),
+ )
+}
+
+#[inline]
+pub(crate) fn tcp_thin_linear_timeouts(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_THIN_LINEAR_TIMEOUTS).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn set_tcp_cork(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
+ setsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK, from_bool(value))
+}
+
+#[inline]
+pub(crate) fn tcp_cork(fd: BorrowedFd<'_>) -> io::Result<bool> {
+ getsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK).map(to_bool)
+}
+
+#[inline]
+pub(crate) fn socket_peercred(fd: BorrowedFd<'_>) -> io::Result<UCred> {
+ getsockopt(fd, c::SOL_SOCKET, linux_raw_sys::net::SO_PEERCRED)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_umem_reg(fd: BorrowedFd<'_>, value: XdpUmemReg) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_REG, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_umem_fill_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_FILL_RING, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_umem_completion_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_COMPLETION_RING, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_tx_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_TX_RING, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn set_xdp_rx_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
+ setsockopt(fd, c::SOL_XDP, c::XDP_RX_RING, value)
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn xdp_mmap_offsets(fd: BorrowedFd<'_>) -> io::Result<XdpMmapOffsets> {
+ // The kernel will write `xdp_mmap_offsets` or `xdp_mmap_offsets_v1` to the
+ // supplied pointer, depending on the kernel version. Both structs only
+ // contain u64 values. By using the larger of both as the parameter, we can
+ // shuffle the values to the non-v1 version returned by
+ // `get_xdp_mmap_offsets` while keeping the return type unaffected by the
+ // kernel version. This works because C will layout all struct members one
+ // after the other.
+
+ let mut optlen = size_of::<xdp_mmap_offsets>().try_into().unwrap();
+ debug_assert!(
+ optlen as usize >= size_of::<c::c_int>(),
+ "Socket APIs don't ever use `bool` directly"
+ );
+ let mut value = MaybeUninit::<xdp_mmap_offsets>::zeroed();
+ getsockopt_raw(fd, c::SOL_XDP, c::XDP_MMAP_OFFSETS, &mut value, &mut optlen)?;
+
+ if optlen as usize == size_of::<c::xdp_mmap_offsets_v1>() {
+ // SAFETY: All members of xdp_mmap_offsets are `u64` and thus are
+ // correctly initialized by `MaybeUninit::<xdp_statistics>::zeroed()`.
+ let xpd_mmap_offsets = unsafe { value.assume_init() };
+ Ok(XdpMmapOffsets {
+ rx: XdpRingOffset {
+ producer: xpd_mmap_offsets.rx.producer,
+ consumer: xpd_mmap_offsets.rx.consumer,
+ desc: xpd_mmap_offsets.rx.desc,
+ flags: None,
+ },
+ tx: XdpRingOffset {
+ producer: xpd_mmap_offsets.rx.flags,
+ consumer: xpd_mmap_offsets.tx.producer,
+ desc: xpd_mmap_offsets.tx.consumer,
+ flags: None,
+ },
+ fr: XdpRingOffset {
+ producer: xpd_mmap_offsets.tx.desc,
+ consumer: xpd_mmap_offsets.tx.flags,
+ desc: xpd_mmap_offsets.fr.producer,
+ flags: None,
+ },
+ cr: XdpRingOffset {
+ producer: xpd_mmap_offsets.fr.consumer,
+ consumer: xpd_mmap_offsets.fr.desc,
+ desc: xpd_mmap_offsets.fr.flags,
+ flags: None,
+ },
+ })
+ } else {
+ assert_eq!(
+ optlen as usize,
+ size_of::<xdp_mmap_offsets>(),
+ "unexpected getsockopt size"
+ );
+ // SAFETY: All members of xdp_mmap_offsets are `u64` and thus are
+ // correctly initialized by `MaybeUninit::<xdp_statistics>::zeroed()`.
+ let xpd_mmap_offsets = unsafe { value.assume_init() };
+ Ok(XdpMmapOffsets {
+ rx: XdpRingOffset {
+ producer: xpd_mmap_offsets.rx.producer,
+ consumer: xpd_mmap_offsets.rx.consumer,
+ desc: xpd_mmap_offsets.rx.desc,
+ flags: Some(xpd_mmap_offsets.rx.flags),
+ },
+ tx: XdpRingOffset {
+ producer: xpd_mmap_offsets.tx.producer,
+ consumer: xpd_mmap_offsets.tx.consumer,
+ desc: xpd_mmap_offsets.tx.desc,
+ flags: Some(xpd_mmap_offsets.tx.flags),
+ },
+ fr: XdpRingOffset {
+ producer: xpd_mmap_offsets.fr.producer,
+ consumer: xpd_mmap_offsets.fr.consumer,
+ desc: xpd_mmap_offsets.fr.desc,
+ flags: Some(xpd_mmap_offsets.fr.flags),
+ },
+ cr: XdpRingOffset {
+ producer: xpd_mmap_offsets.cr.producer,
+ consumer: xpd_mmap_offsets.cr.consumer,
+ desc: xpd_mmap_offsets.cr.desc,
+ flags: Some(xpd_mmap_offsets.cr.flags),
+ },
+ })
+ }
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn xdp_statistics(fd: BorrowedFd<'_>) -> io::Result<XdpStatistics> {
+ let mut optlen = size_of::<xdp_statistics>().try_into().unwrap();
+ debug_assert!(
+ optlen as usize >= size_of::<c::c_int>(),
+ "Socket APIs don't ever use `bool` directly"
+ );
+ let mut value = MaybeUninit::<xdp_statistics>::zeroed();
+ getsockopt_raw(fd, c::SOL_XDP, c::XDP_STATISTICS, &mut value, &mut optlen)?;
+
+ if optlen as usize == size_of::<xdp_statistics_v1>() {
+ // SAFETY: All members of xdp_statistics are `u64` and thus are
+ // correctly initialized by `MaybeUninit::<xdp_statistics>::zeroed()`.
+ let xdp_statistics = unsafe { value.assume_init() };
+ Ok(XdpStatistics {
+ rx_dropped: xdp_statistics.rx_dropped,
+ rx_invalid_descs: xdp_statistics.rx_dropped,
+ tx_invalid_descs: xdp_statistics.rx_dropped,
+ rx_ring_full: None,
+ rx_fill_ring_empty_descs: None,
+ tx_ring_empty_descs: None,
+ })
+ } else {
+ assert_eq!(
+ optlen as usize,
+ size_of::<xdp_statistics>(),
+ "unexpected getsockopt size"
+ );
+ // SAFETY: All members of xdp_statistics are `u64` and thus are
+ // correctly initialized by `MaybeUninit::<xdp_statistics>::zeroed()`.
+ let xdp_statistics = unsafe { value.assume_init() };
+ Ok(XdpStatistics {
+ rx_dropped: xdp_statistics.rx_dropped,
+ rx_invalid_descs: xdp_statistics.rx_invalid_descs,
+ tx_invalid_descs: xdp_statistics.tx_invalid_descs,
+ rx_ring_full: Some(xdp_statistics.rx_ring_full),
+ rx_fill_ring_empty_descs: Some(xdp_statistics.rx_fill_ring_empty_descs),
+ tx_ring_empty_descs: Some(xdp_statistics.tx_ring_empty_descs),
+ })
+ }
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn xdp_options(fd: BorrowedFd<'_>) -> io::Result<XdpOptionsFlags> {
+ getsockopt(fd, c::SOL_XDP, c::XDP_OPTIONS)
+}
+
+#[inline]
+fn from_in_addr(in_addr: c::in_addr) -> Ipv4Addr {
+ Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
+}
+
+#[inline]
+fn to_ip_mreq(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
+ c::ip_mreq {
+ imr_multiaddr: to_imr_addr(multiaddr),
+ imr_interface: to_imr_addr(interface),
+ }
+}
+
+#[inline]
+fn to_ip_mreqn(multiaddr: &Ipv4Addr, address: &Ipv4Addr, ifindex: i32) -> c::ip_mreqn {
+ c::ip_mreqn {
+ imr_multiaddr: to_imr_addr(multiaddr),
+ imr_address: to_imr_addr(address),
+ imr_ifindex: ifindex,
+ }
+}
+
+#[inline]
+fn to_imr_source(
+ multiaddr: &Ipv4Addr,
+ interface: &Ipv4Addr,
+ sourceaddr: &Ipv4Addr,
+) -> c::ip_mreq_source {
+ c::ip_mreq_source {
+ imr_multiaddr: to_imr_addr(multiaddr).s_addr,
+ imr_interface: to_imr_addr(interface).s_addr,
+ imr_sourceaddr: to_imr_addr(sourceaddr).s_addr,
+ }
+}
+
+#[inline]
+fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr {
+ c::in_addr {
+ s_addr: u32::from_ne_bytes(addr.octets()),
+ }
+}
+
+#[inline]
+fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq {
+ c::ipv6_mreq {
+ ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr),
+ ipv6mr_ifindex: to_ipv6mr_interface(interface),
+ }
+}
+
+#[inline]
+fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr {
+ c::in6_addr {
+ in6_u: linux_raw_sys::net::in6_addr__bindgen_ty_1 {
+ u6_addr8: multiaddr.octets(),
+ },
+ }
+}
+
+#[inline]
+fn to_ipv6mr_interface(interface: u32) -> c::c_int {
+ interface as c::c_int
+}
+
+#[inline]
+fn from_bool(value: bool) -> c::c_uint {
+ c::c_uint::from(value)
+}
+
+#[inline]
+fn to_bool(value: c::c_uint) -> bool {
+ value != 0
+}
+
+/// Convert to seconds, rounding up if necessary.
+#[inline]
+fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> {
+ let mut secs = duration.as_secs();
+ if duration.subsec_nanos() != 0 {
+ secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?;
+ }
+ T::try_from(secs).map_err(|_e| io::Errno::INVAL)
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/syscalls.rs b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs
new file mode 100644
index 00000000..488e08f0
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs
@@ -0,0 +1,731 @@
+//! linux_raw syscalls supporting `rustix::net`.
+//!
+//! # Safety
+//!
+//! See the `rustix::backend` module documentation for details.
+#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+
+use super::msghdr::{noaddr_msghdr, with_msghdr, with_recv_msghdr};
+use super::read_sockaddr::initialize_family_to_unspec;
+use super::send_recv::{RecvFlags, ReturnFlags, SendFlags};
+use crate::backend::c;
+#[cfg(target_os = "linux")]
+use crate::backend::conv::slice_mut;
+use crate::backend::conv::{
+ by_mut, by_ref, c_int, c_uint, pass_usize, ret, ret_owned_fd, ret_usize, size_of, slice,
+ socklen_t, zero,
+};
+use crate::backend::reg::raw_arg;
+use crate::fd::{BorrowedFd, OwnedFd};
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::net::addr::SocketAddrArg;
+#[cfg(target_os = "linux")]
+use crate::net::MMsgHdr;
+use crate::net::{
+ AddressFamily, Protocol, RecvAncillaryBuffer, RecvMsg, SendAncillaryBuffer, Shutdown,
+ SocketAddrAny, SocketAddrBuf, SocketFlags, SocketType,
+};
+use core::mem::MaybeUninit;
+#[cfg(target_arch = "x86")]
+use {
+ crate::backend::conv::{slice_just_addr, x86_sys},
+ crate::backend::reg::{ArgReg, SocketArg},
+ linux_raw_sys::net::{
+ SYS_ACCEPT, SYS_ACCEPT4, SYS_BIND, SYS_CONNECT, SYS_GETPEERNAME, SYS_GETSOCKNAME,
+ SYS_LISTEN, SYS_RECV, SYS_RECVFROM, SYS_RECVMSG, SYS_SEND, SYS_SENDMMSG, SYS_SENDMSG,
+ SYS_SENDTO, SYS_SHUTDOWN, SYS_SOCKET, SYS_SOCKETPAIR,
+ },
+};
+
+#[inline]
+pub(crate) fn socket(
+ family: AddressFamily,
+ type_: SocketType,
+ protocol: Option<Protocol>,
+) -> io::Result<OwnedFd> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(__NR_socket, family, type_, protocol))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_SOCKET),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ family.into(),
+ type_.into(),
+ protocol.into(),
+ ])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn socket_with(
+ family: AddressFamily,
+ type_: SocketType,
+ flags: SocketFlags,
+ protocol: Option<Protocol>,
+) -> io::Result<OwnedFd> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_socket,
+ family,
+ (type_, flags),
+ protocol
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret_owned_fd(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_SOCKET),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ family.into(),
+ (type_, flags).into(),
+ protocol.into(),
+ ])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn socketpair(
+ family: AddressFamily,
+ type_: SocketType,
+ flags: SocketFlags,
+ protocol: Option<Protocol>,
+) -> io::Result<(OwnedFd, OwnedFd)> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit();
+ ret(syscall!(
+ __NR_socketpair,
+ family,
+ (type_, flags),
+ protocol,
+ &mut result
+ ))?;
+ let [fd0, fd1] = result.assume_init();
+ Ok((fd0, fd1))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit();
+ ret(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_SOCKETPAIR),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ family.into(),
+ (type_, flags).into(),
+ protocol.into(),
+ (&mut result).into(),
+ ])
+ ))?;
+ let [fd0, fd1] = result.assume_init();
+ Ok((fd0, fd1))
+ }
+}
+
+#[inline]
+pub(crate) fn accept(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> {
+ #[cfg(not(any(target_arch = "x86", target_arch = "s390x")))]
+ unsafe {
+ let fd = ret_owned_fd(syscall_readonly!(__NR_accept, fd, zero(), zero()))?;
+ Ok(fd)
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let fd = ret_owned_fd(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_ACCEPT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[fd.into(), zero(), zero()])
+ ))?;
+ Ok(fd)
+ }
+ #[cfg(target_arch = "s390x")]
+ {
+ // accept is not available on s390x
+ accept_with(fd, SocketFlags::empty())
+ }
+}
+
+#[inline]
+pub(crate) fn accept_with(fd: BorrowedFd<'_>, flags: SocketFlags) -> io::Result<OwnedFd> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ let fd = ret_owned_fd(syscall_readonly!(__NR_accept4, fd, zero(), zero(), flags))?;
+ Ok(fd)
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let fd = ret_owned_fd(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_ACCEPT4),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[fd.into(), zero(), zero(), flags.into()])
+ ))?;
+ Ok(fd)
+ }
+}
+
+#[inline]
+pub(crate) fn acceptfrom(fd: BorrowedFd<'_>) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> {
+ #[cfg(not(any(target_arch = "x86", target_arch = "s390x")))]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ let fd = ret_owned_fd(syscall!(
+ __NR_accept,
+ fd,
+ &mut addr.storage,
+ by_mut(&mut addr.len)
+ ))?;
+ Ok((fd, addr.into_any_option()))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ let fd = ret_owned_fd(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_ACCEPT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ ])
+ ))?;
+ Ok((fd, addr.into_any_option()))
+ }
+ #[cfg(target_arch = "s390x")]
+ {
+ // accept is not available on s390x
+ acceptfrom_with(fd, SocketFlags::empty())
+ }
+}
+
+#[inline]
+pub(crate) fn acceptfrom_with(
+ fd: BorrowedFd<'_>,
+ flags: SocketFlags,
+) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ let fd = ret_owned_fd(syscall!(
+ __NR_accept4,
+ fd,
+ &mut addr.storage,
+ by_mut(&mut addr.len),
+ flags
+ ))?;
+ Ok((fd, addr.into_any_option()))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ let fd = ret_owned_fd(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_ACCEPT4),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ flags.into(),
+ ])
+ ))?;
+ Ok((fd, addr.into_any_option()))
+ }
+}
+
+#[inline]
+pub(crate) fn recvmsg(
+ sockfd: BorrowedFd<'_>,
+ iov: &mut [IoSliceMut<'_>],
+ control: &mut RecvAncillaryBuffer<'_>,
+ msg_flags: RecvFlags,
+) -> io::Result<RecvMsg> {
+ let mut addr = SocketAddrBuf::new();
+
+ // SAFETY: This passes the `msghdr` reference to the OS which reads the
+ // buffers only within the designated bounds.
+ let (bytes, flags) = unsafe {
+ with_recv_msghdr(&mut addr, iov, control, |msghdr| {
+ #[cfg(not(target_arch = "x86"))]
+ let result = ret_usize(syscall!(__NR_recvmsg, sockfd, by_mut(msghdr), msg_flags));
+
+ #[cfg(target_arch = "x86")]
+ let result = ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_RECVMSG),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ sockfd.into(),
+ by_mut(msghdr),
+ msg_flags.into(),
+ ])
+ ));
+
+ result.map(|bytes| (bytes, msghdr.msg_flags))
+ })?
+ };
+
+ // Get the address of the sender, if any.
+ Ok(RecvMsg {
+ bytes,
+ address: unsafe { addr.into_any_option() },
+ flags: ReturnFlags::from_bits_retain(flags),
+ })
+}
+
+#[inline]
+pub(crate) fn sendmsg(
+ sockfd: BorrowedFd<'_>,
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+ msg_flags: SendFlags,
+) -> io::Result<usize> {
+ let msghdr = noaddr_msghdr(iov, control);
+
+ #[cfg(not(target_arch = "x86"))]
+ let result = unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) };
+
+ #[cfg(target_arch = "x86")]
+ let result = unsafe {
+ ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_SENDMSG),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ sockfd.into(),
+ by_ref(&msghdr),
+ msg_flags.into()
+ ])
+ ))
+ };
+
+ result
+}
+
+#[inline]
+pub(crate) fn sendmsg_addr(
+ sockfd: BorrowedFd<'_>,
+ addr: &impl SocketAddrArg,
+ iov: &[IoSlice<'_>],
+ control: &mut SendAncillaryBuffer<'_, '_, '_>,
+ msg_flags: SendFlags,
+) -> io::Result<usize> {
+ // SAFETY: This passes the `msghdr` reference to the OS which reads the
+ // buffers only within the designated bounds.
+ unsafe {
+ with_msghdr(addr, iov, control, |msghdr| {
+ #[cfg(not(target_arch = "x86"))]
+ let result = ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(msghdr), msg_flags));
+
+ #[cfg(target_arch = "x86")]
+ let result = ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_SENDMSG),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ sockfd.into(),
+ by_ref(msghdr),
+ msg_flags.into(),
+ ])
+ ));
+
+ result
+ })
+ }
+}
+
+#[cfg(target_os = "linux")]
+#[inline]
+pub(crate) fn sendmmsg(
+ sockfd: BorrowedFd<'_>,
+ msgs: &mut [MMsgHdr<'_>],
+ flags: SendFlags,
+) -> io::Result<usize> {
+ let (msgs, len) = slice_mut(msgs);
+
+ #[cfg(not(target_arch = "x86"))]
+ let result = unsafe { ret_usize(syscall!(__NR_sendmmsg, sockfd, msgs, len, flags)) };
+
+ #[cfg(target_arch = "x86")]
+ let result = unsafe {
+ ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_SENDMMSG),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[sockfd.into(), msgs, len, flags.into()])
+ ))
+ };
+
+ result
+}
+
+#[inline]
+pub(crate) fn shutdown(fd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_shutdown,
+ fd,
+ c_uint(how as c::c_uint)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_SHUTDOWN),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[fd.into(), c_uint(how as c::c_uint)])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Result<usize> {
+ let (buf_addr, buf_len) = slice(buf);
+
+ #[cfg(not(any(
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "x86",
+ target_arch = "x86_64",
+ )))]
+ unsafe {
+ ret_usize(syscall_readonly!(__NR_send, fd, buf_addr, buf_len, flags))
+ }
+ #[cfg(any(
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ ))]
+ unsafe {
+ ret_usize(syscall_readonly!(
+ __NR_sendto,
+ fd,
+ buf_addr,
+ buf_len,
+ flags,
+ zero(),
+ zero()
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret_usize(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_SEND),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ buf_addr,
+ buf_len,
+ flags.into()
+ ])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn sendto(
+ fd: BorrowedFd<'_>,
+ buf: &[u8],
+ flags: SendFlags,
+ addr: &impl SocketAddrArg,
+) -> io::Result<usize> {
+ let (buf_addr, buf_len) = slice(buf);
+
+ // SAFETY: This passes the `addr_ptr` reference to the OS which reads the
+ // buffers only within the `addr_len` bound.
+ unsafe {
+ addr.with_sockaddr(|addr_ptr, addr_len| {
+ #[cfg(not(target_arch = "x86"))]
+ {
+ ret_usize(syscall_readonly!(
+ __NR_sendto,
+ fd,
+ buf_addr,
+ buf_len,
+ flags,
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ {
+ ret_usize(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_SENDTO),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ buf_addr,
+ buf_len,
+ flags.into(),
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ])
+ ))
+ }
+ })
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn recv(
+ fd: BorrowedFd<'_>,
+ buf: (*mut u8, usize),
+ flags: RecvFlags,
+) -> io::Result<usize> {
+ #[cfg(not(any(
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "x86",
+ target_arch = "x86_64",
+ )))]
+ {
+ ret_usize(syscall!(__NR_recv, fd, buf.0, pass_usize(buf.1), flags))
+ }
+ #[cfg(any(
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv64",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ ))]
+ {
+ ret_usize(syscall!(
+ __NR_recvfrom,
+ fd,
+ buf.0,
+ pass_usize(buf.1),
+ flags,
+ zero(),
+ zero()
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ {
+ ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_RECV),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ buf.0.into(),
+ pass_usize(buf.1),
+ flags.into(),
+ ])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn recvfrom(
+ fd: BorrowedFd<'_>,
+ buf: (*mut u8, usize),
+ flags: RecvFlags,
+) -> io::Result<(usize, Option<SocketAddrAny>)> {
+ let mut addr = SocketAddrBuf::new();
+
+ // `recvfrom` does not write to the storage if the socket is
+ // connection-oriented sockets, so we initialize the family field to
+ // `AF_UNSPEC` so that we can detect this case.
+ initialize_family_to_unspec(addr.storage.as_mut_ptr().cast::<c::sockaddr>());
+
+ #[cfg(not(target_arch = "x86"))]
+ let nread = ret_usize(syscall!(
+ __NR_recvfrom,
+ fd,
+ buf.0,
+ pass_usize(buf.1),
+ flags,
+ &mut addr.storage,
+ by_mut(&mut addr.len)
+ ))?;
+ #[cfg(target_arch = "x86")]
+ let nread = ret_usize(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_RECVFROM),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ buf.0.into(),
+ pass_usize(buf.1),
+ flags.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ ])
+ ))?;
+
+ Ok((nread, addr.into_any_option()))
+}
+
+#[inline]
+pub(crate) fn getpeername(fd: BorrowedFd<'_>) -> io::Result<Option<SocketAddrAny>> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ ret(syscall!(
+ __NR_getpeername,
+ fd,
+ &mut addr.storage,
+ by_mut(&mut addr.len)
+ ))?;
+ Ok(addr.into_any_option())
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ ret(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_GETPEERNAME),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ ])
+ ))?;
+ Ok(addr.into_any_option())
+ }
+}
+
+#[inline]
+pub(crate) fn getsockname(fd: BorrowedFd<'_>) -> io::Result<SocketAddrAny> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ ret(syscall!(
+ __NR_getsockname,
+ fd,
+ &mut addr.storage,
+ by_mut(&mut addr.len)
+ ))?;
+ Ok(addr.into_any())
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ let mut addr = SocketAddrBuf::new();
+ ret(syscall!(
+ __NR_socketcall,
+ x86_sys(SYS_GETSOCKNAME),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ (&mut addr.storage).into(),
+ by_mut(&mut addr.len),
+ ])
+ ))?;
+ Ok(addr.into_any())
+ }
+}
+
+#[inline]
+pub(crate) fn bind(fd: BorrowedFd<'_>, addr: &impl SocketAddrArg) -> io::Result<()> {
+ // SAFETY: This passes the `addr_ptr` reference to the OS which reads the
+ // buffers only within the `addr_len` bound.
+ unsafe {
+ addr.with_sockaddr(|addr_ptr, addr_len| {
+ #[cfg(not(target_arch = "x86"))]
+ {
+ ret(syscall_readonly!(
+ __NR_bind,
+ fd,
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_BIND),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ])
+ ))
+ }
+ })
+ }
+}
+
+#[inline]
+pub(crate) fn connect(fd: BorrowedFd<'_>, addr: &impl SocketAddrArg) -> io::Result<()> {
+ // SAFETY: This passes the `addr_ptr` reference to the OS which reads the
+ // buffers only within the `addr_len` bound.
+ unsafe {
+ addr.with_sockaddr(|addr_ptr, addr_len| {
+ #[cfg(not(target_arch = "x86"))]
+ {
+ ret(syscall_readonly!(
+ __NR_connect,
+ fd,
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_CONNECT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ raw_arg(addr_ptr as *mut _),
+ socklen_t(addr_len)
+ ])
+ ))
+ }
+ })
+ }
+}
+
+#[inline]
+pub(crate) fn connect_unspec(fd: BorrowedFd<'_>) -> io::Result<()> {
+ debug_assert_eq!(c::AF_UNSPEC, 0);
+ let addr = MaybeUninit::<c::sockaddr_storage>::zeroed();
+
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_connect,
+ fd,
+ by_ref(&addr),
+ size_of::<c::sockaddr_storage, _>()
+ ))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_CONNECT),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
+ fd.into(),
+ by_ref(&addr),
+ size_of::<c::sockaddr_storage, _>(),
+ ])
+ ))
+ }
+}
+
+#[inline]
+pub(crate) fn listen(fd: BorrowedFd<'_>, backlog: c::c_int) -> io::Result<()> {
+ #[cfg(not(target_arch = "x86"))]
+ unsafe {
+ ret(syscall_readonly!(__NR_listen, fd, c_int(backlog)))
+ }
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ ret(syscall_readonly!(
+ __NR_socketcall,
+ x86_sys(SYS_LISTEN),
+ slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[fd.into(), c_int(backlog)])
+ ))
+ }
+}
diff --git a/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs b/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs
new file mode 100644
index 00000000..3b348221
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs
@@ -0,0 +1,31 @@
+//! The BSD sockets API requires us to read the `sa_family` field before we can
+//! interpret the rest of a `sockaddr` produced by the kernel.
+#![allow(unsafe_code)]
+
+use crate::backend::c;
+use crate::net::{SocketAddrV4, SocketAddrV6};
+
+pub(crate) fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in {
+ c::sockaddr_in {
+ sin_family: c::AF_INET as _,
+ sin_port: u16::to_be(v4.port()),
+ sin_addr: c::in_addr {
+ s_addr: u32::from_ne_bytes(v4.ip().octets()),
+ },
+ __pad: [0_u8; 8],
+ }
+}
+
+pub(crate) fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 {
+ c::sockaddr_in6 {
+ sin6_family: c::AF_INET6 as _,
+ sin6_port: u16::to_be(v6.port()),
+ sin6_flowinfo: u32::to_be(v6.flowinfo()),
+ sin6_addr: c::in6_addr {
+ in6_u: linux_raw_sys::net::in6_addr__bindgen_ty_1 {
+ u6_addr8: v6.ip().octets(),
+ },
+ },
+ sin6_scope_id: v6.scope_id(),
+ }
+}