@@ -3,6 +3,7 @@ mod tests;
3
3
4
4
use crate :: ffi:: { c_int, c_void} ;
5
5
use crate :: io:: { self , BorrowedCursor , ErrorKind , IoSlice , IoSliceMut } ;
6
+ use crate :: mem:: MaybeUninit ;
6
7
use crate :: net:: {
7
8
Ipv4Addr , Ipv6Addr , Shutdown , SocketAddr , SocketAddrV4 , SocketAddrV6 , ToSocketAddrs ,
8
9
} ;
@@ -177,6 +178,11 @@ fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) {
177
178
}
178
179
}
179
180
181
+ /// Converts the C socket address stored in `storage` to a Rust `SocketAddr`.
182
+ ///
183
+ /// # Safety
184
+ /// * `storage` must contain a valid C socket address whose length is no larger
185
+ /// than `len`.
180
186
unsafe fn socket_addr_from_c (
181
187
storage : * const c:: sockaddr_storage ,
182
188
len : usize ,
@@ -202,49 +208,85 @@ unsafe fn socket_addr_from_c(
202
208
// sockaddr and misc bindings
203
209
////////////////////////////////////////////////////////////////////////////////
204
210
205
- pub fn setsockopt < T > (
211
+ /// Sets the value of a socket option.
212
+ ///
213
+ /// # Safety
214
+ /// `T` must be the type associated with the given socket option.
215
+ pub unsafe fn setsockopt < T > (
206
216
sock : & Socket ,
207
217
level : c_int ,
208
218
option_name : c_int ,
209
219
option_value : T ,
210
220
) -> io:: Result < ( ) > {
211
- unsafe {
212
- cvt ( c:: setsockopt (
221
+ let option_len = size_of :: < T > ( ) as c:: socklen_t ;
222
+ // SAFETY:
223
+ // * `sock` is opened for the duration of this call, as `sock` owns the socket.
224
+ // * the pointer to `option_value` is readable at a size of `size_of::<T>`
225
+ // bytes
226
+ // * the value of `option_value` has a valid type for the given socket option
227
+ // (guaranteed by caller).
228
+ cvt ( unsafe {
229
+ c:: setsockopt (
213
230
sock. as_raw ( ) ,
214
231
level,
215
232
option_name,
216
233
( & raw const option_value) as * const _ ,
217
- size_of :: < T > ( ) as c :: socklen_t ,
218
- ) ) ? ;
219
- Ok ( ( ) )
220
- }
234
+ option_len ,
235
+ )
236
+ } ) ? ;
237
+ Ok ( ( ) )
221
238
}
222
239
223
- pub fn getsockopt < T : Copy > ( sock : & Socket , level : c_int , option_name : c_int ) -> io:: Result < T > {
224
- unsafe {
225
- let mut option_value: T = mem:: zeroed ( ) ;
226
- let mut option_len = size_of :: < T > ( ) as c:: socklen_t ;
227
- cvt ( c:: getsockopt (
240
+ /// Gets the value of a socket option.
241
+ ///
242
+ /// # Safety
243
+ /// `T` must be the type associated with the given socket option.
244
+ pub unsafe fn getsockopt < T : Copy > (
245
+ sock : & Socket ,
246
+ level : c_int ,
247
+ option_name : c_int ,
248
+ ) -> io:: Result < T > {
249
+ let mut option_value = MaybeUninit :: < T > :: zeroed ( ) ;
250
+ let mut option_len = size_of :: < T > ( ) as c:: socklen_t ;
251
+
252
+ // SAFETY:
253
+ // * `sock` is opened for the duration of this call, as `sock` owns the socket.
254
+ // * the pointer to `option_value` is writable and the stack allocation has
255
+ // space for `size_of::<T>` bytes.
256
+ cvt ( unsafe {
257
+ c:: getsockopt (
228
258
sock. as_raw ( ) ,
229
259
level,
230
260
option_name,
231
- ( & raw mut option_value) as * mut _ ,
261
+ option_value. as_mut_ptr ( ) . cast ( ) ,
232
262
& mut option_len,
233
- ) ) ?;
234
- Ok ( option_value)
235
- }
236
- }
237
-
238
- fn sockname < F > ( f : F ) -> io:: Result < SocketAddr >
263
+ )
264
+ } ) ?;
265
+
266
+ // SAFETY: the `getsockopt` call succeeded and the caller guarantees that
267
+ // `T` is the type of this option, thus `option_value` must have
268
+ // been initialized by the system.
269
+ Ok ( unsafe { option_value. assume_init ( ) } )
270
+ }
271
+
272
+ /// Wraps a call to a platform function that returns a socket address.
273
+ ///
274
+ /// # Safety
275
+ /// * if `f` returns a success (i.e. `cvt` returns `Ok` when called on the
276
+ /// return value), the buffer provided to `f` must have been initialized
277
+ /// with a valid C socket address, the length of which must be written
278
+ /// to the second argument.
279
+ unsafe fn sockname < F > ( f : F ) -> io:: Result < SocketAddr >
239
280
where
240
281
F : FnOnce ( * mut c:: sockaddr , * mut c:: socklen_t ) -> c_int ,
241
282
{
242
- unsafe {
243
- let mut storage: c:: sockaddr_storage = mem:: zeroed ( ) ;
244
- let mut len = size_of_val ( & storage) as c:: socklen_t ;
245
- cvt ( f ( ( & raw mut storage) as * mut _ , & mut len) ) ?;
246
- socket_addr_from_c ( & storage, len as usize )
247
- }
283
+ let mut storage = MaybeUninit :: < c:: sockaddr_storage > :: zeroed ( ) ;
284
+ let mut len = size_of :: < c:: sockaddr_storage > ( ) as c:: socklen_t ;
285
+ cvt ( f ( storage. as_mut_ptr ( ) . cast ( ) , & mut len) ) ?;
286
+ // SAFETY:
287
+ // The caller guarantees that the storage has been successfully initialized
288
+ // and its size written to `len` if `f` returns a success.
289
+ unsafe { socket_addr_from_c ( storage. as_ptr ( ) , len as usize ) }
248
290
}
249
291
250
292
#[ cfg( target_os = "android" ) ]
@@ -546,8 +588,8 @@ impl TcpListener {
546
588
// The `accept` function will fill in the storage with the address,
547
589
// so we don't need to zero it here.
548
590
// reference: https://linux.die.net/man/2/accept4
549
- let mut storage: mem :: MaybeUninit < c:: sockaddr_storage > = mem :: MaybeUninit :: uninit ( ) ;
550
- let mut len = size_of_val ( & storage ) as c:: socklen_t ;
591
+ let mut storage = MaybeUninit :: < c:: sockaddr_storage > :: uninit ( ) ;
592
+ let mut len = size_of :: < c :: sockaddr_storage > ( ) as c:: socklen_t ;
551
593
let sock = self . inner . accept ( storage. as_mut_ptr ( ) as * mut _ , & mut len) ?;
552
594
let addr = unsafe { socket_addr_from_c ( storage. as_ptr ( ) , len as usize ) ? } ;
553
595
Ok ( ( TcpStream { inner : sock } , addr) )
0 commit comments