1 // Copyright 2022 The Chromium OS Authors. All rights reserved. 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 crate::{PollToken, RawDescriptor}; 6 use serde::{Deserialize, Serialize}; 7 use std::{ 8 fs::File, 9 mem::{self, ManuallyDrop}, 10 }; 11 12 /// Wraps a RawDescriptor and safely closes it when self falls out of scope. 13 #[derive(Serialize, Deserialize, Debug, Eq)] 14 #[serde(transparent)] 15 pub struct SafeDescriptor { 16 #[serde(with = "super::with_raw_descriptor")] 17 pub(crate) descriptor: RawDescriptor, 18 } 19 20 /// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor 21 pub trait IntoRawDescriptor { into_raw_descriptor(self) -> RawDescriptor22 fn into_raw_descriptor(self) -> RawDescriptor; 23 } 24 25 /// Trait for returning the underlying raw descriptor, without giving up ownership of the 26 /// descriptor. 27 pub trait AsRawDescriptor { as_raw_descriptor(&self) -> RawDescriptor28 fn as_raw_descriptor(&self) -> RawDescriptor; 29 } 30 31 /// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors. 32 pub trait AsRawDescriptors { as_raw_descriptors(&self) -> Vec<RawDescriptor>33 fn as_raw_descriptors(&self) -> Vec<RawDescriptor>; 34 } 35 36 pub trait FromRawDescriptor { 37 /// # Safety 38 /// Safe only if the caller ensures nothing has access to the descriptor after passing it to 39 /// `from_raw_descriptor` from_raw_descriptor(descriptor: RawDescriptor) -> Self40 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self; 41 } 42 43 impl AsRawDescriptor for SafeDescriptor { as_raw_descriptor(&self) -> RawDescriptor44 fn as_raw_descriptor(&self) -> RawDescriptor { 45 self.descriptor 46 } 47 } 48 49 impl<T> AsRawDescriptors for T 50 where 51 T: AsRawDescriptor, 52 { as_raw_descriptors(&self) -> Vec<RawDescriptor>53 fn as_raw_descriptors(&self) -> Vec<RawDescriptor> { 54 vec![self.as_raw_descriptor()] 55 } 56 } 57 58 impl IntoRawDescriptor for SafeDescriptor { into_raw_descriptor(self) -> RawDescriptor59 fn into_raw_descriptor(self) -> RawDescriptor { 60 let descriptor = self.descriptor; 61 mem::forget(self); 62 descriptor 63 } 64 } 65 66 impl FromRawDescriptor for SafeDescriptor { from_raw_descriptor(descriptor: RawDescriptor) -> Self67 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self { 68 SafeDescriptor { descriptor } 69 } 70 } 71 72 impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor { 73 type Error = std::io::Error; 74 75 /// Clones the underlying descriptor (handle), internally creating a new descriptor. 76 /// 77 /// WARNING: Windows does NOT support cloning/duplicating all types of handles. DO NOT use this 78 /// function on IO completion ports, sockets, or pseudo-handles (except those from 79 /// GetCurrentProcess or GetCurrentThread). See 80 /// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle 81 /// for further details. 82 /// 83 /// TODO(b/191800567): this API has sharp edges on Windows. We should evaluate making some 84 /// adjustments to smooth those edges. try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error>85 fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> { 86 // Safe because the underlying raw descriptor is guaranteed valid by rd's existence. 87 // 88 // Note that we are cloning the underlying raw descriptor since we have no guarantee of 89 // its existence after this function returns. 90 let rd_as_safe_desc = ManuallyDrop::new(unsafe { 91 SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor()) 92 }); 93 94 // We have to clone rd because we have no guarantee ownership was transferred (rd is 95 // borrowed). 96 rd_as_safe_desc 97 .try_clone() 98 .map_err(|e| Self::Error::from_raw_os_error(e.errno())) 99 } 100 } 101 102 impl From<File> for SafeDescriptor { from(f: File) -> SafeDescriptor103 fn from(f: File) -> SafeDescriptor { 104 // Safe because we own the File at this point. 105 unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) } 106 } 107 } 108 109 /// For use cases where a simple wrapper around a RawDescriptor is needed. 110 /// This is a simply a wrapper and does not manage the lifetime of the descriptor. 111 /// Most usages should prefer SafeDescriptor or using a RawDescriptor directly 112 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 113 #[repr(transparent)] 114 pub struct Descriptor(pub RawDescriptor); 115 impl AsRawDescriptor for Descriptor { as_raw_descriptor(&self) -> RawDescriptor116 fn as_raw_descriptor(&self) -> RawDescriptor { 117 self.0 118 } 119 } 120 121 /// Implement token for implementations that wish to use this struct as such 122 impl PollToken for Descriptor { as_raw_token(&self) -> u64123 fn as_raw_token(&self) -> u64 { 124 self.0 as u64 125 } 126 from_raw_token(data: u64) -> Self127 fn from_raw_token(data: u64) -> Self { 128 Descriptor(data as RawDescriptor) 129 } 130 } 131