rustix/net/
addr.rs

1//! Types for implementers of socket address types or code that is generic over
2//! address types.
3//!
4//! The concrete address types and [`SocketAddrAny`] are in
5//! [the parent module][`super`].
6
7#![allow(unsafe_code)]
8use core::mem::{size_of, MaybeUninit};
9use core::ptr;
10
11use crate::backend::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6};
12use crate::utils::as_ptr;
13
14use super::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6};
15
16pub use crate::backend::net::addr::SocketAddrStorage;
17
18#[cfg(unix)]
19use super::SocketAddrUnix;
20
21/// Opaque type equivalent to `sockaddr` in C.
22///
23/// This is always used behind a raw pointer that is cast from a pointer to a
24/// `sockaddr`-compatible C type, and then cast back to a `sockaddr` pointer to
25/// be passed to a system call.
26#[repr(C)]
27pub struct SocketAddrOpaque {
28    _data: [u8; 0],
29}
30
31/// A type for the length of a socket address.
32///
33/// This type will always be big enough to hold any socket address, but never
34/// bigger than `usize`.
35#[doc(alias = "socklen_t")]
36pub type SocketAddrLen = u32;
37
38/// A trait abstracting over the types that can be passed as a `sockaddr`.
39///
40/// # Safety
41///
42/// Implementers of this trait must ensure that `with_sockaddr` calls `f` with
43/// a pointer that is readable for the passed length, and points to data that
44/// is a valid socket address for the system calls that accept `sockaddr` as a
45/// const pointer.
46pub unsafe trait SocketAddrArg {
47    /// Call a closure with the pointer and length to the corresponding C type.
48    ///
49    /// The memory pointed to by the pointer of size length is guaranteed to be
50    /// valid only for the duration of the call.
51    ///
52    /// The API uses a closure so that:
53    ///  - The libc types are not exposed in the rustix API.
54    ///  - Types like `SocketAddrUnix` that contain their corresponding C type
55    ///    can pass it directly without a copy.
56    ///  - Other socket types can construct their C-compatible struct on the
57    ///    stack and call the closure with a pointer to it.
58    ///
59    /// # Safety
60    ///
61    /// For `f` to use its pointer argument, it'll contain an `unsafe` block.
62    /// The caller of `with_sockaddr` here is responsible for ensuring that the
63    /// safety condition for that `unsafe` block is satisfied by the guarantee
64    /// that `with_sockaddr` here provides.
65    unsafe fn with_sockaddr<R>(
66        &self,
67        f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
68    ) -> R;
69
70    /// Convert to `SocketAddrAny`.
71    fn as_any(&self) -> SocketAddrAny {
72        let mut storage = MaybeUninit::<SocketAddrStorage>::uninit();
73        // SAFETY: We've allocated `storage` here, we're writing to it, and
74        // we're using the number of bytes written.
75        unsafe {
76            let len = self.write_sockaddr(storage.as_mut_ptr());
77            SocketAddrAny::new(storage, len)
78        }
79    }
80
81    /// Encode an address into a `SocketAddrStorage`.
82    ///
83    /// Returns the number of bytes that were written.
84    ///
85    /// For a safe interface to this functionality, use [`as_any`].
86    ///
87    /// [`as_any`]: Self::as_any
88    ///
89    /// # Safety
90    ///
91    /// `storage` must be valid to write up to `size_of<SocketAddrStorage>()`
92    /// bytes to.
93    unsafe fn write_sockaddr(&self, storage: *mut SocketAddrStorage) -> SocketAddrLen {
94        // The closure dereferences exactly `len` bytes at `ptr`.
95        self.with_sockaddr(|ptr, len| {
96            ptr::copy_nonoverlapping(ptr.cast::<u8>(), storage.cast::<u8>(), len as usize);
97            len
98        })
99    }
100}
101
102/// Helper for implementing `SocketAddrArg::with_sockaddr`.
103///
104/// # Safety
105///
106/// This calls `f` with a pointer to an object it has a reference to, with the
107/// and the length of that object, so they'll be valid for the duration of the
108/// call.
109pub(crate) unsafe fn call_with_sockaddr<A, R>(
110    addr: &A,
111    f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
112) -> R {
113    let ptr = as_ptr(addr).cast();
114    let len = size_of::<A>() as SocketAddrLen;
115    f(ptr, len)
116}
117
118// SAFETY: This just forwards to the inner `SocketAddrArg` implementations.
119unsafe impl SocketAddrArg for SocketAddr {
120    unsafe fn with_sockaddr<R>(
121        &self,
122        f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
123    ) -> R {
124        match self {
125            Self::V4(v4) => v4.with_sockaddr(f),
126            Self::V6(v6) => v6.with_sockaddr(f),
127        }
128    }
129}
130
131// SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles
132// calling `f` with the needed preconditions.
133unsafe impl SocketAddrArg for SocketAddrV4 {
134    unsafe fn with_sockaddr<R>(
135        &self,
136        f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
137    ) -> R {
138        call_with_sockaddr(&encode_sockaddr_v4(self), f)
139    }
140}
141
142// SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles
143// calling `f` with the needed preconditions.
144unsafe impl SocketAddrArg for SocketAddrV6 {
145    unsafe fn with_sockaddr<R>(
146        &self,
147        f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
148    ) -> R {
149        call_with_sockaddr(&encode_sockaddr_v6(self), f)
150    }
151}
152
153#[cfg(unix)]
154// SAFETY: `with_sockaddr` calls `f` using `call_with_sockaddr`, which handles
155// calling `f` with the needed preconditions.
156unsafe impl SocketAddrArg for SocketAddrUnix {
157    unsafe fn with_sockaddr<R>(
158        &self,
159        f: impl FnOnce(*const SocketAddrOpaque, SocketAddrLen) -> R,
160    ) -> R {
161        f(as_ptr(&self.unix).cast(), self.addr_len())
162    }
163}
164
165#[cfg(test)]
166mod tests {
167    use super::*;
168    use crate::backend::c;
169
170    #[test]
171    fn test_layouts() {
172        assert_eq_size!(SocketAddrLen, c::socklen_t);
173
174        #[cfg(not(any(windows, target_os = "redox")))]
175        assert_eq!(
176            memoffset::span_of!(c::msghdr, msg_namelen).len(),
177            size_of::<SocketAddrLen>()
178        );
179
180        assert!(size_of::<SocketAddrLen>() <= size_of::<usize>());
181    }
182}