11use std:: hash:: Hash ;
2- use std:: mem:: { self , size_of, MaybeUninit } ;
2+ use std:: mem:: { self , size_of} ;
33use std:: net:: { SocketAddr , SocketAddrV4 , SocketAddrV6 } ;
44use std:: path:: Path ;
55use std:: { fmt, io, ptr} ;
@@ -17,6 +17,54 @@ use crate::Domain;
1717#[ allow( non_camel_case_types) ]
1818pub type socklen_t = crate :: sys:: socklen_t ;
1919
20+ /// Rust version of the [`sockaddr_storage`] type.
21+ ///
22+ /// This type is intended to be used with with direct calls to the `getsockname` syscall. See the
23+ /// documentation of [`SockAddr::new`] for examples.
24+ ///
25+ /// This crate defines its own `sockaddr_storage` type to avoid semver concerns with upgrading
26+ /// `windows-sys`.
27+ #[ repr( transparent) ]
28+ pub struct SockAddrStorage {
29+ storage : sockaddr_storage ,
30+ }
31+
32+ impl SockAddrStorage {
33+ /// Construct a new storage containing all zeros.
34+ #[ inline]
35+ pub fn zeroed ( ) -> Self {
36+ // SAFETY: All zeros is valid for this type.
37+ unsafe { mem:: zeroed ( ) }
38+ }
39+
40+ /// Returns the size of this storage.
41+ #[ inline]
42+ pub fn size_of ( & self ) -> socklen_t {
43+ size_of :: < Self > ( ) as socklen_t
44+ }
45+
46+ /// View this type as another type.
47+ ///
48+ /// # Safety
49+ ///
50+ /// The type `T` must be one of the `sockaddr_*` types defined by this platform.
51+ #[ inline]
52+ pub unsafe fn view_as < T > ( & mut self ) -> & mut T {
53+ assert ! ( size_of:: <T >( ) <= size_of:: <Self >( ) ) ;
54+ // SAFETY: This type is repr(transparent) over `sockaddr_storage` and `T` is one of the
55+ // `sockaddr_*` types defined by this platform.
56+ unsafe { & mut * ( self as * mut Self as * mut T ) }
57+ }
58+ }
59+
60+ impl std:: fmt:: Debug for SockAddrStorage {
61+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
62+ f. debug_struct ( "sockaddr_storage" )
63+ . field ( "ss_family" , & self . storage . ss_family )
64+ . finish_non_exhaustive ( )
65+ }
66+ }
67+
2068/// The address of a socket.
2169///
2270/// `SockAddr`s may be constructed directly to and from the standard library
@@ -52,15 +100,15 @@ impl SockAddr {
52100 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
53101 ///
54102 /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
55- /// let mut addr_storage: libc::sockaddr_storage = unsafe { mem ::zeroed() } ;
56- /// let mut len = mem::size_of_val(& addr_storage) as libc::socklen_t ;
103+ /// let mut addr_storage = SockAddrStorage ::zeroed();
104+ /// let mut len = addr_storage.size_of() ;
57105 ///
58106 /// // The `getsockname(2)` system call will intiliase `storage` for
59107 /// // us, setting `len` to the correct length.
60108 /// let res = unsafe {
61109 /// libc::getsockname(
62110 /// socket.as_raw_fd(),
63- /// (&mut addr_storage as *mut libc::sockaddr_storage ).cast(),
111+ /// (&mut addr_storage).cast(),
64112 /// &mut len,
65113 /// )
66114 /// };
@@ -74,8 +122,11 @@ impl SockAddr {
74122 /// # Ok(())
75123 /// # }
76124 /// ```
77- pub const unsafe fn new ( storage : sockaddr_storage , len : socklen_t ) -> SockAddr {
78- SockAddr { storage, len }
125+ pub const unsafe fn new ( storage : SockAddrStorage , len : socklen_t ) -> SockAddr {
126+ SockAddr {
127+ storage : storage. storage ,
128+ len : len as socklen_t ,
129+ }
79130 }
80131
81132 /// Initialise a `SockAddr` by calling the function `init`.
@@ -125,25 +176,19 @@ impl SockAddr {
125176 /// ```
126177 pub unsafe fn try_init < F , T > ( init : F ) -> io:: Result < ( T , SockAddr ) >
127178 where
128- F : FnOnce ( * mut sockaddr_storage , * mut socklen_t ) -> io:: Result < T > ,
179+ F : FnOnce ( * mut SockAddrStorage , * mut socklen_t ) -> io:: Result < T > ,
129180 {
130181 const STORAGE_SIZE : socklen_t = size_of :: < sockaddr_storage > ( ) as socklen_t ;
131182 // NOTE: `SockAddr::unix` depends on the storage being zeroed before
132183 // calling `init`.
133184 // NOTE: calling `recvfrom` with an empty buffer also depends on the
134185 // storage being zeroed before calling `init` as the OS might not
135186 // initialise it.
136- let mut storage = MaybeUninit :: < sockaddr_storage > :: zeroed ( ) ;
187+ let mut storage = SockAddrStorage :: zeroed ( ) ;
137188 let mut len = STORAGE_SIZE ;
138- init ( storage. as_mut_ptr ( ) , & mut len) . map ( |res| {
189+ init ( & mut storage, & mut len) . map ( |res| {
139190 debug_assert ! ( len <= STORAGE_SIZE , "overflown address storage" ) ;
140- let addr = SockAddr {
141- // Safety: zeroed-out `sockaddr_storage` is valid, caller must
142- // ensure at least `len` bytes are valid.
143- storage : storage. assume_init ( ) ,
144- len,
145- } ;
146- ( res, addr)
191+ ( res, SockAddr :: new ( storage, len) )
147192 } )
148193 }
149194
0 commit comments