Coverage Report

Created: 2025-07-18 07:02

/rust/registry/src/index.crates.io-6f17d22bba15001f/socket2-0.6.0/src/sockaddr.rs
Line
Count
Source (jump to first uncovered line)
1
use std::hash::Hash;
2
use std::mem::{self, size_of};
3
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
4
use std::path::Path;
5
use std::{fmt, io, ptr};
6
7
#[cfg(windows)]
8
use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
9
10
use crate::sys::{c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, AF_INET, AF_INET6, AF_UNIX};
11
use crate::Domain;
12
13
/// The integer type used with `getsockname` on this platform.
14
#[allow(non_camel_case_types)]
15
pub 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)]
19
pub 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)]
29
pub struct SockAddrStorage {
30
    storage: sockaddr_storage,
31
}
32
33
impl SockAddrStorage {
34
    /// Construct a new storage containing all zeros.
35
    #[inline]
36
0
    pub fn zeroed() -> Self {
37
0
        // SAFETY: All zeros is valid for this type.
38
0
        unsafe { mem::zeroed() }
39
0
    }
40
41
    /// Returns the size of this storage.
42
    #[inline]
43
0
    pub fn size_of(&self) -> socklen_t {
44
0
        size_of::<Self>() as socklen_t
45
0
    }
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
0
    pub unsafe fn view_as<T>(&mut self) -> &mut T {
54
0
        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
0
        &mut *(self as *mut Self as *mut T)
58
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>
59
}
60
61
impl std::fmt::Debug for SockAddrStorage {
62
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63
0
        f.debug_struct("sockaddr_storage")
64
0
            .field("ss_family", &self.storage.ss_family)
65
0
            .finish_non_exhaustive()
66
0
    }
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)]
74
pub struct SockAddr {
75
    storage: sockaddr_storage,
76
    len: socklen_t,
77
}
78
79
#[allow(clippy::len_without_is_empty)]
80
impl 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
0
    pub const unsafe fn new(storage: SockAddrStorage, len: socklen_t) -> SockAddr {
126
0
        SockAddr {
127
0
            storage: storage.storage,
128
0
            len: len as socklen_t,
129
0
        }
130
0
    }
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
0
    pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
178
0
    where
179
0
        F: FnOnce(*mut SockAddrStorage, *mut socklen_t) -> io::Result<T>,
180
0
    {
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
0
        let mut storage = SockAddrStorage::zeroed();
188
0
        let mut len = STORAGE_SIZE;
189
0
        init(&mut storage, &mut len).map(|res| {
190
0
            debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
191
0
            (res, SockAddr::new(storage, len))
192
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}
193
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>
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
0
    pub fn unix<P>(path: P) -> io::Result<SockAddr>
199
0
    where
200
0
        P: AsRef<Path>,
201
0
    {
202
0
        crate::sys::unix_sockaddr(path.as_ref())
203
0
    }
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
0
    pub unsafe fn set_length(&mut self, length: socklen_t) {
212
0
        self.len = length;
213
0
    }
214
215
    /// Returns this address's family.
216
0
    pub const fn family(&self) -> sa_family_t {
217
0
        self.storage.ss_family
218
0
    }
219
220
    /// Returns this address's `Domain`.
221
0
    pub const fn domain(&self) -> Domain {
222
0
        Domain(self.storage.ss_family as c_int)
223
0
    }
224
225
    /// Returns the size of this address in bytes.
226
0
    pub const fn len(&self) -> socklen_t {
227
0
        self.len
228
0
    }
229
230
    /// Returns a raw pointer to the address.
231
0
    pub const fn as_ptr(&self) -> *const SockAddrStorage {
232
0
        &self.storage as *const sockaddr_storage as *const SockAddrStorage
233
0
    }
234
235
    /// Retuns the address as the storage.
236
0
    pub const fn as_storage(self) -> SockAddrStorage {
237
0
        SockAddrStorage {
238
0
            storage: self.storage,
239
0
        }
240
0
    }
241
242
    /// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise.
243
0
    pub const fn is_ipv4(&self) -> bool {
244
0
        self.storage.ss_family == AF_INET as sa_family_t
245
0
    }
246
247
    /// Returns true if this address is in the `AF_INET6` (IPv6) family, false
248
    /// otherwise.
249
0
    pub const fn is_ipv6(&self) -> bool {
250
0
        self.storage.ss_family == AF_INET6 as sa_family_t
251
0
    }
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
0
    pub fn is_unix(&self) -> bool {
256
0
        self.storage.ss_family == AF_UNIX as sa_family_t
257
0
    }
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
0
    pub fn as_socket(&self) -> Option<SocketAddr> {
262
0
        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
0
            let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) };
266
0
            let ip = crate::sys::from_in_addr(addr.sin_addr);
267
0
            let port = u16::from_be(addr.sin_port);
268
0
            Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
269
0
        } 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
0
            let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) };
273
0
            let ip = crate::sys::from_in6_addr(addr.sin6_addr);
274
0
            let port = u16::from_be(addr.sin6_port);
275
0
            Some(SocketAddr::V6(SocketAddrV6::new(
276
0
                ip,
277
0
                port,
278
0
                addr.sin6_flowinfo,
279
0
                #[cfg(unix)]
280
0
                addr.sin6_scope_id,
281
0
                #[cfg(windows)]
282
0
                unsafe {
283
0
                    addr.Anonymous.sin6_scope_id
284
0
                },
285
0
            )))
286
        } else {
287
0
            None
288
        }
289
0
    }
290
291
    /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
292
    /// family.
293
0
    pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
294
0
        match self.as_socket() {
295
0
            Some(SocketAddr::V4(addr)) => Some(addr),
296
0
            _ => None,
297
        }
298
0
    }
299
300
    /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
301
    /// family.
302
0
    pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
303
0
        match self.as_socket() {
304
0
            Some(SocketAddr::V6(addr)) => Some(addr),
305
0
            _ => None,
306
        }
307
0
    }
308
309
    /// Returns the initialised storage bytes.
310
0
    fn as_bytes(&self) -> &[u8] {
311
0
        // SAFETY: `self.storage` is a C struct which can always be treated a
312
0
        // slice of bytes. Furthermore, we ensure we don't read any unitialised
313
0
        // bytes by using `self.len`.
314
0
        unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
315
0
    }
316
}
317
318
impl From<SocketAddr> for SockAddr {
319
0
    fn from(addr: SocketAddr) -> SockAddr {
320
0
        match addr {
321
0
            SocketAddr::V4(addr) => addr.into(),
322
0
            SocketAddr::V6(addr) => addr.into(),
323
        }
324
0
    }
325
}
326
327
impl From<SocketAddrV4> for SockAddr {
328
0
    fn from(addr: SocketAddrV4) -> SockAddr {
329
0
        // SAFETY: a `sockaddr_storage` of all zeros is valid.
330
0
        let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
331
0
        let len = {
332
0
            let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() };
333
0
            storage.sin_family = AF_INET as sa_family_t;
334
0
            storage.sin_port = addr.port().to_be();
335
0
            storage.sin_addr = crate::sys::to_in_addr(addr.ip());
336
0
            storage.sin_zero = Default::default();
337
0
            mem::size_of::<sockaddr_in>() as socklen_t
338
0
        };
339
0
        #[cfg(any(
340
0
            target_os = "dragonfly",
341
0
            target_os = "freebsd",
342
0
            target_os = "haiku",
343
0
            target_os = "hermit",
344
0
            target_os = "ios",
345
0
            target_os = "visionos",
346
0
            target_os = "macos",
347
0
            target_os = "netbsd",
348
0
            target_os = "nto",
349
0
            target_os = "openbsd",
350
0
            target_os = "tvos",
351
0
            target_os = "vxworks",
352
0
            target_os = "watchos",
353
0
        ))]
354
0
        {
355
0
            storage.ss_len = len as u8;
356
0
        }
357
0
        SockAddr { storage, len }
358
0
    }
359
}
360
361
impl From<SocketAddrV6> for SockAddr {
362
0
    fn from(addr: SocketAddrV6) -> SockAddr {
363
0
        // SAFETY: a `sockaddr_storage` of all zeros is valid.
364
0
        let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
365
0
        let len = {
366
0
            let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
367
0
            storage.sin6_family = AF_INET6 as sa_family_t;
368
0
            storage.sin6_port = addr.port().to_be();
369
0
            storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
370
0
            storage.sin6_flowinfo = addr.flowinfo();
371
0
            #[cfg(unix)]
372
0
            {
373
0
                storage.sin6_scope_id = addr.scope_id();
374
0
            }
375
0
            #[cfg(windows)]
376
0
            {
377
0
                storage.Anonymous = SOCKADDR_IN6_0 {
378
0
                    sin6_scope_id: addr.scope_id(),
379
0
                };
380
0
            }
381
0
            mem::size_of::<sockaddr_in6>() as socklen_t
382
0
        };
383
0
        #[cfg(any(
384
0
            target_os = "dragonfly",
385
0
            target_os = "freebsd",
386
0
            target_os = "haiku",
387
0
            target_os = "hermit",
388
0
            target_os = "ios",
389
0
            target_os = "visionos",
390
0
            target_os = "macos",
391
0
            target_os = "netbsd",
392
0
            target_os = "nto",
393
0
            target_os = "openbsd",
394
0
            target_os = "tvos",
395
0
            target_os = "vxworks",
396
0
            target_os = "watchos",
397
0
        ))]
398
0
        {
399
0
            storage.ss_len = len as u8;
400
0
        }
401
0
        SockAddr { storage, len }
402
0
    }
403
}
404
405
impl fmt::Debug for SockAddr {
406
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
407
0
        let mut f = fmt.debug_struct("SockAddr");
408
0
        #[cfg(any(
409
0
            target_os = "dragonfly",
410
0
            target_os = "freebsd",
411
0
            target_os = "haiku",
412
0
            target_os = "hermit",
413
0
            target_os = "ios",
414
0
            target_os = "visionos",
415
0
            target_os = "macos",
416
0
            target_os = "netbsd",
417
0
            target_os = "nto",
418
0
            target_os = "openbsd",
419
0
            target_os = "tvos",
420
0
            target_os = "vxworks",
421
0
            target_os = "watchos",
422
0
        ))]
423
0
        f.field("ss_len", &self.storage.ss_len);
424
0
        f.field("ss_family", &self.storage.ss_family)
425
0
            .field("len", &self.len)
426
0
            .finish()
427
0
    }
428
}
429
430
impl PartialEq for SockAddr {
431
0
    fn eq(&self, other: &Self) -> bool {
432
0
        self.as_bytes() == other.as_bytes()
433
0
    }
434
}
435
436
impl Eq for SockAddr {}
437
438
impl Hash for SockAddr {
439
0
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
440
0
        self.as_bytes().hash(state);
441
0
    }
442
}
443
444
#[cfg(test)]
445
mod 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
}