summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/net/addr.rs
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/addr.rs
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/rustix/src/net/addr.rs')
-rw-r--r--vendor/rustix/src/net/addr.rs182
1 files changed, 182 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>());
+ }
+}