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
@@ -44,23 +92,22 @@ impl SockAddr {
44
92
/// # fn main() -> std::io::Result<()> {
45
93
/// # #[cfg(unix)] {
46
94
/// use std::io;
47
- /// use std::mem;
48
95
/// use std::os::unix::io::AsRawFd;
49
96
///
50
- /// use socket2::{SockAddr, Socket, Domain, Type};
97
+ /// use socket2::{SockAddr, SockAddrStorage, Socket, Domain, Type};
51
98
///
52
99
/// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
53
100
///
54
101
/// // 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 ;
102
+ /// let mut addr_storage = SockAddrStorage ::zeroed();
103
+ /// let mut len = addr_storage.size_of() ;
57
104
///
58
105
/// // The `getsockname(2)` system call will intiliase `storage` for
59
106
/// // us, setting `len` to the correct length.
60
107
/// let res = unsafe {
61
108
/// libc::getsockname(
62
109
/// socket.as_raw_fd(),
63
- /// (&mut addr_storage as *mut libc::sockaddr_storage).cast (),
110
+ /// addr_storage.view_as (),
64
111
/// &mut len,
65
112
/// )
66
113
/// };
@@ -74,8 +121,11 @@ impl SockAddr {
74
121
/// # Ok(())
75
122
/// # }
76
123
/// ```
77
- pub const unsafe fn new ( storage : sockaddr_storage , len : socklen_t ) -> SockAddr {
78
- SockAddr { storage, len }
124
+ pub const unsafe fn new ( storage : SockAddrStorage , len : socklen_t ) -> SockAddr {
125
+ SockAddr {
126
+ storage : storage. storage ,
127
+ len : len as socklen_t ,
128
+ }
79
129
}
80
130
81
131
/// Initialise a `SockAddr` by calling the function `init`.
@@ -125,25 +175,19 @@ impl SockAddr {
125
175
/// ```
126
176
pub unsafe fn try_init < F , T > ( init : F ) -> io:: Result < ( T , SockAddr ) >
127
177
where
128
- F : FnOnce ( * mut sockaddr_storage , * mut socklen_t ) -> io:: Result < T > ,
178
+ F : FnOnce ( * mut SockAddrStorage , * mut socklen_t ) -> io:: Result < T > ,
129
179
{
130
180
const STORAGE_SIZE : socklen_t = size_of :: < sockaddr_storage > ( ) as socklen_t ;
131
181
// NOTE: `SockAddr::unix` depends on the storage being zeroed before
132
182
// calling `init`.
133
183
// NOTE: calling `recvfrom` with an empty buffer also depends on the
134
184
// storage being zeroed before calling `init` as the OS might not
135
185
// initialise it.
136
- let mut storage = MaybeUninit :: < sockaddr_storage > :: zeroed ( ) ;
186
+ let mut storage = SockAddrStorage :: zeroed ( ) ;
137
187
let mut len = STORAGE_SIZE ;
138
- init ( storage. as_mut_ptr ( ) , & mut len) . map ( |res| {
188
+ init ( & mut storage, & mut len) . map ( |res| {
139
189
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)
190
+ ( res, SockAddr :: new ( storage, len) )
147
191
} )
148
192
}
149
193
0 commit comments