Skip to content

Commit eba1416

Browse files
committed
std: improve internal socket functions
1 parent d615d2f commit eba1416

File tree

1 file changed

+69
-27
lines changed
  • library/std/src/sys/net/connection/socket

1 file changed

+69
-27
lines changed

library/std/src/sys/net/connection/socket/mod.rs

Lines changed: 69 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod tests;
33

44
use crate::ffi::{c_int, c_void};
55
use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
6+
use crate::mem::MaybeUninit;
67
use 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`.
180186
unsafe 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>
239280
where
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

Comments
 (0)