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 use serde::Serializer; 13 14 use crate::EventToken; 15 use 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)] 20 pub 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 26 pub trait IntoRawDescriptor { into_raw_descriptor(self) -> RawDescriptor27 fn into_raw_descriptor(self) -> RawDescriptor; 28 } 29 30 /// Trait for returning the underlying raw descriptor, without giving up ownership of the 31 /// descriptor. 32 pub 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. as_raw_descriptor(&self) -> RawDescriptor44 fn as_raw_descriptor(&self) -> RawDescriptor; 45 } 46 47 /// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors. 48 pub 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. as_raw_descriptors(&self) -> Vec<RawDescriptor>53 fn as_raw_descriptors(&self) -> Vec<RawDescriptor>; 54 } 55 56 pub 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` from_raw_descriptor(descriptor: RawDescriptor) -> Self60 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self; 61 } 62 63 impl AsRawDescriptor for SafeDescriptor { as_raw_descriptor(&self) -> RawDescriptor64 fn as_raw_descriptor(&self) -> RawDescriptor { 65 self.descriptor 66 } 67 } 68 69 impl<T> AsRawDescriptor for Arc<T> 70 where 71 T: AsRawDescriptor, 72 { as_raw_descriptor(&self) -> RawDescriptor73 fn as_raw_descriptor(&self) -> RawDescriptor { 74 self.as_ref().as_raw_descriptor() 75 } 76 } 77 78 impl<T> AsRawDescriptors for T 79 where 80 T: AsRawDescriptor, 81 { as_raw_descriptors(&self) -> Vec<RawDescriptor>82 fn as_raw_descriptors(&self) -> Vec<RawDescriptor> { 83 vec![self.as_raw_descriptor()] 84 } 85 } 86 87 impl IntoRawDescriptor for SafeDescriptor { into_raw_descriptor(self) -> RawDescriptor88 fn into_raw_descriptor(self) -> RawDescriptor { 89 let descriptor = self.descriptor; 90 mem::forget(self); 91 descriptor 92 } 93 } 94 95 impl FromRawDescriptor for SafeDescriptor { from_raw_descriptor(descriptor: RawDescriptor) -> Self96 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self { 97 SafeDescriptor { descriptor } 98 } 99 } 100 101 impl 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. try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error>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 132 impl From<File> for SafeDescriptor { from(f: File) -> SafeDescriptor133 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)] 162 pub struct Descriptor(pub RawDescriptor); 163 impl AsRawDescriptor for Descriptor { as_raw_descriptor(&self) -> RawDescriptor164 fn as_raw_descriptor(&self) -> RawDescriptor { 165 self.0 166 } 167 } 168 impl FromRawDescriptor for Descriptor { from_raw_descriptor(desc: RawDescriptor) -> Self169 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 175 impl EventToken for Descriptor { as_raw_token(&self) -> u64176 fn as_raw_token(&self) -> u64 { 177 self.0 as u64 178 } 179 from_raw_token(data: u64) -> Self180 fn from_raw_token(data: u64) -> Self { 181 Descriptor(data as RawDescriptor) 182 } 183 } 184 185 impl Serialize for Descriptor { serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,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 194 impl<'de> Deserialize<'de> for Descriptor { deserialize<D>(deserializer: D) -> Result<Descriptor, D::Error> where D: serde::Deserializer<'de>,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 } 202