// Copyright 2022 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::fs::File;5use std::mem;6use std::mem::ManuallyDrop;7use std::sync::Arc;89use serde::Deserialize;10use serde::Serialize;11use serde::Serializer;1213use crate::EventToken;14use crate::RawDescriptor;1516/// Wraps a RawDescriptor and safely closes it when self falls out of scope.17#[derive(Serialize, Deserialize, Debug, Eq)]18#[serde(transparent)]19pub struct SafeDescriptor {20#[serde(with = "super::with_raw_descriptor")]21pub(crate) descriptor: RawDescriptor,22}2324/// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor25pub trait IntoRawDescriptor {26fn into_raw_descriptor(self) -> RawDescriptor;27}2829/// Trait for returning the underlying raw descriptor, without giving up ownership of the30/// descriptor.31pub trait AsRawDescriptor {32/// Returns the underlying raw descriptor.33///34/// Since the descriptor is still owned by the provider, callers should not assume that it will35/// remain open for longer than the immediate call of this method. In particular, it is a36/// dangerous practice to store the result of this method for future use: instead, it should be37/// used to e.g. obtain a raw descriptor that is immediately passed to a system call.38///39/// If you need to use the descriptor for a longer time (and particularly if you cannot reliably40/// track the lifetime of the providing object), you should probably consider using41/// [`SafeDescriptor`] (possibly along with [`trait@IntoRawDescriptor`]) to get full ownership42/// over a descriptor pointing to the same resource.43fn as_raw_descriptor(&self) -> RawDescriptor;44}4546/// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.47pub trait AsRawDescriptors {48/// Returns the underlying raw descriptors.49///50/// Please refer to the documentation of [`AsRawDescriptor::as_raw_descriptor`] for limitations51/// and recommended use.52fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;53}5455pub trait FromRawDescriptor {56/// # Safety57/// Safe only if the caller ensures nothing has access to the descriptor after passing it to58/// `from_raw_descriptor`59unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;60}6162impl AsRawDescriptor for SafeDescriptor {63fn as_raw_descriptor(&self) -> RawDescriptor {64self.descriptor65}66}6768impl<T> AsRawDescriptor for Arc<T>69where70T: AsRawDescriptor,71{72fn as_raw_descriptor(&self) -> RawDescriptor {73self.as_ref().as_raw_descriptor()74}75}7677impl<T> AsRawDescriptors for T78where79T: AsRawDescriptor,80{81fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {82vec![self.as_raw_descriptor()]83}84}8586impl IntoRawDescriptor for SafeDescriptor {87fn into_raw_descriptor(self) -> RawDescriptor {88let descriptor = self.descriptor;89mem::forget(self);90descriptor91}92}9394impl FromRawDescriptor for SafeDescriptor {95unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {96SafeDescriptor { descriptor }97}98}99100impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {101type Error = std::io::Error;102103/// Clones the underlying descriptor (handle), internally creating a new descriptor.104///105/// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this106/// function on IO completion ports, sockets, or pseudo-handles (except those from107/// GetCurrentProcess or GetCurrentThread). See108/// <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle>109/// for further details.110///111/// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some112/// adjustments to smooth those edges.113fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {114// SAFETY:115// Safe because the underlying raw descriptor is guaranteed valid by rd's existence.116//117// Note that we are cloning the underlying raw descriptor since we have no guarantee of118// its existence after this function returns.119let rd_as_safe_desc = ManuallyDrop::new(unsafe {120SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())121});122123// We have to clone rd because we have no guarantee ownership was transferred (rd is124// borrowed).125rd_as_safe_desc126.try_clone()127.map_err(|e| Self::Error::from_raw_os_error(e.errno()))128}129}130131impl From<File> for SafeDescriptor {132fn from(f: File) -> SafeDescriptor {133// SAFETY:134// Safe because we own the File at this point.135unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }136}137}138139/// For use cases where a simple wrapper around a [`RawDescriptor`] is needed, in order to e.g.140/// implement [`trait@AsRawDescriptor`].141///142/// This is a simply a wrapper and does not manage the lifetime of the descriptor. As such it is the143/// responsibility of the user to ensure that the wrapped descriptor will not be closed for as long144/// as the `Descriptor` is alive.145///146/// Most use-cases should prefer [`SafeDescriptor`] or implementing and using147/// [`trait@AsRawDescriptor`] on the type providing the descriptor. Using this wrapper usually means148/// something can be improved in your code.149///150/// Valid uses of this struct include:151/// * You only have a valid [`RawDescriptor`] and need to pass something that implements152/// [`trait@AsRawDescriptor`] to a function,153/// * You need to serialize a [`RawDescriptor`],154/// * You need [`trait@Send`] or [`trait@Sync`] for your descriptor and properly handle the case155/// where your descriptor gets closed.156///157/// Note that with the exception of the last use-case (which requires proper error checking against158/// the descriptor being closed), the `Descriptor` instance would be very short-lived.159#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]160#[repr(transparent)]161pub struct Descriptor(pub RawDescriptor);162impl AsRawDescriptor for Descriptor {163fn as_raw_descriptor(&self) -> RawDescriptor {164self.0165}166}167impl FromRawDescriptor for Descriptor {168unsafe fn from_raw_descriptor(desc: RawDescriptor) -> Self {169Descriptor(desc)170}171}172173/// Implement token for implementations that wish to use this struct as such174impl EventToken for Descriptor {175fn as_raw_token(&self) -> u64 {176self.0 as u64177}178179fn from_raw_token(data: u64) -> Self {180Descriptor(data as RawDescriptor)181}182}183184impl Serialize for Descriptor {185fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>186where187S: Serializer,188{189serializer.serialize_u64(self.0 as u64)190}191}192193impl<'de> Deserialize<'de> for Descriptor {194fn deserialize<D>(deserializer: D) -> Result<Descriptor, D::Error>195where196D: serde::Deserializer<'de>,197{198u64::deserialize(deserializer).map(|data| Descriptor(data as RawDescriptor))199}200}201202203