blob: 5c1634084a055b31381849b8fc5085d47da89330 [file] [log] [blame]
//! Owned and borrowed OS sockets.
#![stable(feature = "io_safety", since = "1.63.0")]
use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
use crate::mem;
use crate::mem::forget;
use crate::sys;
use crate::sys::c;
#[cfg(not(target_vendor = "uwp"))]
use crate::sys::cvt;
/// A borrowed socket.
///
/// This has a lifetime parameter to tie it to the lifetime of something that
/// owns the socket.
///
/// This uses `repr(transparent)` and has the representation of a host socket,
/// so it can be used in FFI in places where a socket is passed as an argument,
/// it is not captured or consumed, and it never has the value
/// `INVALID_SOCKET`.
///
/// This type's `.to_owned()` implementation returns another `BorrowedSocket`
/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw
/// socket, which is then borrowed under the same lifetime.
#[derive(Copy, Clone)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
#[cfg_attr(
target_pointer_width = "64",
rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
)]
#[rustc_nonnull_optimization_guaranteed]
#[stable(feature = "io_safety", since = "1.63.0")]
pub struct BorrowedSocket<'socket> {
socket: RawSocket,
_phantom: PhantomData<&'socket OwnedSocket>,
}
/// An owned socket.
///
/// This closes the socket on drop.
///
/// This uses `repr(transparent)` and has the representation of a host socket,
/// so it can be used in FFI in places where a socket is passed as a consumed
/// argument or returned as an owned value, and it never has the value
/// `INVALID_SOCKET`.
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
#[cfg_attr(
target_pointer_width = "64",
rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
)]
#[rustc_nonnull_optimization_guaranteed]
#[stable(feature = "io_safety", since = "1.63.0")]
pub struct OwnedSocket {
socket: RawSocket,
}
impl BorrowedSocket<'_> {
/// Return a `BorrowedSocket` holding the given raw socket.
///
/// # Safety
///
/// The resource pointed to by `raw` must remain open for the duration of
/// the returned `BorrowedSocket`, and it must not have the value
/// `INVALID_SOCKET`.
#[inline]
#[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
#[stable(feature = "io_safety", since = "1.63.0")]
pub const unsafe fn borrow_raw(socket: RawSocket) -> Self {
assert!(socket != c::INVALID_SOCKET as RawSocket);
Self { socket, _phantom: PhantomData }
}
}
impl OwnedSocket {
/// Creates a new `OwnedSocket` instance that shares the same underlying
/// object as the existing `OwnedSocket` instance.
#[stable(feature = "io_safety", since = "1.63.0")]
pub fn try_clone(&self) -> io::Result<Self> {
self.as_socket().try_clone_to_owned()
}
// FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-;
#[allow(fuzzy_provenance_casts)]
#[cfg(not(target_vendor = "uwp"))]
pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
cvt(unsafe {
c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
})
.map(drop)
}
#[cfg(target_vendor = "uwp")]
pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP"))
}
}
impl BorrowedSocket<'_> {
/// Creates a new `OwnedSocket` instance that shares the same underlying
/// object as the existing `BorrowedSocket` instance.
#[stable(feature = "io_safety", since = "1.63.0")]
pub fn try_clone_to_owned(&self) -> io::Result<OwnedSocket> {
let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
let result = unsafe {
c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
};
sys::net::cvt(result)?;
let socket = unsafe {
c::WSASocketW(
info.iAddressFamily,
info.iSocketType,
info.iProtocol,
&mut info,
0,
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
)
};
if socket != c::INVALID_SOCKET {
unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
} else {
let error = unsafe { c::WSAGetLastError() };
if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
return Err(io::Error::from_raw_os_error(error));
}
let socket = unsafe {
c::WSASocketW(
info.iAddressFamily,
info.iSocketType,
info.iProtocol,
&mut info,
0,
c::WSA_FLAG_OVERLAPPED,
)
};
if socket == c::INVALID_SOCKET {
return Err(last_error());
}
unsafe {
let socket = OwnedSocket::from_raw_socket(socket);
socket.set_no_inherit()?;
Ok(socket)
}
}
}
}
/// Returns the last error from the Windows socket interface.
fn last_error() -> io::Error {
io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawSocket for BorrowedSocket<'_> {
#[inline]
fn as_raw_socket(&self) -> RawSocket {
self.socket
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawSocket for OwnedSocket {
#[inline]
fn as_raw_socket(&self) -> RawSocket {
self.socket
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl IntoRawSocket for OwnedSocket {
#[inline]
fn into_raw_socket(self) -> RawSocket {
let socket = self.socket;
forget(self);
socket
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl FromRawSocket for OwnedSocket {
#[inline]
unsafe fn from_raw_socket(socket: RawSocket) -> Self {
debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
Self { socket }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl Drop for OwnedSocket {
#[inline]
fn drop(&mut self) {
unsafe {
let _ = c::closesocket(self.socket);
}
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl fmt::Debug for BorrowedSocket<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowedSocket").field("socket", &self.socket).finish()
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl fmt::Debug for OwnedSocket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedSocket").field("socket", &self.socket).finish()
}
}
/// A trait to borrow the socket from an underlying object.
#[stable(feature = "io_safety", since = "1.63.0")]
pub trait AsSocket {
/// Borrows the socket.
#[stable(feature = "io_safety", since = "1.63.0")]
fn as_socket(&self) -> BorrowedSocket<'_>;
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl<T: AsSocket> AsSocket for &T {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
T::as_socket(self)
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl<T: AsSocket> AsSocket for &mut T {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
T::as_socket(self)
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsSocket for BorrowedSocket<'_> {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
*self
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsSocket for OwnedSocket {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
// Safety: `OwnedSocket` and `BorrowedSocket` have the same validity
// invariants, and the `BorrowdSocket` is bounded by the lifetime
// of `&self`.
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsSocket for crate::net::TcpStream {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::TcpStream> for OwnedSocket {
#[inline]
fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedSocket> for crate::net::TcpStream {
#[inline]
fn from(owned: OwnedSocket) -> Self {
unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsSocket for crate::net::TcpListener {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::TcpListener> for OwnedSocket {
#[inline]
fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedSocket> for crate::net::TcpListener {
#[inline]
fn from(owned: OwnedSocket) -> Self {
unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsSocket for crate::net::UdpSocket {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::UdpSocket> for OwnedSocket {
#[inline]
fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedSocket> for crate::net::UdpSocket {
#[inline]
fn from(owned: OwnedSocket) -> Self {
unsafe { Self::from_raw_socket(owned.into_raw_socket()) }
}
}