Skip to main content

socket2/
sockaddr.rs

1use std::hash::Hash;
2use std::mem::{self, size_of};
3use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
4#[cfg(not(target_os = "wasi"))]
5use std::path::Path;
6use std::{fmt, io, ptr};
7
8#[cfg(windows)]
9use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
10
11#[cfg(not(target_os = "wasi"))]
12use crate::sys::AF_UNIX;
13use crate::sys::{c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, AF_INET, AF_INET6};
14use crate::Domain;
15
16/// The integer type used with `getsockname` on this platform.
17#[allow(non_camel_case_types)]
18pub 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)]
22pub 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)]
32pub struct SockAddrStorage {
33    storage: sockaddr_storage,
34}
35
36impl SockAddrStorage {
37    /// Construct a new storage containing all zeros.
38    #[inline]
39    pub fn zeroed() -> Self {
40        // SAFETY: All zeros is valid for this type.
41        unsafe { mem::zeroed() }
42    }
43
44    /// Returns the size of this storage.
45    #[inline]
46    pub fn size_of(&self) -> socklen_t {
47        size_of::<Self>() as socklen_t
48    }
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    pub unsafe fn view_as<T>(&mut self) -> &mut T {
74        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        &mut *(self as *mut Self as *mut T)
78    }
79}
80
81impl std::fmt::Debug for SockAddrStorage {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        f.debug_struct("sockaddr_storage")
84            .field("ss_family", &self.storage.ss_family)
85            .finish_non_exhaustive()
86    }
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)]
94pub struct SockAddr {
95    storage: sockaddr_storage,
96    len: socklen_t,
97}
98
99#[allow(clippy::len_without_is_empty)]
100impl 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    pub const unsafe fn new(storage: SockAddrStorage, len: socklen_t) -> SockAddr {
146        SockAddr {
147            storage: storage.storage,
148            len: len as socklen_t,
149        }
150    }
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    pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
198    where
199        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        let mut storage = SockAddrStorage::zeroed();
208        let mut len = STORAGE_SIZE;
209        init(&mut storage, &mut len).map(|res| {
210            debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
211            (res, SockAddr::new(storage, len))
212        })
213    }
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    pub fn unix<P>(path: P) -> io::Result<SockAddr>
220    where
221        P: AsRef<Path>,
222    {
223        crate::sys::unix_sockaddr(path.as_ref())
224    }
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    pub unsafe fn set_length(&mut self, length: socklen_t) {
233        self.len = length;
234    }
235
236    /// Returns this address's family.
237    pub const fn family(&self) -> sa_family_t {
238        self.storage.ss_family
239    }
240
241    /// Returns this address's `Domain`.
242    pub const fn domain(&self) -> Domain {
243        Domain(self.storage.ss_family as c_int)
244    }
245
246    /// Returns the size of this address in bytes.
247    pub const fn len(&self) -> socklen_t {
248        self.len
249    }
250
251    /// Returns a raw pointer to the address.
252    pub const fn as_ptr(&self) -> *const SockAddrStorage {
253        &self.storage as *const sockaddr_storage as *const SockAddrStorage
254    }
255
256    /// Returns the address as the storage.
257    pub const fn as_storage(self) -> SockAddrStorage {
258        SockAddrStorage {
259            storage: self.storage,
260        }
261    }
262
263    /// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise.
264    pub const fn is_ipv4(&self) -> bool {
265        self.storage.ss_family == AF_INET as sa_family_t
266    }
267
268    /// Returns true if this address is in the `AF_INET6` (IPv6) family, false
269    /// otherwise.
270    pub const fn is_ipv6(&self) -> bool {
271        self.storage.ss_family == AF_INET6 as sa_family_t
272    }
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    pub fn is_unix(&self) -> bool {
278        self.storage.ss_family == AF_UNIX as sa_family_t
279    }
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    pub fn as_socket(&self) -> Option<SocketAddr> {
284        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            let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) };
288            let ip = crate::sys::from_in_addr(addr.sin_addr);
289            let port = u16::from_be(addr.sin_port);
290            Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
291        } 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            let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) };
295            let ip = crate::sys::from_in6_addr(addr.sin6_addr);
296            let port = u16::from_be(addr.sin6_port);
297            Some(SocketAddr::V6(SocketAddrV6::new(
298                ip,
299                port,
300                addr.sin6_flowinfo,
301                #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
302                addr.sin6_scope_id,
303                #[cfg(windows)]
304                unsafe {
305                    addr.Anonymous.sin6_scope_id
306                },
307            )))
308        } else {
309            None
310        }
311    }
312
313    /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
314    /// family.
315    pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
316        match self.as_socket() {
317            Some(SocketAddr::V4(addr)) => Some(addr),
318            _ => None,
319        }
320    }
321
322    /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
323    /// family.
324    pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
325        match self.as_socket() {
326            Some(SocketAddr::V6(addr)) => Some(addr),
327            _ => None,
328        }
329    }
330
331    /// Returns the initialised storage bytes.
332    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        unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
337    }
338}
339
340impl From<SocketAddr> for SockAddr {
341    fn from(addr: SocketAddr) -> SockAddr {
342        match addr {
343            SocketAddr::V4(addr) => addr.into(),
344            SocketAddr::V6(addr) => addr.into(),
345        }
346    }
347}
348
349impl From<SocketAddrV4> for SockAddr {
350    fn from(addr: SocketAddrV4) -> SockAddr {
351        // SAFETY: a `sockaddr_storage` of all zeros is valid.
352        let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
353        let len = {
354            let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() };
355            storage.sin_family = AF_INET as sa_family_t;
356            storage.sin_port = addr.port().to_be();
357            storage.sin_addr = crate::sys::to_in_addr(addr.ip());
358            #[cfg(not(target_os = "wasi"))]
359            {
360                storage.sin_zero = Default::default();
361            }
362            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        SockAddr { storage, len }
383    }
384}
385
386impl From<SocketAddrV6> for SockAddr {
387    fn from(addr: SocketAddrV6) -> SockAddr {
388        // SAFETY: a `sockaddr_storage` of all zeros is valid.
389        let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
390        let len = {
391            let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
392            storage.sin6_family = AF_INET6 as sa_family_t;
393            storage.sin6_port = addr.port().to_be();
394            storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
395            storage.sin6_flowinfo = addr.flowinfo();
396            #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
397            {
398                storage.sin6_scope_id = addr.scope_id();
399            }
400            #[cfg(windows)]
401            {
402                storage.Anonymous = SOCKADDR_IN6_0 {
403                    sin6_scope_id: addr.scope_id(),
404                };
405            }
406            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        SockAddr { storage, len }
427    }
428}
429
430impl fmt::Debug for SockAddr {
431    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
432        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        f.field("ss_family", &self.storage.ss_family)
450            .field("len", &self.len)
451            .finish()
452    }
453}
454
455impl PartialEq for SockAddr {
456    fn eq(&self, other: &Self) -> bool {
457        self.as_bytes() == other.as_bytes()
458    }
459}
460
461impl Eq for SockAddr {}
462
463impl Hash for SockAddr {
464    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
465        self.as_bytes().hash(state);
466    }
467}
468
469#[cfg(test)]
470mod 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}