• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 use std::fs::File;
6 use std::mem;
7 use std::mem::ManuallyDrop;
8 use std::sync::Arc;
9 
10 use serde::Deserialize;
11 use serde::Serialize;
12 
13 use crate::EventToken;
14 use crate::RawDescriptor;
15 
16 /// Wraps a RawDescriptor and safely closes it when self falls out of scope.
17 #[derive(Serialize, Deserialize, Debug, Eq)]
18 #[serde(transparent)]
19 pub struct SafeDescriptor {
20     #[serde(with = "super::with_raw_descriptor")]
21     pub(crate) descriptor: RawDescriptor,
22 }
23 
24 /// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
25 pub trait IntoRawDescriptor {
into_raw_descriptor(self) -> RawDescriptor26     fn into_raw_descriptor(self) -> RawDescriptor;
27 }
28 
29 /// Trait for returning the underlying raw descriptor, without giving up ownership of the
30 /// descriptor.
31 pub 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 will
35     /// remain open for longer than the immediate call of this method. In particular, it is a
36     /// dangerous practice to store the result of this method for future use: instead, it should be
37     /// 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 reliably
40     /// track the lifetime of the providing object), you should probably consider using
41     /// [`SafeDescriptor`] (possibly along with [`trait@IntoRawDescriptor`]) to get full ownership
42     /// over a descriptor pointing to the same resource.
as_raw_descriptor(&self) -> RawDescriptor43     fn as_raw_descriptor(&self) -> RawDescriptor;
44 }
45 
46 /// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.
47 pub trait AsRawDescriptors {
48     /// Returns the underlying raw descriptors.
49     ///
50     /// Please refer to the documentation of [`AsRawDescriptor::as_raw_descriptor`] for limitations
51     /// and recommended use.
as_raw_descriptors(&self) -> Vec<RawDescriptor>52     fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;
53 }
54 
55 pub trait FromRawDescriptor {
56     /// # Safety
57     /// Safe only if the caller ensures nothing has access to the descriptor after passing it to
58     /// `from_raw_descriptor`
from_raw_descriptor(descriptor: RawDescriptor) -> Self59     unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
60 }
61 
62 impl AsRawDescriptor for SafeDescriptor {
as_raw_descriptor(&self) -> RawDescriptor63     fn as_raw_descriptor(&self) -> RawDescriptor {
64         self.descriptor
65     }
66 }
67 
68 impl<T> AsRawDescriptor for Arc<T>
69 where
70     T: AsRawDescriptor,
71 {
as_raw_descriptor(&self) -> RawDescriptor72     fn as_raw_descriptor(&self) -> RawDescriptor {
73         self.as_ref().as_raw_descriptor()
74     }
75 }
76 
77 impl<T> AsRawDescriptors for T
78 where
79     T: AsRawDescriptor,
80 {
as_raw_descriptors(&self) -> Vec<RawDescriptor>81     fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
82         vec![self.as_raw_descriptor()]
83     }
84 }
85 
86 impl IntoRawDescriptor for SafeDescriptor {
into_raw_descriptor(self) -> RawDescriptor87     fn into_raw_descriptor(self) -> RawDescriptor {
88         let descriptor = self.descriptor;
89         mem::forget(self);
90         descriptor
91     }
92 }
93 
94 impl FromRawDescriptor for SafeDescriptor {
from_raw_descriptor(descriptor: RawDescriptor) -> Self95     unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
96         SafeDescriptor { descriptor }
97     }
98 }
99 
100 impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
101     type Error = std::io::Error;
102 
103     /// 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 this
106     /// function on IO completion ports, sockets, or pseudo-handles (except those from
107     /// GetCurrentProcess or GetCurrentThread). See
108     /// <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 some
112     /// adjustments to smooth those edges.
try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error>113     fn 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 of
118         // its existence after this function returns.
119         let rd_as_safe_desc = ManuallyDrop::new(unsafe {
120             SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
121         });
122 
123         // We have to clone rd because we have no guarantee ownership was transferred (rd is
124         // borrowed).
125         rd_as_safe_desc
126             .try_clone()
127             .map_err(|e| Self::Error::from_raw_os_error(e.errno()))
128     }
129 }
130 
131 impl From<File> for SafeDescriptor {
from(f: File) -> SafeDescriptor132     fn from(f: File) -> SafeDescriptor {
133         // SAFETY:
134         // Safe because we own the File at this point.
135         unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
136     }
137 }
138 
139 /// 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 the
143 /// responsibility of the user to ensure that the wrapped descriptor will not be closed for as long
144 /// as the `Descriptor` is alive.
145 ///
146 /// Most use-cases should prefer [`SafeDescriptor`] or implementing and using
147 /// [`trait@AsRawDescriptor`] on the type providing the descriptor. Using this wrapper usually means
148 /// 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 implements
152 ///   [`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 case
155 ///   where your descriptor gets closed.
156 ///
157 /// Note that with the exception of the last use-case (which requires proper error checking against
158 /// the descriptor being closed), the `Descriptor` instance would be very short-lived.
159 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
160 #[repr(transparent)]
161 pub struct Descriptor(pub RawDescriptor);
162 impl AsRawDescriptor for Descriptor {
as_raw_descriptor(&self) -> RawDescriptor163     fn as_raw_descriptor(&self) -> RawDescriptor {
164         self.0
165     }
166 }
167 impl FromRawDescriptor for Descriptor {
from_raw_descriptor(desc: RawDescriptor) -> Self168     unsafe fn from_raw_descriptor(desc: RawDescriptor) -> Self {
169         Descriptor(desc)
170     }
171 }
172 
173 /// Implement token for implementations that wish to use this struct as such
174 impl EventToken for Descriptor {
as_raw_token(&self) -> u64175     fn as_raw_token(&self) -> u64 {
176         self.0 as u64
177     }
178 
from_raw_token(data: u64) -> Self179     fn from_raw_token(data: u64) -> Self {
180         Descriptor(data as RawDescriptor)
181     }
182 }
183