1 use {Port, Rights, Signals, Status, Time, WaitAsyncOpts, ok, sys};
2 use std::marker::PhantomData;
3 use std::mem;
4 
5 /// An object representing a Zircon
6 /// [handle](https://fuchsia.googlesource.com/zircon/+/master/docs/handles.md).
7 ///
8 /// Internally, it is represented as a 32-bit integer, but this wrapper enforces
9 /// strict ownership semantics. The `Drop` implementation closes the handle.
10 ///
11 /// This type represents the most general reference to a kernel object, and can
12 /// be interconverted to and from more specific types. Those conversions are not
13 /// enforced in the type system; attempting to use them will result in errors
14 /// returned by the kernel. These conversions don't change the underlying
15 /// representation, but do change the type and thus what operations are available.
16 #[derive(Debug, Eq, PartialEq, Hash)]
17 pub struct Handle(sys::zx_handle_t);
18 
19 impl AsHandleRef for Handle {
as_handle_ref(&self) -> HandleRef20     fn as_handle_ref(&self) -> HandleRef {
21         HandleRef { handle: self.0, phantom: Default::default() }
22     }
23 }
24 
25 impl HandleBased for Handle {}
26 
27 impl Drop for Handle {
drop(&mut self)28     fn drop(&mut self) {
29         if self.0 != sys::ZX_HANDLE_INVALID {
30             unsafe { sys::zx_handle_close(self.0) };
31         }
32     }
33 }
34 
35 impl Handle {
36     /// Initialize a handle backed by ZX_HANDLE_INVALID, the only safe non-handle.
invalid() -> Handle37     pub fn invalid() -> Handle {
38         Handle(sys::ZX_HANDLE_INVALID)
39     }
40 
41     /// If a raw handle is obtained from some other source, this method converts
42     /// it into a type-safe owned handle.
from_raw(raw: sys::zx_handle_t) -> Handle43     pub unsafe fn from_raw(raw: sys::zx_handle_t) -> Handle {
44         Handle(raw)
45     }
46 
is_invalid(&self) -> bool47     pub fn is_invalid(&self) -> bool {
48         self.0 == sys::ZX_HANDLE_INVALID
49     }
50 
replace(self, rights: Rights) -> Result<Handle, Status>51     pub fn replace(self, rights: Rights) -> Result<Handle, Status> {
52         let handle = self.0;
53         let mut out = 0;
54         let status = unsafe { sys::zx_handle_replace(handle, rights.bits(), &mut out) };
55         ok(status).map(|()| Handle(out))
56     }
57 }
58 
59 /// A borrowed reference to a `Handle`.
60 ///
61 /// Mostly useful as part of a `WaitItem`.
62 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
63 pub struct HandleRef<'a> {
64     handle: sys::zx_handle_t,
65     phantom: PhantomData<&'a sys::zx_handle_t>,
66 }
67 
68 impl<'a> HandleRef<'a> {
raw_handle(&self) -> sys::zx_handle_t69     pub fn raw_handle(&self) -> sys::zx_handle_t {
70         self.handle
71     }
72 
duplicate(&self, rights: Rights) -> Result<Handle, Status>73     pub fn duplicate(&self, rights: Rights) -> Result<Handle, Status> {
74         let handle = self.handle;
75         let mut out = 0;
76         let status = unsafe { sys::zx_handle_duplicate(handle, rights.bits(), &mut out) };
77         ok(status).map(|()| Handle(out))
78     }
79 
signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status>80     pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
81         let handle = self.handle;
82         let status = unsafe { sys::zx_object_signal(handle, clear_mask.bits(), set_mask.bits()) };
83         ok(status)
84     }
85 
wait(&self, signals: Signals, deadline: Time) -> Result<Signals, Status>86     pub fn wait(&self, signals: Signals, deadline: Time) -> Result<Signals, Status> {
87         let handle = self.handle;
88         let mut pending = Signals::empty().bits();
89         let status = unsafe {
90             sys::zx_object_wait_one(handle, signals.bits(), deadline.nanos(), &mut pending)
91         };
92         ok(status).map(|()| Signals::from_bits_truncate(pending))
93     }
94 
wait_async(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts) -> Result<(), Status>95     pub fn wait_async(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts)
96         -> Result<(), Status>
97     {
98         let handle = self.handle;
99         let status = unsafe {
100             sys::zx_object_wait_async(
101                 handle, port.raw_handle(), key, signals.bits(), options as u32)
102         };
103         ok(status)
104     }
105 }
106 
107 /// A trait to get a reference to the underlying handle of an object.
108 pub trait AsHandleRef {
109     /// Get a reference to the handle. One important use of such a reference is
110     /// for `object_wait_many`.
as_handle_ref(&self) -> HandleRef111     fn as_handle_ref(&self) -> HandleRef;
112 
113     /// Interpret the reference as a raw handle (an integer type). Two distinct
114     /// handles will have different raw values (so it can perhaps be used as a
115     /// key in a data structure).
raw_handle(&self) -> sys::zx_handle_t116     fn raw_handle(&self) -> sys::zx_handle_t {
117         self.as_handle_ref().raw_handle()
118     }
119 
120     /// Set and clear userspace-accessible signal bits on an object. Wraps the
121     /// [zx_object_signal](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_signal.md)
122     /// syscall.
signal_handle(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status>123     fn signal_handle(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
124         self.as_handle_ref().signal(clear_mask, set_mask)
125     }
126 
127     /// Waits on a handle. Wraps the
128     /// [zx_object_wait_one](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_one.md)
129     /// syscall.
wait_handle(&self, signals: Signals, deadline: Time) -> Result<Signals, Status>130     fn wait_handle(&self, signals: Signals, deadline: Time) -> Result<Signals, Status> {
131         self.as_handle_ref().wait(signals, deadline)
132     }
133 
134     /// Causes packet delivery on the given port when the object changes state and matches signals.
135     /// [zx_object_wait_async](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_async.md)
136     /// syscall.
wait_async_handle(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts) -> Result<(), Status>137     fn wait_async_handle(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts)
138         -> Result<(), Status>
139     {
140         self.as_handle_ref().wait_async(port, key, signals, options)
141     }
142 }
143 
144 impl<'a> AsHandleRef for HandleRef<'a> {
as_handle_ref(&self) -> HandleRef145     fn as_handle_ref(&self) -> HandleRef { *self }
146 }
147 
148 /// A trait implemented by all handle-based types.
149 ///
150 /// Note: it is reasonable for user-defined objects wrapping a handle to implement
151 /// this trait. For example, a specific interface in some protocol might be
152 /// represented as a newtype of `Channel`, and implement the `as_handle_ref`
153 /// method and the `From<Handle>` trait to facilitate conversion from and to the
154 /// interface.
155 pub trait HandleBased: AsHandleRef + From<Handle> + Into<Handle> {
156     /// Duplicate a handle, possibly reducing the rights available. Wraps the
157     /// [zx_handle_duplicate](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/handle_duplicate.md)
158     /// syscall.
duplicate_handle(&self, rights: Rights) -> Result<Self, Status>159     fn duplicate_handle(&self, rights: Rights) -> Result<Self, Status> {
160         self.as_handle_ref().duplicate(rights).map(|handle| Self::from(handle))
161     }
162 
163     /// Create a replacement for a handle, possibly reducing the rights available. This invalidates
164     /// the original handle. Wraps the
165     /// [zx_handle_replace](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/handle_replace.md)
166     /// syscall.
replace_handle(self, rights: Rights) -> Result<Self, Status>167     fn replace_handle(self, rights: Rights) -> Result<Self, Status> {
168         <Self as Into<Handle>>::into(self)
169             .replace(rights).map(|handle| Self::from(handle))
170     }
171 
172     /// Converts the value into its inner handle.
173     ///
174     /// This is a convenience function which simply forwards to the `Into` trait.
into_handle(self) -> Handle175     fn into_handle(self) -> Handle {
176         self.into()
177     }
178 
179     /// Converts the handle into it's raw representation.
180     ///
181     /// The caller takes ownership over the raw handle, and must close or transfer it to avoid a handle leak.
into_raw(self) -> sys::zx_handle_t182     fn into_raw(self) -> sys::zx_handle_t {
183         let h = self.into_handle();
184         let r = h.0;
185         mem::forget(h);
186         r
187    }
188 
189     /// Creates an instance of this type from a handle.
190     ///
191     /// This is a convenience function which simply forwards to the `From` trait.
from_handle(handle: Handle) -> Self192     fn from_handle(handle: Handle) -> Self {
193         Self::from(handle)
194     }
195 
196     /// Creates an instance of another handle-based type from this value's inner handle.
into_handle_based<H: HandleBased>(self) -> H197     fn into_handle_based<H: HandleBased>(self) -> H {
198         H::from_handle(self.into_handle())
199     }
200 
201     /// Creates an instance of this type from the inner handle of another
202     /// handle-based type.
from_handle_based<H: HandleBased>(h: H) -> Self203     fn from_handle_based<H: HandleBased>(h: H) -> Self {
204         Self::from_handle(h.into_handle())
205     }
206 }
207 
208 /// A trait implemented by all handles for objects which have a peer.
209 pub trait Peered: HandleBased {
210     /// Set and clear userspace-accessible signal bits on the object's peer. Wraps the
211     /// [zx_object_signal_peer](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_signal.md)
212     /// syscall.
signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status>213     fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
214         let handle = self.as_handle_ref().handle;
215         let status = unsafe {
216             sys::zx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits())
217         };
218         ok(status)
219     }
220 }
221 
222 /// A trait implemented by all handles for objects which can have a cookie attached.
223 pub trait Cookied: HandleBased {
224     /// Get the cookie attached to this object, if any. Wraps the
225     /// [zx_object_get_cookie](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/object_get_cookie.md)
226     /// syscall.
get_cookie(&self, scope: &HandleRef) -> Result<u64, Status>227     fn get_cookie(&self, scope: &HandleRef) -> Result<u64, Status> {
228         let handle = self.as_handle_ref().handle;
229         let mut cookie = 0;
230         let status = unsafe { sys::zx_object_get_cookie(handle, scope.handle, &mut cookie) };
231         ok(status).map(|()| cookie)
232     }
233 
234     /// Attach an opaque cookie to this object with the given scope. The cookie may be read or
235     /// changed in future only with the same scope. Wraps the
236     /// [zx_object_set_cookie](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/object_set_cookie.md)
237     /// syscall.
set_cookie(&self, scope: &HandleRef, cookie: u64) -> Result<(), Status>238     fn set_cookie(&self, scope: &HandleRef, cookie: u64) -> Result<(), Status> {
239         let handle = self.as_handle_ref().handle;
240         let status = unsafe { sys::zx_object_set_cookie(handle, scope.handle, cookie) };
241         ok(status)
242     }
243 }
244