Coverage Report

Created: 2026-08-05 07:20

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