• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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