1
1
use std:: hash:: Hash ;
2
- use std:: mem:: { self , size_of, MaybeUninit } ;
2
+ use std:: mem:: { self , size_of} ;
3
3
use std:: net:: { SocketAddr , SocketAddrV4 , SocketAddrV6 } ;
4
4
use std:: path:: Path ;
5
5
use std:: { fmt, io, ptr} ;
@@ -17,6 +17,54 @@ use crate::Domain;
17
17
#[ allow( non_camel_case_types) ]
18
18
pub type socklen_t = crate :: sys:: socklen_t ;
19
19
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
+
20
68
/// The address of a socket.
21
69
///
22
70
/// `SockAddr`s may be constructed directly to and from the standard library
@@ -52,15 +100,15 @@ impl SockAddr {
52
100
/// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
53
101
///
54
102
/// // 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() ;
57
105
///
58
106
/// // The `getsockname(2)` system call will intiliase `storage` for
59
107
/// // us, setting `len` to the correct length.
60
108
/// let res = unsafe {
61
109
/// libc::getsockname(
62
110
/// socket.as_raw_fd(),
63
- /// (&mut addr_storage as *mut libc::sockaddr_storage ).cast(),
111
+ /// (&mut addr_storage).cast(),
64
112
/// &mut len,
65
113
/// )
66
114
/// };
@@ -74,8 +122,11 @@ impl SockAddr {
74
122
/// # Ok(())
75
123
/// # }
76
124
/// ```
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
+ }
79
130
}
80
131
81
132
/// Initialise a `SockAddr` by calling the function `init`.
@@ -125,25 +176,19 @@ impl SockAddr {
125
176
/// ```
126
177
pub unsafe fn try_init < F , T > ( init : F ) -> io:: Result < ( T , SockAddr ) >
127
178
where
128
- F : FnOnce ( * mut sockaddr_storage , * mut socklen_t ) -> io:: Result < T > ,
179
+ F : FnOnce ( * mut SockAddrStorage , * mut socklen_t ) -> io:: Result < T > ,
129
180
{
130
181
const STORAGE_SIZE : socklen_t = size_of :: < sockaddr_storage > ( ) as socklen_t ;
131
182
// NOTE: `SockAddr::unix` depends on the storage being zeroed before
132
183
// calling `init`.
133
184
// NOTE: calling `recvfrom` with an empty buffer also depends on the
134
185
// storage being zeroed before calling `init` as the OS might not
135
186
// initialise it.
136
- let mut storage = MaybeUninit :: < sockaddr_storage > :: zeroed ( ) ;
187
+ let mut storage = SockAddrStorage :: zeroed ( ) ;
137
188
let mut len = STORAGE_SIZE ;
138
- init ( storage. as_mut_ptr ( ) , & mut len) . map ( |res| {
189
+ init ( & mut storage, & mut len) . map ( |res| {
139
190
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) )
147
192
} )
148
193
}
149
194
0 commit comments