base/
descriptor.rs

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