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