summaryrefslogtreecommitdiffstats
path: root/library/std/src/os/solid/io.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /library/std/src/os/solid/io.rs
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/std/src/os/solid/io.rs')
-rw-r--r--library/std/src/os/solid/io.rs300
1 files changed, 297 insertions, 3 deletions
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index f82034663..19b4fe220 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -1,8 +1,55 @@
//! SOLID-specific extensions to general I/O primitives
+//!
+//! Just like raw pointers, raw SOLID Sockets file descriptors point to
+//! resources with dynamic lifetimes, and they can dangle if they outlive their
+//! resources or be forged if they're created from invalid values.
+//!
+//! This module provides three types for representing raw file descriptors
+//! with different ownership properties: raw, borrowed, and owned, which are
+//! analogous to types used for representing pointers:
+//!
+//! | Type | Analogous to |
+//! | ------------------ | ------------ |
+//! | [`RawFd`] | `*const _` |
+//! | [`BorrowedFd<'a>`] | `&'a _` |
+//! | [`OwnedFd`] | `Box<_>` |
+//!
+//! Like raw pointers, `RawFd` values are primitive values. And in new code,
+//! they should be considered unsafe to do I/O on (analogous to dereferencing
+//! them). Rust did not always provide this guidance, so existing code in the
+//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
+//! `io_safety` feature is stable, libraries will be encouraged to migrate,
+//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
+//! using to `BorrowedFd` or `OwnedFd` instead.
+//!
+//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure
+//! that they don't outlive the resource they point to. These are safe to
+//! use. `BorrowedFd` values may be used in APIs which provide safe access to
+//! any system call except for:
+//!
+//! - `close`, because that would end the dynamic lifetime of the resource
+//! without ending the lifetime of the file descriptor.
+//!
+//! - `dup2`/`dup3`, in the second argument, because this argument is
+//! closed and assigned a new resource, which may break the assumptions
+//! other code using that file descriptor.
+//!
+//! `BorrowedFd` values may be used in APIs which provide safe access to `dup`
+//! system calls, so types implementing `AsFd` or `From<OwnedFd>` should not
+//! assume they always have exclusive access to the underlying file
+//! description.
+//!
+//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
+//! and free (close) it when they are dropped.
+//!
+//! [`BorrowedFd<'a>`]: crate::os::solid::io::BorrowedFd
#![deny(unsafe_op_in_unsafe_fn)]
#![unstable(feature = "solid_ext", issue = "none")]
+use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::forget;
use crate::net;
use crate::sys;
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
@@ -10,6 +57,253 @@ use crate::sys_common::{self, AsInner, FromInner, IntoInner};
/// Raw file descriptors.
pub type RawFd = i32;
+/// A borrowed SOLID Sockets file descriptor.
+///
+/// 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 file
+/// descriptor, 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
+/// `SOLID_NET_INVALID_FD`.
+///
+/// This type's `.to_owned()` implementation returns another `BorrowedFd`
+/// rather than an `OwnedFd`. 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 `SOLID_NET_INVALID_FD`.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[rustc_nonnull_optimization_guaranteed]
+pub struct BorrowedFd<'socket> {
+ fd: RawFd,
+ _phantom: PhantomData<&'socket OwnedFd>,
+}
+
+/// An owned SOLID Sockets file descriptor.
+///
+/// This closes the file descriptor on drop.
+///
+/// This uses `repr(transparent)` and has the representation of a host file
+/// descriptor, 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
+/// `SOLID_NET_INVALID_FD`.
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[rustc_nonnull_optimization_guaranteed]
+pub struct OwnedFd {
+ fd: RawFd,
+}
+
+impl BorrowedFd<'_> {
+ /// Return a `BorrowedFd` holding the given raw file descriptor.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `fd` must remain open for the duration of
+ /// the returned `BorrowedFd`, and it must not have the value
+ /// `SOLID_NET_INVALID_FD`.
+ #[inline]
+ pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
+ assert!(fd != -1 as RawFd);
+ // SAFETY: we just asserted that the value is in the valid range and
+ // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+ unsafe { Self { fd, _phantom: PhantomData } }
+ }
+}
+
+impl OwnedFd {
+ /// Creates a new `OwnedFd` instance that shares the same underlying file
+ /// description as the existing `OwnedFd` instance.
+ pub fn try_clone(&self) -> crate::io::Result<Self> {
+ self.as_fd().try_clone_to_owned()
+ }
+}
+
+impl BorrowedFd<'_> {
+ /// Creates a new `OwnedFd` instance that shares the same underlying file
+ /// description as the existing `BorrowedFd` instance.
+ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
+ let fd = sys::net::cvt(unsafe { sys::net::netc::dup(self.as_raw_fd()) })?;
+ Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+ }
+}
+
+impl AsRawFd for BorrowedFd<'_> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd
+ }
+}
+
+impl AsRawFd for OwnedFd {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd
+ }
+}
+
+impl IntoRawFd for OwnedFd {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ let fd = self.fd;
+ forget(self);
+ fd
+ }
+}
+
+impl FromRawFd for OwnedFd {
+ /// Constructs a new instance of `Self` from the given raw file descriptor.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `fd` must be open and suitable for assuming
+ /// ownership. The resource must not require any cleanup other than `close`.
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self {
+ assert_ne!(fd, -1 as RawFd);
+ // SAFETY: we just asserted that the value is in the valid range and
+ // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+ unsafe { Self { fd } }
+ }
+}
+
+impl Drop for OwnedFd {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { sys::net::netc::close(self.fd) };
+ }
+}
+
+impl fmt::Debug for BorrowedFd<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
+ }
+}
+
+impl fmt::Debug for OwnedFd {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
+ }
+}
+
+macro_rules! impl_is_terminal {
+ ($($t:ty),*$(,)?) => {$(
+ #[unstable(feature = "sealed", issue = "none")]
+ impl crate::sealed::Sealed for $t {}
+
+ #[stable(feature = "is_terminal", since = "1.70.0")]
+ impl crate::io::IsTerminal for $t {
+ #[inline]
+ fn is_terminal(&self) -> bool {
+ crate::sys::io::is_terminal(self)
+ }
+ }
+ )*}
+}
+
+impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
+
+/// A trait to borrow the SOLID Sockets file descriptor from an underlying
+/// object.
+pub trait AsFd {
+ /// Borrows the file descriptor.
+ fn as_fd(&self) -> BorrowedFd<'_>;
+}
+
+impl<T: AsFd> AsFd for &T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+impl<T: AsFd> AsFd for &mut T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+impl AsFd for BorrowedFd<'_> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ *self
+ }
+}
+
+impl AsFd for OwnedFd {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ // Safety: `OwnedFd` and `BorrowedFd` have the same validity
+ // invariants, and the `BorrowedFd` is bounded by the lifetime
+ // of `&self`.
+ unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
+ }
+}
+
+macro_rules! impl_owned_fd_traits {
+ ($($t:ident)*) => {$(
+ impl AsFd for net::$t {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().socket().as_fd()
+ }
+ }
+
+ impl From<net::$t> for OwnedFd {
+ #[inline]
+ fn from(socket: net::$t) -> OwnedFd {
+ socket.into_inner().into_socket().into_inner()
+ }
+ }
+
+ impl From<OwnedFd> for net::$t {
+ #[inline]
+ fn from(owned_fd: OwnedFd) -> Self {
+ Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
+ }
+ }
+ )*};
+}
+impl_owned_fd_traits! { TcpStream TcpListener UdpSocket }
+
+/// This impl allows implementing traits that require `AsFd` on Arc.
+/// ```
+/// # #[cfg(target_os = "solid_asp3")] mod group_cfg {
+/// # use std::os::solid::io::AsFd;
+/// use std::net::UdpSocket;
+/// use std::sync::Arc;
+///
+/// trait MyTrait: AsFd {}
+/// impl MyTrait for Arc<UdpSocket> {}
+/// impl MyTrait for Box<UdpSocket> {}
+/// # }
+/// ```
+impl<T: AsFd> AsFd for crate::sync::Arc<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
+impl<T: AsFd> AsFd for crate::rc::Rc<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
+impl<T: AsFd> AsFd for Box<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
/// A trait to extract the raw SOLID Sockets file descriptor from an underlying
/// object.
pub trait AsRawFd {
@@ -84,7 +378,7 @@ macro_rules! impl_as_raw_fd {
impl AsRawFd for net::$t {
#[inline]
fn as_raw_fd(&self) -> RawFd {
- *self.as_inner().socket().as_inner()
+ self.as_inner().socket().as_raw_fd()
}
}
)*};
@@ -97,7 +391,7 @@ macro_rules! impl_from_raw_fd {
impl FromRawFd for net::$t {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
- let socket = sys::net::Socket::from_inner(fd);
+ let socket = unsafe { sys::net::Socket::from_raw_fd(fd) };
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
}
}
@@ -111,7 +405,7 @@ macro_rules! impl_into_raw_fd {
impl IntoRawFd for net::$t {
#[inline]
fn into_raw_fd(self) -> RawFd {
- self.into_inner().into_socket().into_inner()
+ self.into_inner().into_socket().into_raw_fd()
}
}
)*};