Coverage Report

Created: 2025-07-23 07:04

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