//! Types for implementers of socket address types or code that is generic over //! address types. //! //! The concrete address types and [`SocketAddrAny`] are in //! [the parent module][`super`]. #![allow(unsafe_code)] use core::mem::{size_of, MaybeUninit}; use core::ptr; use crate::backend::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; use crate::utils::as_ptr; use super::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; pub use crate::backend::net::addr::SocketAddrStorage; #[cfg(unix)] use super::SocketAddrUnix; /// Opaque type equivalent to `sockaddr` in C. /// /// This is always used behind a raw pointer that is cast from a pointer to a /// `sockaddr`-compatible C type, and then cast back to a `sockaddr` pointer to /// be passed to a system call. #[repr(C)] pub struct SocketAddrOpaque { _data: [u8; 0], } /// A type for the length of a socket address. /// /// This type will always be big enough to hold any socket address, but never /// bigger than `usize`. #[doc(alias = "socklen_t")] pub type SocketAddrLen = u32; /// A trait abstracting over the types that can be passed as a `sockaddr`. /// /// # Safety /// /// Implementers of this trait must ensure that `with_sockaddr` calls `f` with /// a pointer that is readable for the passed length, and points to data that /// is a valid socket address for the system calls that accept `sockaddr` as a /// const pointer. pub unsafe trait SocketAddrArg { /// Call a closure with the pointer and length to the corresponding C type. /// /// The memory pointed to by the pointer of size length is guaranteed to be /// valid only for the duration of the call. /// /// The API uses a closure so that: /// - The libc types are not exposed in the rustix API. /// - Types like `SocketAddrUnix` that contain their corresponding C type /// can pass it directly without a copy. /// - Other socket types can construct their C-compatible struct on the /// stack and call the closure with a pointer to it. /// /// # Safety /// /// For `f` to use its pointer argument, it'll contain an `unsafe` block. /// The caller of `with_sockaddr` here is responsible for ensuring that the /// safety condition for that `unsafe` block is satisfied by the guarantee /// that `with_sockaddr` here provides. unsafe fn with_sockaddr( &self, f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, ) -> R; /// Convert to `SocketAddrAny`. fn as_any(&self) -> SocketAddrAny { let mut storage = MaybeUninit::::uninit(); // SAFETY: We've allocated `storage` here, we're writing to it, and // we're using the number of bytes written. unsafe { let len = self.write_sockaddr(storage.as_mut_ptr()); SocketAddrAny::new(storage, len) } } /// Encode an address into a `SocketAddrStorage`. /// /// Returns the number of bytes that were written. /// /// For a safe interface to this functionality, use [`as_any`]. /// /// [`as_any`]: Self::as_any /// /// # Safety /// /// `storage` must be valid to write up to `size_of()` /// bytes to. unsafe fn write_sockaddr(&self, storage: *mut SocketAddrStorage) -> SocketAddrLen { // The closure dereferences exactly `len` bytes at `ptr`. self.with_sockaddr(|ptr, len| { ptr::copy_nonoverlapping(ptr.cast::(), storage.cast::(), len as usize); len }) } } /// Helper for implementing `SocketAddrArg::with_sockaddr`. /// /// # Safety /// /// This calls `f` with a pointer to an object it has a reference to, with the /// and the length of that object, so they'll be valid for the duration of the /// call. pub(crate) unsafe fn call_with_sockaddr( addr: &A, f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, ) -> R { let ptr = as_ptr(addr).cast(); let len = size_of::() as SocketAddrLen; f(ptr, len) } // SAFETY: This just forwards to the inner `SocketAddrArg` implementations. unsafe impl SocketAddrArg for SocketAddr { unsafe fn with_sockaddr( &self, f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, ) -> R { match self { Self::V4(v4) => v4.with_sockaddr(f), Self::V6(v6) => v6.with_sockaddr(f), } } } // SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles // calling `f` with the needed preconditions. unsafe impl SocketAddrArg for SocketAddrV4 { unsafe fn with_sockaddr( &self, f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, ) -> R { call_with_sockaddr(&encode_sockaddr_v4(self), f) } } // SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles // calling `f` with the needed preconditions. unsafe impl SocketAddrArg for SocketAddrV6 { unsafe fn with_sockaddr( &self, f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, ) -> R { call_with_sockaddr(&encode_sockaddr_v6(self), f) } } #[cfg(unix)] // SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles // calling `f` with the needed preconditions. unsafe impl SocketAddrArg for SocketAddrUnix { unsafe fn with_sockaddr( &self, f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R, ) -> R { f(as_ptr(&self.unix).cast(), self.addr_len()) } } #[cfg(test)] mod tests { use super::*; use crate::backend::c; #[test] fn test_layouts() { assert_eq_size!(SocketAddrLen, c::socklen_t); #[cfg(not(any(windows, target_os = "redox")))] assert_eq!( memoffset::span_of!(c::msghdr, msg_namelen).len(), size_of::() ); assert!(size_of::() <= size_of::()); } }