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