1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::fs::File;
use std::mem;
use std::mem::ManuallyDrop;
use std::sync::Arc;
use serde::Deserialize;
use serde::Serialize;
use serde::Serializer;
use crate::EventToken;
use crate::RawDescriptor;
/// Wraps a RawDescriptor and safely closes it when self falls out of scope.
#[derive(Serialize, Deserialize, Debug, Eq)]
#[serde(transparent)]
pub struct SafeDescriptor {
#[serde(with = "super::with_raw_descriptor")]
pub(crate) descriptor: RawDescriptor,
}
/// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
pub trait IntoRawDescriptor {
fn into_raw_descriptor(self) -> RawDescriptor;
}
/// Trait for returning the underlying raw descriptor, without giving up ownership of the
/// descriptor.
pub trait AsRawDescriptor {
/// Returns the underlying raw descriptor.
///
/// Since the descriptor is still owned by the provider, callers should not assume that it will
/// remain open for longer than the immediate call of this method. In particular, it is a
/// dangerous practice to store the result of this method for future use: instead, it should be
/// used to e.g. obtain a raw descriptor that is immediately passed to a system call.
///
/// If you need to use the descriptor for a longer time (and particularly if you cannot reliably
/// track the lifetime of the providing object), you should probably consider using
/// [`SafeDescriptor`] (possibly along with [`trait@IntoRawDescriptor`]) to get full ownership
/// over a descriptor pointing to the same resource.
fn as_raw_descriptor(&self) -> RawDescriptor;
}
/// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.
pub trait AsRawDescriptors {
/// Returns the underlying raw descriptors.
///
/// Please refer to the documentation of [`AsRawDescriptor::as_raw_descriptor`] for limitations
/// and recommended use.
fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;
}
pub trait FromRawDescriptor {
/// # Safety
/// Safe only if the caller ensures nothing has access to the descriptor after passing it to
/// `from_raw_descriptor`
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
}
impl AsRawDescriptor for SafeDescriptor {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.descriptor
}
}
impl<T> AsRawDescriptor for Arc<T>
where
T: AsRawDescriptor,
{
fn as_raw_descriptor(&self) -> RawDescriptor {
self.as_ref().as_raw_descriptor()
}
}
impl<T> AsRawDescriptors for T
where
T: AsRawDescriptor,
{
fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
vec![self.as_raw_descriptor()]
}
}
impl IntoRawDescriptor for SafeDescriptor {
fn into_raw_descriptor(self) -> RawDescriptor {
let descriptor = self.descriptor;
mem::forget(self);
descriptor
}
}
impl FromRawDescriptor for SafeDescriptor {
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
SafeDescriptor { descriptor }
}
}
impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
type Error = std::io::Error;
/// Clones the underlying descriptor (handle), internally creating a new descriptor.
///
/// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this
/// function on IO completion ports, sockets, or pseudo-handles (except those from
/// GetCurrentProcess or GetCurrentThread). See
/// <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle>
/// for further details.
///
/// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some
/// adjustments to smooth those edges.
fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {
// SAFETY:
// Safe because the underlying raw descriptor is guaranteed valid by rd's existence.
//
// Note that we are cloning the underlying raw descriptor since we have no guarantee of
// its existence after this function returns.
let rd_as_safe_desc = ManuallyDrop::new(unsafe {
SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
});
// We have to clone rd because we have no guarantee ownership was transferred (rd is
// borrowed).
rd_as_safe_desc
.try_clone()
.map_err(|e| Self::Error::from_raw_os_error(e.errno()))
}
}
impl From<File> for SafeDescriptor {
fn from(f: File) -> SafeDescriptor {
// SAFETY:
// Safe because we own the File at this point.
unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
}
}
/// For use cases where a simple wrapper around a [`RawDescriptor`] is needed, in order to e.g.
/// implement [`trait@AsRawDescriptor`].
///
/// This is a simply a wrapper and does not manage the lifetime of the descriptor. As such it is the
/// responsibility of the user to ensure that the wrapped descriptor will not be closed for as long
/// as the `Descriptor` is alive.
///
/// Most use-cases should prefer [`SafeDescriptor`] or implementing and using
/// [`trait@AsRawDescriptor`] on the type providing the descriptor. Using this wrapper usually means
/// something can be improved in your code.
///
/// Valid uses of this struct include:
/// * You only have a valid [`RawDescriptor`] and need to pass something that implements
/// [`trait@AsRawDescriptor`] to a function,
/// * You need to serialize a [`RawDescriptor`],
/// * You need [`trait@Send`] or [`trait@Sync`] for your descriptor and properly handle the case
/// where your descriptor gets closed.
///
/// Note that with the exception of the last use-case (which requires proper error checking against
/// the descriptor being closed), the `Descriptor` instance would be very short-lived.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Descriptor(pub RawDescriptor);
impl AsRawDescriptor for Descriptor {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.0
}
}
impl FromRawDescriptor for Descriptor {
unsafe fn from_raw_descriptor(desc: RawDescriptor) -> Self {
Descriptor(desc)
}
}
/// Implement token for implementations that wish to use this struct as such
impl EventToken for Descriptor {
fn as_raw_token(&self) -> u64 {
self.0 as u64
}
fn from_raw_token(data: u64) -> Self {
Descriptor(data as RawDescriptor)
}
}
impl Serialize for Descriptor {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u64(self.0 as u64)
}
}
impl<'de> Deserialize<'de> for Descriptor {
fn deserialize<D>(deserializer: D) -> Result<Descriptor, D::Error>
where
D: serde::Deserializer<'de>,
{
u64::deserialize(deserializer).map(|data| Descriptor(data as RawDescriptor))
}
}