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}