Coverage Report

Created: 2025-11-24 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/socket2-0.6.1/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
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
        // 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
    ///
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
0
    pub unsafe fn view_as<T>(&mut self) -> &mut T {
71
0
        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
0
        &mut *(self as *mut Self as *mut T)
75
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>
76
}
77
78
impl std::fmt::Debug for SockAddrStorage {
79
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80
0
        f.debug_struct("sockaddr_storage")
81
0
            .field("ss_family", &self.storage.ss_family)
82
0
            .finish_non_exhaustive()
83
0
    }
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)]
91
pub struct SockAddr {
92
    storage: sockaddr_storage,
93
    len: socklen_t,
94
}
95
96
#[allow(clippy::len_without_is_empty)]
97
impl 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
0
    pub const unsafe fn new(storage: SockAddrStorage, len: socklen_t) -> SockAddr {
143
0
        SockAddr {
144
0
            storage: storage.storage,
145
0
            len: len as socklen_t,
146
0
        }
147
0
    }
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
0
    pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
195
0
    where
196
0
        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
0
        let mut storage = SockAddrStorage::zeroed();
205
0
        let mut len = STORAGE_SIZE;
206
0
        init(&mut storage, &mut len).map(|res| {
207
0
            debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
208
0
            (res, SockAddr::new(storage, len))
209
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}
210
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>
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
0
    pub fn unix<P>(path: P) -> io::Result<SockAddr>
216
0
    where
217
0
        P: AsRef<Path>,
218
    {
219
0
        crate::sys::unix_sockaddr(path.as_ref())
220
0
    }
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
0
    pub unsafe fn set_length(&mut self, length: socklen_t) {
229
0
        self.len = length;
230
0
    }
231
232
    /// Returns this address's family.
233
0
    pub const fn family(&self) -> sa_family_t {
234
0
        self.storage.ss_family
235
0
    }
236
237
    /// Returns this address's `Domain`.
238
0
    pub const fn domain(&self) -> Domain {
239
0
        Domain(self.storage.ss_family as c_int)
240
0
    }
241
242
    /// Returns the size of this address in bytes.
243
0
    pub const fn len(&self) -> socklen_t {
244
0
        self.len
245
0
    }
246
247
    /// Returns a raw pointer to the address.
248
0
    pub const fn as_ptr(&self) -> *const SockAddrStorage {
249
0
        &self.storage as *const sockaddr_storage as *const SockAddrStorage
250
0
    }
251
252
    /// Retuns the address as the storage.
253
0
    pub const fn as_storage(self) -> SockAddrStorage {
254
0
        SockAddrStorage {
255
0
            storage: self.storage,
256
0
        }
257
0
    }
258
259
    /// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise.
260
0
    pub const fn is_ipv4(&self) -> bool {
261
0
        self.storage.ss_family == AF_INET as sa_family_t
262
0
    }
263
264
    /// Returns true if this address is in the `AF_INET6` (IPv6) family, false
265
    /// otherwise.
266
0
    pub const fn is_ipv6(&self) -> bool {
267
0
        self.storage.ss_family == AF_INET6 as sa_family_t
268
0
    }
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
0
    pub fn is_unix(&self) -> bool {
273
0
        self.storage.ss_family == AF_UNIX as sa_family_t
274
0
    }
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
0
    pub fn as_socket(&self) -> Option<SocketAddr> {
279
0
        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
0
            let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) };
283
0
            let ip = crate::sys::from_in_addr(addr.sin_addr);
284
0
            let port = u16::from_be(addr.sin_port);
285
0
            Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
286
0
        } 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
0
            let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) };
290
0
            let ip = crate::sys::from_in6_addr(addr.sin6_addr);
291
0
            let port = u16::from_be(addr.sin6_port);
292
0
            Some(SocketAddr::V6(SocketAddrV6::new(
293
0
                ip,
294
0
                port,
295
0
                addr.sin6_flowinfo,
296
0
                #[cfg(unix)]
297
0
                addr.sin6_scope_id,
298
0
                #[cfg(windows)]
299
0
                unsafe {
300
0
                    addr.Anonymous.sin6_scope_id
301
0
                },
302
0
            )))
303
        } else {
304
0
            None
305
        }
306
0
    }
307
308
    /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
309
    /// family.
310
0
    pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
311
0
        match self.as_socket() {
312
0
            Some(SocketAddr::V4(addr)) => Some(addr),
313
0
            _ => None,
314
        }
315
0
    }
316
317
    /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
318
    /// family.
319
0
    pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
320
0
        match self.as_socket() {
321
0
            Some(SocketAddr::V6(addr)) => Some(addr),
322
0
            _ => None,
323
        }
324
0
    }
325
326
    /// Returns the initialised storage bytes.
327
0
    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
0
        unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
332
0
    }
333
}
334
335
impl From<SocketAddr> for SockAddr {
336
0
    fn from(addr: SocketAddr) -> SockAddr {
337
0
        match addr {
338
0
            SocketAddr::V4(addr) => addr.into(),
339
0
            SocketAddr::V6(addr) => addr.into(),
340
        }
341
0
    }
342
}
343
344
impl From<SocketAddrV4> for SockAddr {
345
0
    fn from(addr: SocketAddrV4) -> SockAddr {
346
        // SAFETY: a `sockaddr_storage` of all zeros is valid.
347
0
        let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
348
0
        let len = {
349
0
            let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() };
350
0
            storage.sin_family = AF_INET as sa_family_t;
351
0
            storage.sin_port = addr.port().to_be();
352
0
            storage.sin_addr = crate::sys::to_in_addr(addr.ip());
353
0
            storage.sin_zero = Default::default();
354
0
            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
0
        SockAddr { storage, len }
375
0
    }
376
}
377
378
impl From<SocketAddrV6> for SockAddr {
379
0
    fn from(addr: SocketAddrV6) -> SockAddr {
380
        // SAFETY: a `sockaddr_storage` of all zeros is valid.
381
0
        let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
382
0
        let len = {
383
0
            let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
384
0
            storage.sin6_family = AF_INET6 as sa_family_t;
385
0
            storage.sin6_port = addr.port().to_be();
386
0
            storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
387
0
            storage.sin6_flowinfo = addr.flowinfo();
388
            #[cfg(unix)]
389
0
            {
390
0
                storage.sin6_scope_id = addr.scope_id();
391
0
            }
392
            #[cfg(windows)]
393
            {
394
                storage.Anonymous = SOCKADDR_IN6_0 {
395
                    sin6_scope_id: addr.scope_id(),
396
                };
397
            }
398
0
            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
0
        SockAddr { storage, len }
419
0
    }
420
}
421
422
impl fmt::Debug for SockAddr {
423
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
424
0
        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
0
        f.field("ss_family", &self.storage.ss_family)
442
0
            .field("len", &self.len)
443
0
            .finish()
444
0
    }
445
}
446
447
impl PartialEq for SockAddr {
448
0
    fn eq(&self, other: &Self) -> bool {
449
0
        self.as_bytes() == other.as_bytes()
450
0
    }
451
}
452
453
impl Eq for SockAddr {}
454
455
impl Hash for SockAddr {
456
0
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
457
0
        self.as_bytes().hash(state);
458
0
    }
459
}
460
461
#[cfg(test)]
462
mod 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
}