diff --git a/src/sockref.rs b/src/sockref.rs index c00abf0c..d23b7c0f 100644 --- a/src/sockref.rs +++ b/src/sockref.rs @@ -3,9 +3,9 @@ use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::Deref; #[cfg(unix)] -use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::os::unix::io::{AsFd, AsRawFd, FromRawFd}; #[cfg(windows)] -use std::os::windows::io::{AsRawSocket, FromRawSocket}; +use std::os::windows::io::{AsRawSocket, AsSocket, FromRawSocket}; use crate::Socket; @@ -15,14 +15,13 @@ use crate::Socket; /// This allows for example a [`TcpStream`], found in the standard library, to /// be configured using all the additional methods found in the [`Socket`] API. /// -/// `SockRef` can be created from any socket type that implements [`AsRawFd`] -/// (Unix) or [`AsRawSocket`] (Windows) using the [`From`] implementation, but -/// the caller must ensure the file descriptor/socket is a valid. +/// `SockRef` can be created from any socket type that implements [`AsFd`] +/// (Unix) or [`AsSocket`] (Windows) using the [`From`] implementation. /// /// [`TcpStream`]: std::net::TcpStream // Don't use intra-doc links because they won't build on every platform. -/// [`AsRawFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsRawFd.html -/// [`AsRawSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsRawSocket.html +/// [`AsFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsFd.html +/// [`AsSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html /// /// # Examples /// @@ -59,29 +58,6 @@ use crate::Socket; /// # Ok(()) /// # } /// ``` -/// -/// Below is an example of **incorrect usage** of `SockRef::from`, which is -/// currently possible (but not intended and will be fixed in future versions). -/// -/// ```compile_fail -/// use socket2::SockRef; -/// -/// # fn main() -> Result<(), Box> { -/// /// THIS USAGE IS NOT VALID! -/// let socket_ref = SockRef::from(&123); -/// // The above line is overseen possibility when using `SockRef::from`, it -/// // uses the `RawFd` (on Unix), which is a type alias for `c_int`/`i32`, -/// // which implements `AsRawFd`. However it may be clear that this usage is -/// // invalid as it doesn't guarantee that `123` is a valid file descriptor. -/// -/// // Using `Socket::set_nodelay` now will call it on a file descriptor we -/// // don't own! We don't even not if the file descriptor is valid or a socket. -/// socket_ref.set_nodelay(true)?; -/// drop(socket_ref); -/// # Ok(()) -/// # } -/// # DO_NOT_COMPILE -/// ``` pub struct SockRef<'s> { /// Because this is a reference we don't own the `Socket`, however `Socket` /// closes itself when dropped, so we use `ManuallyDrop` to prevent it from @@ -100,16 +76,16 @@ impl<'s> Deref for SockRef<'s> { } } -/// On Windows, a corresponding `From<&impl AsRawSocket>` implementation exists. +/// On Windows, a corresponding `From<&impl AsSocket>` implementation exists. #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] impl<'s, S> From<&'s S> for SockRef<'s> where - S: AsRawFd, + S: AsFd, { /// The caller must ensure `S` is actually a socket. fn from(socket: &'s S) -> Self { - let fd = socket.as_raw_fd(); + let fd = socket.as_fd().as_raw_fd(); assert!(fd >= 0); SockRef { socket: ManuallyDrop::new(unsafe { Socket::from_raw_fd(fd) }), @@ -118,16 +94,16 @@ where } } -/// On Unix, a corresponding `From<&impl AsRawFd>` implementation exists. +/// On Unix, a corresponding `From<&impl AsFd>` implementation exists. #[cfg(windows)] #[cfg_attr(docsrs, doc(cfg(windows)))] impl<'s, S> From<&'s S> for SockRef<'s> where - S: AsRawSocket, + S: AsSocket, { - /// See the `From<&impl AsRawFd>` implementation. + /// See the `From<&impl AsFd>` implementation. fn from(socket: &'s S) -> Self { - let socket = socket.as_raw_socket(); + let socket = socket.as_socket().as_raw_socket(); assert!(socket != windows_sys::Win32::Networking::WinSock::INVALID_SOCKET as _); SockRef { socket: ManuallyDrop::new(unsafe { Socket::from_raw_socket(socket) }), diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 6411fec7..0911675b 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -37,7 +37,7 @@ use std::os::unix::ffi::OsStrExt; ) ))] use std::os::unix::io::RawFd; -use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}; #[cfg(feature = "all")] use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; #[cfg(feature = "all")] @@ -2012,6 +2012,14 @@ impl crate::Socket { } } +#[cfg_attr(docsrs, doc(cfg(unix)))] +impl AsFd for crate::Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + // SAFETY: lifetime is bound by self. + unsafe { BorrowedFd::borrow_raw(self.as_raw()) } + } +} + #[cfg_attr(docsrs, doc(cfg(unix)))] impl AsRawFd for crate::Socket { fn as_raw_fd(&self) -> c_int { @@ -2019,6 +2027,14 @@ impl AsRawFd for crate::Socket { } } +#[cfg_attr(docsrs, doc(cfg(unix)))] +impl From for OwnedFd { + fn from(sock: crate::Socket) -> OwnedFd { + // SAFETY: sock.into_raw() always returns a valid fd. + unsafe { OwnedFd::from_raw_fd(sock.into_raw()) } + } +} + #[cfg_attr(docsrs, doc(cfg(unix)))] impl IntoRawFd for crate::Socket { fn into_raw_fd(self) -> c_int { @@ -2026,6 +2042,14 @@ impl IntoRawFd for crate::Socket { } } +#[cfg_attr(docsrs, doc(cfg(unix)))] +impl From for crate::Socket { + fn from(fd: OwnedFd) -> crate::Socket { + // SAFETY: `OwnedFd` ensures the fd is valid. + unsafe { crate::Socket::from_raw_fd(fd.into_raw_fd()) } + } +} + #[cfg_attr(docsrs, doc(cfg(unix)))] impl FromRawFd for crate::Socket { unsafe fn from_raw_fd(fd: c_int) -> crate::Socket { diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 9ca6abdf..681325df 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -11,7 +11,9 @@ use std::io::{self, IoSlice}; use std::marker::PhantomData; use std::mem::{self, size_of, MaybeUninit}; use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; -use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; +use std::os::windows::io::{ + AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, +}; use std::sync::Once; use std::time::{Duration, Instant}; use std::{process, ptr, slice}; @@ -800,18 +802,45 @@ impl crate::Socket { } } +#[cfg_attr(docsrs, doc(cfg(windows)))] +impl AsSocket for crate::Socket { + fn as_socket(&self) -> BorrowedSocket<'_> { + // SAFETY: lifetime is bound by self. + unsafe { BorrowedSocket::borrow_raw(self.as_raw() as RawSocket) } + } +} + +#[cfg_attr(docsrs, doc(cfg(windows)))] impl AsRawSocket for crate::Socket { fn as_raw_socket(&self) -> RawSocket { self.as_raw() as RawSocket } } +#[cfg_attr(docsrs, doc(cfg(windows)))] +impl From for OwnedSocket { + fn from(sock: crate::Socket) -> OwnedSocket { + // SAFETY: sock.into_raw() always returns a valid fd. + unsafe { OwnedSocket::from_raw_socket(sock.into_raw() as RawSocket) } + } +} + +#[cfg_attr(docsrs, doc(cfg(windows)))] impl IntoRawSocket for crate::Socket { fn into_raw_socket(self) -> RawSocket { self.into_raw() as RawSocket } } +#[cfg_attr(docsrs, doc(cfg(windows)))] +impl From for crate::Socket { + fn from(fd: OwnedSocket) -> crate::Socket { + // SAFETY: `OwnedFd` ensures the fd is valid. + unsafe { crate::Socket::from_raw_socket(fd.into_raw_socket()) } + } +} + +#[cfg_attr(docsrs, doc(cfg(windows)))] impl FromRawSocket for crate::Socket { unsafe fn from_raw_socket(socket: RawSocket) -> crate::Socket { crate::Socket::from_raw(socket as Socket)