socket2/
sockaddr.rs

1use std::hash::Hash;
2use std::mem::{self, size_of};
3use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
4use std::path::Path;
5use std::{fmt, io, ptr};
6
7#[cfg(windows)]
8use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
9
10use crate::sys::{c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, AF_INET, AF_INET6, AF_UNIX};
11use crate::Domain;
12
13/// The integer type used with `getsockname` on this platform.
14#[allow(non_camel_case_types)]
15pub type socklen_t = crate::sys::socklen_t;
16
17/// The integer type for the `ss_family` field on this platform.
18#[allow(non_camel_case_types)]
19pub type sa_family_t = crate::sys::sa_family_t;
20
21/// Rust version of the [`sockaddr_storage`] type.
22///
23/// This type is intended to be used with with direct calls to the `getsockname` syscall. See the
24/// documentation of [`SockAddr::new`] for examples.
25///
26/// This crate defines its own `sockaddr_storage` type to avoid semver concerns with upgrading
27/// `windows-sys`.
28#[repr(transparent)]
29pub struct SockAddrStorage {
30    storage: sockaddr_storage,
31}
32
33impl SockAddrStorage {
34    /// Construct a new storage containing all zeros.
35    #[inline]
36    pub fn zeroed() -> Self {
37        // SAFETY: All zeros is valid for this type.
38        unsafe { mem::zeroed() }
39    }
40
41    /// Returns the size of this storage.
42    #[inline]
43    pub fn size_of(&self) -> socklen_t {
44        size_of::<Self>() as socklen_t
45    }
46
47    /// View this type as another type.
48    ///
49    /// # Safety
50    ///
51    /// The type `T` must be one of the `sockaddr_*` types defined by this platform.
52    #[inline]
53    pub unsafe fn view_as<T>(&mut self) -> &mut T {
54        assert!(size_of::<T>() <= size_of::<Self>());
55        // SAFETY: This type is repr(transparent) over `sockaddr_storage` and `T` is one of the
56        // `sockaddr_*` types defined by this platform.
57        &mut *(self as *mut Self as *mut T)
58    }
59}
60
61impl std::fmt::Debug for SockAddrStorage {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        f.debug_struct("sockaddr_storage")
64            .field("ss_family", &self.storage.ss_family)
65            .finish_non_exhaustive()
66    }
67}
68
69/// The address of a socket.
70///
71/// `SockAddr`s may be constructed directly to and from the standard library
72/// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types.
73#[derive(Clone)]
74pub struct SockAddr {
75    storage: sockaddr_storage,
76    len: socklen_t,
77}
78
79#[allow(clippy::len_without_is_empty)]
80impl SockAddr {
81    /// Create a `SockAddr` from the underlying storage and its length.
82    ///
83    /// # Safety
84    ///
85    /// Caller must ensure that the address family and length match the type of
86    /// storage address. For example if `storage.ss_family` is set to `AF_INET`
87    /// the `storage` must be initialised as `sockaddr_in`, setting the content
88    /// and length appropriately.
89    ///
90    /// # Examples
91    ///
92    /// ```
93    /// # fn main() -> std::io::Result<()> {
94    /// # #[cfg(unix)] {
95    /// use std::io;
96    /// use std::os::fd::AsRawFd;
97    ///
98    /// use socket2::{SockAddr, SockAddrStorage, Socket, Domain, Type};
99    ///
100    /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
101    ///
102    /// // Initialise a `SocketAddr` by calling `getsockname(2)`.
103    /// let mut addr_storage = SockAddrStorage::zeroed();
104    /// let mut len = addr_storage.size_of();
105    ///
106    /// // The `getsockname(2)` system call will initialize `storage` for
107    /// // us, setting `len` to the correct length.
108    /// let res = unsafe {
109    ///     libc::getsockname(
110    ///         socket.as_raw_fd(),
111    ///         addr_storage.view_as(),
112    ///         &mut len,
113    ///     )
114    /// };
115    /// if res == -1 {
116    ///     return Err(io::Error::last_os_error());
117    /// }
118    ///
119    /// let address = unsafe { SockAddr::new(addr_storage, len) };
120    /// # drop(address);
121    /// # }
122    /// # Ok(())
123    /// # }
124    /// ```
125    pub const unsafe fn new(storage: SockAddrStorage, len: socklen_t) -> SockAddr {
126        SockAddr {
127            storage: storage.storage,
128            len: len as socklen_t,
129        }
130    }
131
132    /// Initialise a `SockAddr` by calling the function `init`.
133    ///
134    /// The type of the address storage and length passed to the function `init`
135    /// is OS/architecture specific.
136    ///
137    /// The address is zeroed before `init` is called and is thus valid to
138    /// dereference and read from. The length initialised to the maximum length
139    /// of the storage.
140    ///
141    /// # Safety
142    ///
143    /// Caller must ensure that the address family and length match the type of
144    /// storage address. For example if `storage.ss_family` is set to `AF_INET`
145    /// the `storage` must be initialised as `sockaddr_in`, setting the content
146    /// and length appropriately.
147    ///
148    /// # Examples
149    ///
150    /// ```
151    /// # fn main() -> std::io::Result<()> {
152    /// # #[cfg(unix)] {
153    /// use std::io;
154    /// use std::os::fd::AsRawFd;
155    ///
156    /// use socket2::{SockAddr, Socket, Domain, Type};
157    ///
158    /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
159    ///
160    /// // Initialise a `SocketAddr` by calling `getsockname(2)`.
161    /// let (_, address) = unsafe {
162    ///     SockAddr::try_init(|addr_storage, len| {
163    ///         // The `getsockname(2)` system call will initialize `storage` for
164    ///         // us, setting `len` to the correct length.
165    ///         if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 {
166    ///             Err(io::Error::last_os_error())
167    ///         } else {
168    ///             Ok(())
169    ///         }
170    ///     })
171    /// }?;
172    /// # drop(address);
173    /// # }
174    /// # Ok(())
175    /// # }
176    /// ```
177    pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
178    where
179        F: FnOnce(*mut SockAddrStorage, *mut socklen_t) -> io::Result<T>,
180    {
181        const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t;
182        // NOTE: `SockAddr::unix` depends on the storage being zeroed before
183        // calling `init`.
184        // NOTE: calling `recvfrom` with an empty buffer also depends on the
185        // storage being zeroed before calling `init` as the OS might not
186        // initialise it.
187        let mut storage = SockAddrStorage::zeroed();
188        let mut len = STORAGE_SIZE;
189        init(&mut storage, &mut len).map(|res| {
190            debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
191            (res, SockAddr::new(storage, len))
192        })
193    }
194
195    /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
196    ///
197    /// Returns an error if the path is longer than `SUN_LEN`.
198    pub fn unix<P>(path: P) -> io::Result<SockAddr>
199    where
200        P: AsRef<Path>,
201    {
202        crate::sys::unix_sockaddr(path.as_ref())
203    }
204
205    /// Set the length of the address.
206    ///
207    /// # Safety
208    ///
209    /// Caller must ensure that the address up to `length` bytes are properly
210    /// initialised.
211    pub unsafe fn set_length(&mut self, length: socklen_t) {
212        self.len = length;
213    }
214
215    /// Returns this address's family.
216    pub const fn family(&self) -> sa_family_t {
217        self.storage.ss_family
218    }
219
220    /// Returns this address's `Domain`.
221    pub const fn domain(&self) -> Domain {
222        Domain(self.storage.ss_family as c_int)
223    }
224
225    /// Returns the size of this address in bytes.
226    pub const fn len(&self) -> socklen_t {
227        self.len
228    }
229
230    /// Returns a raw pointer to the address.
231    pub const fn as_ptr(&self) -> *const SockAddrStorage {
232        &self.storage as *const sockaddr_storage as *const SockAddrStorage
233    }
234
235    /// Retuns the address as the storage.
236    pub const fn as_storage(self) -> SockAddrStorage {
237        SockAddrStorage {
238            storage: self.storage,
239        }
240    }
241
242    /// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise.
243    pub const fn is_ipv4(&self) -> bool {
244        self.storage.ss_family == AF_INET as sa_family_t
245    }
246
247    /// Returns true if this address is in the `AF_INET6` (IPv6) family, false
248    /// otherwise.
249    pub const fn is_ipv6(&self) -> bool {
250        self.storage.ss_family == AF_INET6 as sa_family_t
251    }
252
253    /// Returns true if this address is of a unix socket (for local interprocess communication),
254    /// i.e. it is from the `AF_UNIX` family, false otherwise.
255    pub fn is_unix(&self) -> bool {
256        self.storage.ss_family == AF_UNIX as sa_family_t
257    }
258
259    /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4)
260    /// or `AF_INET6` (IPv6) family, otherwise returns `None`.
261    pub fn as_socket(&self) -> Option<SocketAddr> {
262        if self.storage.ss_family == AF_INET as sa_family_t {
263            // SAFETY: if the `ss_family` field is `AF_INET` then storage must
264            // be a `sockaddr_in`.
265            let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) };
266            let ip = crate::sys::from_in_addr(addr.sin_addr);
267            let port = u16::from_be(addr.sin_port);
268            Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
269        } else if self.storage.ss_family == AF_INET6 as sa_family_t {
270            // SAFETY: if the `ss_family` field is `AF_INET6` then storage must
271            // be a `sockaddr_in6`.
272            let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) };
273            let ip = crate::sys::from_in6_addr(addr.sin6_addr);
274            let port = u16::from_be(addr.sin6_port);
275            Some(SocketAddr::V6(SocketAddrV6::new(
276                ip,
277                port,
278                addr.sin6_flowinfo,
279                #[cfg(unix)]
280                addr.sin6_scope_id,
281                #[cfg(windows)]
282                unsafe {
283                    addr.Anonymous.sin6_scope_id
284                },
285            )))
286        } else {
287            None
288        }
289    }
290
291    /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
292    /// family.
293    pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
294        match self.as_socket() {
295            Some(SocketAddr::V4(addr)) => Some(addr),
296            _ => None,
297        }
298    }
299
300    /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
301    /// family.
302    pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
303        match self.as_socket() {
304            Some(SocketAddr::V6(addr)) => Some(addr),
305            _ => None,
306        }
307    }
308
309    /// Returns the initialised storage bytes.
310    fn as_bytes(&self) -> &[u8] {
311        // SAFETY: `self.storage` is a C struct which can always be treated a
312        // slice of bytes. Furthermore, we ensure we don't read any unitialised
313        // bytes by using `self.len`.
314        unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
315    }
316}
317
318impl From<SocketAddr> for SockAddr {
319    fn from(addr: SocketAddr) -> SockAddr {
320        match addr {
321            SocketAddr::V4(addr) => addr.into(),
322            SocketAddr::V6(addr) => addr.into(),
323        }
324    }
325}
326
327impl From<SocketAddrV4> for SockAddr {
328    fn from(addr: SocketAddrV4) -> SockAddr {
329        // SAFETY: a `sockaddr_storage` of all zeros is valid.
330        let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
331        let len = {
332            let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() };
333            storage.sin_family = AF_INET as sa_family_t;
334            storage.sin_port = addr.port().to_be();
335            storage.sin_addr = crate::sys::to_in_addr(addr.ip());
336            storage.sin_zero = Default::default();
337            mem::size_of::<sockaddr_in>() as socklen_t
338        };
339        #[cfg(any(
340            target_os = "dragonfly",
341            target_os = "freebsd",
342            target_os = "haiku",
343            target_os = "hermit",
344            target_os = "ios",
345            target_os = "visionos",
346            target_os = "macos",
347            target_os = "netbsd",
348            target_os = "nto",
349            target_os = "openbsd",
350            target_os = "tvos",
351            target_os = "vxworks",
352            target_os = "watchos",
353        ))]
354        {
355            storage.ss_len = len as u8;
356        }
357        SockAddr { storage, len }
358    }
359}
360
361impl From<SocketAddrV6> for SockAddr {
362    fn from(addr: SocketAddrV6) -> SockAddr {
363        // SAFETY: a `sockaddr_storage` of all zeros is valid.
364        let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
365        let len = {
366            let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
367            storage.sin6_family = AF_INET6 as sa_family_t;
368            storage.sin6_port = addr.port().to_be();
369            storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
370            storage.sin6_flowinfo = addr.flowinfo();
371            #[cfg(unix)]
372            {
373                storage.sin6_scope_id = addr.scope_id();
374            }
375            #[cfg(windows)]
376            {
377                storage.Anonymous = SOCKADDR_IN6_0 {
378                    sin6_scope_id: addr.scope_id(),
379                };
380            }
381            mem::size_of::<sockaddr_in6>() as socklen_t
382        };
383        #[cfg(any(
384            target_os = "dragonfly",
385            target_os = "freebsd",
386            target_os = "haiku",
387            target_os = "hermit",
388            target_os = "ios",
389            target_os = "visionos",
390            target_os = "macos",
391            target_os = "netbsd",
392            target_os = "nto",
393            target_os = "openbsd",
394            target_os = "tvos",
395            target_os = "vxworks",
396            target_os = "watchos",
397        ))]
398        {
399            storage.ss_len = len as u8;
400        }
401        SockAddr { storage, len }
402    }
403}
404
405impl fmt::Debug for SockAddr {
406    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
407        let mut f = fmt.debug_struct("SockAddr");
408        #[cfg(any(
409            target_os = "dragonfly",
410            target_os = "freebsd",
411            target_os = "haiku",
412            target_os = "hermit",
413            target_os = "ios",
414            target_os = "visionos",
415            target_os = "macos",
416            target_os = "netbsd",
417            target_os = "nto",
418            target_os = "openbsd",
419            target_os = "tvos",
420            target_os = "vxworks",
421            target_os = "watchos",
422        ))]
423        f.field("ss_len", &self.storage.ss_len);
424        f.field("ss_family", &self.storage.ss_family)
425            .field("len", &self.len)
426            .finish()
427    }
428}
429
430impl PartialEq for SockAddr {
431    fn eq(&self, other: &Self) -> bool {
432        self.as_bytes() == other.as_bytes()
433    }
434}
435
436impl Eq for SockAddr {}
437
438impl Hash for SockAddr {
439    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
440        self.as_bytes().hash(state);
441    }
442}
443
444#[cfg(test)]
445mod tests {
446    use super::*;
447
448    #[test]
449    fn ipv4() {
450        use std::net::Ipv4Addr;
451        let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
452        let addr = SockAddr::from(std);
453        assert!(addr.is_ipv4());
454        assert!(!addr.is_ipv6());
455        assert!(!addr.is_unix());
456        assert_eq!(addr.family(), AF_INET as sa_family_t);
457        assert_eq!(addr.domain(), Domain::IPV4);
458        assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
459        assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
460        assert_eq!(addr.as_socket_ipv4(), Some(std));
461        assert!(addr.as_socket_ipv6().is_none());
462
463        let addr = SockAddr::from(SocketAddr::from(std));
464        assert_eq!(addr.family(), AF_INET as sa_family_t);
465        assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
466        assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
467        assert_eq!(addr.as_socket_ipv4(), Some(std));
468        assert!(addr.as_socket_ipv6().is_none());
469        #[cfg(unix)]
470        {
471            assert!(addr.as_pathname().is_none());
472            assert!(addr.as_abstract_namespace().is_none());
473        }
474    }
475
476    #[test]
477    fn ipv6() {
478        use std::net::Ipv6Addr;
479        let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
480        let addr = SockAddr::from(std);
481        assert!(addr.is_ipv6());
482        assert!(!addr.is_ipv4());
483        assert!(!addr.is_unix());
484        assert_eq!(addr.family(), AF_INET6 as sa_family_t);
485        assert_eq!(addr.domain(), Domain::IPV6);
486        assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
487        assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
488        assert!(addr.as_socket_ipv4().is_none());
489        assert_eq!(addr.as_socket_ipv6(), Some(std));
490
491        let addr = SockAddr::from(SocketAddr::from(std));
492        assert_eq!(addr.family(), AF_INET6 as sa_family_t);
493        assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
494        assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
495        assert!(addr.as_socket_ipv4().is_none());
496        assert_eq!(addr.as_socket_ipv6(), Some(std));
497        #[cfg(unix)]
498        {
499            assert!(addr.as_pathname().is_none());
500            assert!(addr.as_abstract_namespace().is_none());
501        }
502    }
503
504    #[test]
505    fn ipv4_eq() {
506        use std::net::Ipv4Addr;
507
508        let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
509        let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
510
511        test_eq(
512            SockAddr::from(std1),
513            SockAddr::from(std1),
514            SockAddr::from(std2),
515        );
516    }
517
518    #[test]
519    fn ipv4_hash() {
520        use std::net::Ipv4Addr;
521
522        let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
523        let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
524
525        test_hash(
526            SockAddr::from(std1),
527            SockAddr::from(std1),
528            SockAddr::from(std2),
529        );
530    }
531
532    #[test]
533    fn ipv6_eq() {
534        use std::net::Ipv6Addr;
535
536        let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
537        let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
538
539        test_eq(
540            SockAddr::from(std1),
541            SockAddr::from(std1),
542            SockAddr::from(std2),
543        );
544    }
545
546    #[test]
547    fn ipv6_hash() {
548        use std::net::Ipv6Addr;
549
550        let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
551        let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
552
553        test_hash(
554            SockAddr::from(std1),
555            SockAddr::from(std1),
556            SockAddr::from(std2),
557        );
558    }
559
560    #[test]
561    fn ipv4_ipv6_eq() {
562        use std::net::Ipv4Addr;
563        use std::net::Ipv6Addr;
564
565        let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
566        let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
567
568        test_eq(
569            SockAddr::from(std1),
570            SockAddr::from(std1),
571            SockAddr::from(std2),
572        );
573
574        test_eq(
575            SockAddr::from(std2),
576            SockAddr::from(std2),
577            SockAddr::from(std1),
578        );
579    }
580
581    #[test]
582    fn ipv4_ipv6_hash() {
583        use std::net::Ipv4Addr;
584        use std::net::Ipv6Addr;
585
586        let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
587        let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
588
589        test_hash(
590            SockAddr::from(std1),
591            SockAddr::from(std1),
592            SockAddr::from(std2),
593        );
594
595        test_hash(
596            SockAddr::from(std2),
597            SockAddr::from(std2),
598            SockAddr::from(std1),
599        );
600    }
601
602    #[allow(clippy::eq_op)] // allow a0 == a0 check
603    fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) {
604        assert!(a0 == a0);
605        assert!(a0 == a1);
606        assert!(a1 == a0);
607        assert!(a0 != b);
608        assert!(b != a0);
609    }
610
611    fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
612        assert!(calculate_hash(&a0) == calculate_hash(&a0));
613        assert!(calculate_hash(&a0) == calculate_hash(&a1));
614        // technically unequal values can have the same hash, in this case x != z and both have different hashes
615        assert!(calculate_hash(&a0) != calculate_hash(&b));
616    }
617
618    fn calculate_hash(x: &SockAddr) -> u64 {
619        use std::collections::hash_map::DefaultHasher;
620        use std::hash::Hasher;
621
622        let mut hasher = DefaultHasher::new();
623        x.hash(&mut hasher);
624        hasher.finish()
625    }
626}