@@ -3,6 +3,7 @@ mod tests;
33
44use crate :: ffi:: { c_int, c_void} ;
55use crate :: io:: { self , BorrowedCursor , ErrorKind , IoSlice , IoSliceMut } ;
6+ use crate :: mem:: MaybeUninit ;
67use crate :: net:: {
78 Ipv4Addr , Ipv6Addr , Shutdown , SocketAddr , SocketAddrV4 , SocketAddrV6 , ToSocketAddrs ,
89} ;
@@ -177,6 +178,11 @@ fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) {
177178 }
178179}
179180
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`.
180186unsafe fn socket_addr_from_c (
181187 storage : * const c:: sockaddr_storage ,
182188 len : usize ,
@@ -202,49 +208,85 @@ unsafe fn socket_addr_from_c(
202208// sockaddr and misc bindings
203209////////////////////////////////////////////////////////////////////////////////
204210
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 > (
206216 sock : & Socket ,
207217 level : c_int ,
208218 option_name : c_int ,
209219 option_value : T ,
210220) -> 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 (
213230 sock. as_raw ( ) ,
214231 level,
215232 option_name,
216233 ( & 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 ( ( ) )
221238}
222239
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 (
228258 sock. as_raw ( ) ,
229259 level,
230260 option_name,
231- ( & raw mut option_value) as * mut _ ,
261+ option_value. as_mut_ptr ( ) . cast ( ) ,
232262 & 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 >
239280where
240281 F : FnOnce ( * mut c:: sockaddr , * mut c:: socklen_t ) -> c_int ,
241282{
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 ) }
248290}
249291
250292#[ cfg( target_os = "android" ) ]
@@ -546,8 +588,8 @@ impl TcpListener {
546588 // The `accept` function will fill in the storage with the address,
547589 // so we don't need to zero it here.
548590 // 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 ;
551593 let sock = self . inner . accept ( storage. as_mut_ptr ( ) as * mut _ , & mut len) ?;
552594 let addr = unsafe { socket_addr_from_c ( storage. as_ptr ( ) , len as usize ) ? } ;
553595 Ok ( ( TcpStream { inner : sock } , addr) )
0 commit comments