zx/
handle.rs

1// Copyright 2018 The Fuchsia 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//! Type-safe bindings for Zircon handles.
6
7use crate::{
8    Koid, MonotonicInstant, Name, ObjectQuery, ObjectType, Port, Property, PropertyQuery, Rights,
9    Signals, Status, Topic, WaitAsyncOpts, object_get_info_single, object_get_property,
10    object_set_property, ok, sys,
11};
12use std::marker::PhantomData;
13use std::mem::{self, ManuallyDrop};
14use std::num::NonZeroU32;
15
16/// An owned and valid Zircon
17/// [handle](https://fuchsia.dev/fuchsia-src/concepts/objects/handles) to a kernel object.
18///
19/// This type can be interconverted to and from more specific types. Those conversions are not
20/// enforced in the type system; attempting to use them will result in errors returned by the
21/// kernel. These conversions don't change the underlying representation, but do change the type and
22/// what operations are available.
23///
24/// # Lifecycle
25///
26/// This type closes the handle it owns when dropped.
27///
28/// # Layout
29///
30/// `Option<Handle>` is guaranteed to have the same layout and bit patterns as `zx_handle_t`.
31/// Unlike many types in this crate it does not implement `zerocopy` traits because those are not
32/// appropriate for types with real `Drop` implementations.
33#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
34#[repr(transparent)]
35pub struct Handle(NonZeroU32);
36
37// Ensure ABI-compatibility with zx_handle_t with the following static assertions. NonZeroU32 lets
38// Option store the None variant in the all-zeroes bit pattern, which is ZX_HANDLE_INVALID. By
39// banning use of ZX_HANDLE_INVALID inside a Handle, we ensure that Option<Handle> is ABI-compatible
40// with sys::zx_handle_t while providing statically checkable nullability.
41static_assertions::const_assert_eq!(sys::ZX_HANDLE_INVALID, 0);
42static_assertions::assert_eq_size!(Handle, sys::zx_handle_t);
43static_assertions::assert_eq_align!(Handle, sys::zx_handle_t);
44static_assertions::assert_eq_size!(Option<Handle>, sys::zx_handle_t);
45static_assertions::assert_eq_align!(Option<Handle>, sys::zx_handle_t);
46
47impl Handle {
48    /// Take exclusive ownership over a raw handle.
49    ///
50    /// # Safety
51    ///
52    /// `raw` must be a valid handle present in the current handle table that will not be closed by
53    /// another owner.
54    ///
55    /// # Panics
56    ///
57    /// If `ZX_HANDLE_INVALID` is passed.
58    pub unsafe fn from_raw(raw: sys::zx_handle_t) -> Self {
59        debug_assert!(Self::check_raw_valid(raw).is_ok());
60        Self(NonZeroU32::new(raw).unwrap())
61    }
62
63    /// Wraps the
64    /// [zx_handle_check_valid](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_check_valid.md)
65    /// syscall.
66    ///
67    /// Note that this does *not* guarantee that the handle is safe to pass to `Handle::from_raw`
68    /// in cases where another function may close the handle.
69    pub fn check_raw_valid(raw: sys::zx_handle_t) -> Result<(), Status> {
70        // SAFETY: basic FFI call.
71        ok(unsafe { sys::zx_handle_check_valid(raw) })
72    }
73
74    /// Returns the raw handle's integer value.
75    pub const fn raw_handle(&self) -> sys::zx_handle_t {
76        self.0.get()
77    }
78
79    /// Return the raw handle's integer value without closing it when `self` is dropped.
80    pub const fn into_raw(self) -> sys::zx_handle_t {
81        let ret = self.0.get();
82        std::mem::forget(self);
83        ret
84    }
85
86    /// Wraps the
87    /// [zx_handle_replace](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_replace.md)
88    /// syscall.
89    pub fn replace(self, rights: Rights) -> Result<Self, Status> {
90        let mut out = 0;
91
92        // SAFETY: basic FFI call.
93        let status = unsafe { sys::zx_handle_replace(self.into_raw(), rights.bits(), &mut out) };
94        ok(status)?;
95
96        // SAFETY: zx_handle_replace gives us a valid owned handle if the call succeeded.
97        unsafe { Ok(Self::from_raw(out)) }
98    }
99}
100
101impl Drop for Handle {
102    fn drop(&mut self) {
103        // SAFETY: basic FFI call.
104        unsafe { sys::zx_handle_close(self.0.get()) };
105    }
106}
107
108/// An object representing a Zircon
109/// [handle](https://fuchsia.dev/fuchsia-src/concepts/objects/handles).
110///
111/// Internally, it is represented as a 32-bit integer, but this wrapper enforces
112/// strict ownership semantics. The `Drop` implementation closes the handle.
113///
114/// This type represents the most general reference to a kernel object, and can
115/// be interconverted to and from more specific types. Those conversions are not
116/// enforced in the type system; attempting to use them will result in errors
117/// returned by the kernel. These conversions don't change the underlying
118/// representation, but do change the type and thus what operations are available.
119// TODO(https://fxbug.dev/465766514): remove
120#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
121#[repr(transparent)]
122pub struct NullableHandle(Option<Handle>);
123
124impl AsHandleRef for NullableHandle {
125    fn as_handle_ref(&self) -> HandleRef<'_> {
126        if let Some(inner) = &self.0 {
127            // SAFETY: inner is a guaranteed valid handle.
128            unsafe { Unowned::from_raw_handle(inner.raw_handle()) }
129        } else {
130            // SAFETY: ZX_HANDLE_INVALID is a valid handle for Unowned::from_raw_handle.
131            unsafe { Unowned::from_raw_handle(sys::ZX_HANDLE_INVALID) }
132        }
133    }
134
135    fn raw_handle(&self) -> sys::zx_handle_t {
136        self.0.as_ref().map(|h| h.raw_handle()).unwrap_or(sys::ZX_HANDLE_INVALID)
137    }
138}
139
140impl HandleBased for NullableHandle {
141    fn into_raw(self) -> sys::zx_handle_t {
142        if let Some(inner) = self.0 { inner.into_raw() } else { sys::ZX_HANDLE_INVALID }
143    }
144}
145
146impl NullableHandle {
147    /// Initialize a handle backed by ZX_HANDLE_INVALID, the only safe non-handle.
148    #[inline(always)]
149    pub const fn invalid() -> Self {
150        Self(None)
151    }
152
153    /// If a raw handle is obtained from some other source, this method converts
154    /// it into a type-safe owned handle.
155    ///
156    /// # Safety
157    ///
158    /// `raw` must either be a valid handle (i.e. not dangling), or
159    /// `ZX_HANDLE_INVALID`. If `raw` is a valid handle, then either:
160    /// - `raw` may be closed manually and the returned `NullableHandle` must not be
161    ///   dropped.
162    /// - Or `raw` must not be closed until the returned `NullableHandle` is dropped, at
163    ///   which time it will close `raw`.
164    pub const unsafe fn from_raw(raw: sys::zx_handle_t) -> Self {
165        // We need to manually construct the inner `Handle` because its constructor is not
166        // const since the only valid way to call this function in a `const` context is to pass
167        // `ZX_HANDLE_INVALID`.
168        if let Some(inner) = NonZeroU32::new(raw) { Self(Some(Handle(inner))) } else { Self(None) }
169    }
170
171    pub fn is_invalid(&self) -> bool {
172        self.0.is_none()
173    }
174
175    pub fn replace(mut self, rights: Rights) -> Result<Self, Status> {
176        if let Some(inner) = self.0.take() {
177            let inner = inner.replace(rights)?;
178            Ok(Self(Some(inner)))
179        } else {
180            Ok(Self(None))
181        }
182    }
183}
184struct NameProperty();
185unsafe impl PropertyQuery for NameProperty {
186    const PROPERTY: Property = Property::NAME;
187    // SAFETY: this type is correctly sized and the kernel guarantees that it will be
188    // null-terminated like the type requires.
189    type PropTy = Name;
190}
191
192/// A borrowed value of type `T`.
193///
194/// This is primarily used for working with borrowed values of `HandleBased` types.
195#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
196#[repr(transparent)]
197pub struct Unowned<'a, T: Into<NullableHandle>> {
198    inner: ManuallyDrop<T>,
199    marker: PhantomData<&'a T>,
200}
201
202impl<T: Into<NullableHandle>> Drop for Unowned<'_, T> {
203    fn drop(&mut self) {
204        // SAFETY: This is safe because we don't use this ManuallyDrop again.
205        let handle: NullableHandle = unsafe { ManuallyDrop::take(&mut self.inner).into() };
206        mem::forget(handle);
207    }
208}
209
210impl<'a, T: Into<NullableHandle>> ::std::ops::Deref for Unowned<'a, T> {
211    type Target = T;
212
213    fn deref(&self) -> &Self::Target {
214        &*self.inner
215    }
216}
217
218impl<T: HandleBased> Clone for Unowned<'_, T> {
219    fn clone(&self) -> Self {
220        unsafe { Self::from_raw_handle(self.inner.as_handle_ref().raw_handle()) }
221    }
222}
223
224pub type HandleRef<'a> = Unowned<'a, NullableHandle>;
225
226impl<'a, T: Into<NullableHandle>> Unowned<'a, T> {
227    /// Returns a new object that borrows the underyling handle.  This will work for any type that
228    /// implements `From<U>` where `U` is handle-like i.e. it implements `AsHandleRef` and
229    /// `From<Handle>`.
230    pub fn new<U: AsHandleRef + From<NullableHandle>>(inner: &'a U) -> Self
231    where
232        T: From<U>,
233    {
234        // SAFETY: This is safe because we are converting from &U to U to allow us to create T, and
235        // then when we drop, we convert T into a handle that we forget.
236        Unowned {
237            inner: ManuallyDrop::new(T::from(U::from(unsafe {
238                NullableHandle::from_raw(inner.as_handle_ref().raw_handle())
239            }))),
240            marker: PhantomData,
241        }
242    }
243}
244
245impl<'a, T: HandleBased> Unowned<'a, T> {
246    /// Create a `HandleRef` from a raw handle. Use this method when you are given a raw handle but
247    /// should not take ownership of it. Examples include process-global handles like the root
248    /// VMAR. This method should be called with an explicitly provided lifetime that must not
249    /// outlive the lifetime during which the handle is owned by the current process. It is unsafe
250    /// because most of the time, it is better to use a `Handle` to prevent leaking resources.
251    ///
252    /// # Safety
253    ///
254    /// `handle` must be a valid handle (i.e. not dangling), or
255    /// `ZX_HANDLE_INVALID`. If `handle` is a valid handle, then it must not be
256    /// closed for the lifetime `'a`.
257    pub unsafe fn from_raw_handle(handle: sys::zx_handle_t) -> Self {
258        Unowned {
259            inner: ManuallyDrop::new(T::from(unsafe { NullableHandle::from_raw(handle) })),
260            marker: PhantomData,
261        }
262    }
263
264    pub fn raw_handle(&self) -> sys::zx_handle_t {
265        self.inner.raw_handle()
266    }
267
268    pub fn duplicate(&self, rights: Rights) -> Result<T, Status> {
269        let mut out = 0;
270        // SAFETY: basic FFI call.
271        let status =
272            unsafe { sys::zx_handle_duplicate(self.raw_handle(), rights.bits(), &mut out) };
273        ok(status)?;
274
275        // SAFETY: zx_handle_duplicate returns a valid handle that this function owns.
276        Ok(T::from(unsafe { NullableHandle::from_raw(out) }))
277    }
278
279    pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
280        let status =
281            unsafe { sys::zx_object_signal(self.raw_handle(), clear_mask.bits(), set_mask.bits()) };
282        ok(status)
283    }
284
285    pub fn wait(&self, signals: Signals, deadline: MonotonicInstant) -> WaitResult {
286        let mut pending = Signals::empty().bits();
287        let status = unsafe {
288            sys::zx_object_wait_one(
289                self.raw_handle(),
290                signals.bits(),
291                deadline.into_nanos(),
292                &mut pending,
293            )
294        };
295        let signals = Signals::from_bits_truncate(pending);
296        match ok(status) {
297            Ok(()) => WaitResult::Ok(signals),
298            Err(Status::TIMED_OUT) => WaitResult::TimedOut(signals),
299            Err(Status::CANCELED) => WaitResult::Canceled(signals),
300            Err(e) => WaitResult::Err(e),
301        }
302    }
303
304    pub fn wait_async(
305        &self,
306        port: &Port,
307        key: u64,
308        signals: Signals,
309        options: WaitAsyncOpts,
310    ) -> Result<(), Status> {
311        let status = unsafe {
312            sys::zx_object_wait_async(
313                self.raw_handle(),
314                port.raw_handle(),
315                key,
316                signals.bits(),
317                options.bits(),
318            )
319        };
320        ok(status)
321    }
322}
323
324/// Result from `HandleRef::wait` and `AsHandleRef::wait_handle`. Conveys the
325/// result of the
326/// [zx_object_wait_one](https://fuchsia.dev/reference/syscalls/object_wait_one)
327/// syscall and the signals that were asserted on the object when the syscall
328/// completed.
329#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
330pub enum WaitResult {
331    /// The syscall completed with `ZX_OK` and the provided signals were observed.
332    Ok(Signals),
333
334    /// The syscall completed with `ZX_ERR_TIMED_OUT` and the provided signals
335    /// were observed. These signals may reflect state changes that occurred
336    /// after the deadline passed, but before the syscall returned.
337    TimedOut(Signals),
338
339    /// The syscall completed with `ZX_ERR_CANCELED` and the provided signals
340    /// were observed. The signals will include `ZX_SIGNAL_HANDLE_CLOSED`.
341    ///
342    /// Note that the state of these signals may be racy and difficult to
343    /// interpret. Often, the correct behavior in this case is to treat this as
344    /// an error.
345    Canceled(Signals),
346
347    /// The syscall completed with a status other than `ZX_OK`, `ZX_ERR_TIMED_OUT`,
348    /// or `ZX_ERR_CANCELED`. No signals are returned in this scenario.
349    Err(Status),
350}
351
352impl WaitResult {
353    /// Convert this `WaitResult` into a `Result<Signals, Status>`. The signals
354    /// are discarded in all cases except `WaitResult::Ok`.
355    pub const fn to_result(self) -> Result<Signals, Status> {
356        match self {
357            WaitResult::Ok(signals) => Ok(signals),
358            WaitResult::TimedOut(_signals) => Err(Status::TIMED_OUT),
359            WaitResult::Canceled(_signals) => Err(Status::CANCELED),
360            WaitResult::Err(status) => Err(status),
361        }
362    }
363
364    // The following definitions are all copied from `std::result::Result`. They
365    // allow a `WaitResult` to be treated like a `Result` in many circumstance. All
366    // simply delegate to `to_result()`.
367
368    #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
369    #[inline]
370    pub const fn is_ok(&self) -> bool {
371        self.to_result().is_ok()
372    }
373
374    #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
375    #[inline]
376    pub const fn is_err(&self) -> bool {
377        self.to_result().is_err()
378    }
379
380    #[inline]
381    pub fn map<U, F: FnOnce(Signals) -> U>(self, op: F) -> Result<U, Status> {
382        self.to_result().map(op)
383    }
384
385    #[inline]
386    pub fn map_err<F, O: FnOnce(Status) -> F>(self, op: O) -> Result<Signals, F> {
387        self.to_result().map_err(op)
388    }
389
390    #[inline]
391    #[track_caller]
392    pub fn expect(self, msg: &str) -> Signals {
393        self.to_result().expect(msg)
394    }
395
396    #[inline]
397    #[track_caller]
398    pub fn expect_err(self, msg: &str) -> Status {
399        self.to_result().expect_err(msg)
400    }
401
402    #[inline(always)]
403    #[track_caller]
404    pub fn unwrap(self) -> Signals {
405        self.to_result().unwrap()
406    }
407}
408
409impl<'a> Unowned<'a, NullableHandle> {
410    /// Convert this HandleRef to one of a specific type.
411    pub fn cast<T: HandleBased>(self) -> Unowned<'a, T> {
412        // SAFETY: this function's guarantees are upheld by the self input.
413        unsafe { Unowned::from_raw_handle(self.raw_handle()) }
414    }
415}
416
417/// A trait to get a reference to the underlying handle of an object.
418pub trait AsHandleRef {
419    /// Get a reference to the handle. One important use of such a reference is
420    /// for `object_wait_many`.
421    fn as_handle_ref(&self) -> HandleRef<'_>;
422
423    /// Interpret the reference as a raw handle (an integer type). Two distinct
424    /// handles will have different raw values (so it can perhaps be used as a
425    /// key in a data structure).
426    fn raw_handle(&self) -> sys::zx_handle_t {
427        self.as_handle_ref().inner.raw_handle()
428    }
429
430    /// Set and clear userspace-accessible signal bits on an object. Wraps the
431    /// [zx_object_signal](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_signal.md)
432    /// syscall.
433    fn signal_handle(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
434        self.as_handle_ref().signal(clear_mask, set_mask)
435    }
436
437    /// Waits on a handle. Wraps the
438    /// [zx_object_wait_one](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_wait_one.md)
439    /// syscall.
440    fn wait_handle(&self, signals: Signals, deadline: MonotonicInstant) -> WaitResult {
441        self.as_handle_ref().wait(signals, deadline)
442    }
443
444    /// Causes packet delivery on the given port when the object changes state and matches signals.
445    /// [zx_object_wait_async](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_wait_async.md)
446    /// syscall.
447    fn wait_async_handle(
448        &self,
449        port: &Port,
450        key: u64,
451        signals: Signals,
452        options: WaitAsyncOpts,
453    ) -> Result<(), Status> {
454        self.as_handle_ref().wait_async(port, key, signals, options)
455    }
456
457    /// Get the [Property::NAME] property for this object.
458    ///
459    /// Wraps a call to the
460    /// [zx_object_get_property](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_property.md)
461    /// syscall for the ZX_PROP_NAME property.
462    fn get_name(&self) -> Result<Name, Status> {
463        object_get_property::<NameProperty>(self.as_handle_ref())
464    }
465
466    /// Set the [Property::NAME] property for this object.
467    ///
468    /// The name's length must be less than [sys::ZX_MAX_NAME_LEN], i.e.
469    /// name.[to_bytes_with_nul()](CStr::to_bytes_with_nul()).len() <= [sys::ZX_MAX_NAME_LEN], or
470    /// Err([Status::INVALID_ARGS]) will be returned.
471    ///
472    /// Wraps a call to the
473    /// [zx_object_get_property](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_property.md)
474    /// syscall for the ZX_PROP_NAME property.
475    fn set_name(&self, name: &Name) -> Result<(), Status> {
476        object_set_property::<NameProperty>(self.as_handle_ref(), &name)
477    }
478
479    /// Wraps the
480    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
481    /// syscall for the ZX_INFO_HANDLE_BASIC topic.
482    fn basic_info(&self) -> Result<HandleBasicInfo, Status> {
483        Ok(HandleBasicInfo::from(object_get_info_single::<HandleBasicInfoQuery>(
484            self.as_handle_ref(),
485        )?))
486    }
487
488    /// Wraps the
489    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
490    /// syscall for the ZX_INFO_HANDLE_COUNT topic.
491    fn count_info(&self) -> Result<HandleCountInfo, Status> {
492        Ok(HandleCountInfo::from(object_get_info_single::<HandleCountInfoQuery>(
493            self.as_handle_ref(),
494        )?))
495    }
496
497    /// Returns the koid (kernel object ID) for this handle.
498    fn get_koid(&self) -> Result<Koid, Status> {
499        self.basic_info().map(|info| info.koid)
500    }
501}
502
503impl<'a, T: HandleBased> AsHandleRef for Unowned<'a, T> {
504    fn as_handle_ref(&self) -> HandleRef<'_> {
505        self.inner.as_handle_ref()
506    }
507}
508
509impl<T: AsHandleRef> AsHandleRef for &T {
510    fn as_handle_ref(&self) -> HandleRef<'_> {
511        (*self).as_handle_ref()
512    }
513}
514
515/// A trait implemented by all handle-based types.
516///
517/// Note: it is reasonable for user-defined objects wrapping a handle to implement
518/// this trait. For example, a specific interface in some protocol might be
519/// represented as a newtype of `Channel`, and implement the `as_handle_ref`
520/// method and the `From<Handle>` trait to facilitate conversion from and to the
521/// interface.
522pub trait HandleBased: AsHandleRef + From<NullableHandle> + Into<NullableHandle> {
523    /// Duplicate a handle, possibly reducing the rights available. Wraps the
524    /// [zx_handle_duplicate](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_duplicate.md)
525    /// syscall.
526    fn duplicate_handle(&self, rights: Rights) -> Result<Self, Status> {
527        self.as_handle_ref().duplicate(rights).map(|handle| Self::from(handle))
528    }
529
530    /// Create a replacement for a handle, possibly reducing the rights available. This invalidates
531    /// the original handle. Wraps the
532    /// [zx_handle_replace](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_replace.md)
533    /// syscall.
534    fn replace_handle(self, rights: Rights) -> Result<Self, Status> {
535        <Self as Into<NullableHandle>>::into(self).replace(rights).map(|handle| Self::from(handle))
536    }
537
538    /// Converts the value into its inner handle.
539    ///
540    /// This is a convenience function which simply forwards to the `Into` trait.
541    fn into_handle(self) -> NullableHandle {
542        self.into()
543    }
544
545    /// Converts the handle into it's raw representation.
546    ///
547    /// The caller takes ownership over the raw handle, and must close or transfer it to avoid a handle leak.
548    fn into_raw(self) -> sys::zx_handle_t {
549        self.into_handle().into_raw()
550    }
551
552    /// Creates an instance of this type from a handle.
553    ///
554    /// This is a convenience function which simply forwards to the `From` trait.
555    fn from_handle(handle: NullableHandle) -> Self {
556        Self::from(handle)
557    }
558
559    /// Creates an instance of another handle-based type from this value's inner handle.
560    fn into_handle_based<H: HandleBased>(self) -> H {
561        H::from_handle(self.into_handle())
562    }
563
564    /// Creates an instance of this type from the inner handle of another
565    /// handle-based type.
566    fn from_handle_based<H: HandleBased>(h: H) -> Self {
567        Self::from_handle(h.into_handle())
568    }
569
570    fn is_invalid_handle(&self) -> bool {
571        self.as_handle_ref().is_invalid()
572    }
573}
574
575/// A trait implemented by all handles for objects which have a peer.
576pub trait Peered: HandleBased {
577    /// Set and clear userspace-accessible signal bits on the object's peer. Wraps the
578    /// [zx_object_signal_peer][osp] syscall.
579    ///
580    /// [osp]: https://fuchsia.dev/fuchsia-src/reference/syscalls/object_signal_peer.md
581    fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
582        let handle = self.raw_handle();
583        let status =
584            unsafe { sys::zx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits()) };
585        ok(status)
586    }
587
588    /// Returns true if the handle has received the `PEER_CLOSED` signal.
589    ///
590    /// # Errors
591    ///
592    /// See https://fuchsia.dev/reference/syscalls/object_wait_one?hl=en#errors for a full list of
593    /// errors. Note that `Status::TIMED_OUT` errors are converted to `Ok(false)` and all other
594    /// errors are propagated.
595    fn is_closed(&self) -> Result<bool, Status> {
596        match self.wait_handle(Signals::OBJECT_PEER_CLOSED, MonotonicInstant::INFINITE_PAST) {
597            WaitResult::Ok(signals) => Ok(signals.contains(Signals::OBJECT_PEER_CLOSED)),
598            WaitResult::TimedOut(_) => Ok(false),
599            WaitResult::Canceled(_) => Err(Status::CANCELED),
600            WaitResult::Err(e) => Err(e),
601        }
602    }
603}
604
605/// Basic information about a handle.
606///
607/// Wrapper for data returned from [Handle::basic_info()].
608#[derive(Debug, Copy, Clone, Eq, PartialEq)]
609pub struct HandleBasicInfo {
610    pub koid: Koid,
611    pub rights: Rights,
612    pub object_type: ObjectType,
613    pub related_koid: Koid,
614}
615
616impl Default for HandleBasicInfo {
617    fn default() -> Self {
618        Self::from(sys::zx_info_handle_basic_t::default())
619    }
620}
621
622impl From<sys::zx_info_handle_basic_t> for HandleBasicInfo {
623    fn from(info: sys::zx_info_handle_basic_t) -> Self {
624        let sys::zx_info_handle_basic_t { koid, rights, type_, related_koid, .. } = info;
625
626        // Note lossy conversion of Rights and HandleProperty here if either of those types are out
627        // of date or incomplete.
628        HandleBasicInfo {
629            koid: Koid::from_raw(koid),
630            rights: Rights::from_bits_truncate(rights),
631            object_type: ObjectType::from_raw(type_),
632            related_koid: Koid::from_raw(related_koid),
633        }
634    }
635}
636
637// zx_info_handle_basic_t is able to be safely replaced with a byte representation and is a PoD
638// type.
639struct HandleBasicInfoQuery;
640unsafe impl ObjectQuery for HandleBasicInfoQuery {
641    const TOPIC: Topic = Topic::HANDLE_BASIC;
642    type InfoTy = sys::zx_info_handle_basic_t;
643}
644
645sys::zx_info_handle_count_t!(HandleCountInfo);
646
647impl From<sys::zx_info_handle_count_t> for HandleCountInfo {
648    fn from(sys::zx_info_handle_count_t { handle_count }: sys::zx_info_handle_count_t) -> Self {
649        HandleCountInfo { handle_count }
650    }
651}
652
653// zx_info_handle_count_t is able to be safely replaced with a byte representation and is a PoD
654// type.
655struct HandleCountInfoQuery;
656unsafe impl ObjectQuery for HandleCountInfoQuery {
657    const TOPIC: Topic = Topic::HANDLE_COUNT;
658    type InfoTy = sys::zx_info_handle_count_t;
659}
660
661/// Handle operation.
662#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
663pub enum HandleOp<'a> {
664    Move(NullableHandle),
665    Duplicate(HandleRef<'a>),
666}
667
668/// Operation to perform on handles during write. ABI-compatible with `zx_handle_disposition_t`.
669#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
670#[repr(C)]
671pub struct HandleDisposition<'a> {
672    // Must be either ZX_HANDLE_OP_MOVE or ZX_HANDLE_OP_DUPLICATE.
673    operation: sys::zx_handle_op_t,
674    // ZX_HANDLE_OP_MOVE==owned, ZX_HANDLE_OP_DUPLICATE==borrowed.
675    handle: sys::zx_handle_t,
676    // Preserve a borrowed handle's lifetime. Does not occupy any layout.
677    _handle_lifetime: std::marker::PhantomData<&'a ()>,
678
679    pub object_type: ObjectType,
680    pub rights: Rights,
681    pub result: Status,
682}
683
684static_assertions::assert_eq_size!(HandleDisposition<'_>, sys::zx_handle_disposition_t);
685static_assertions::const_assert_eq!(
686    std::mem::offset_of!(HandleDisposition<'_>, operation),
687    std::mem::offset_of!(sys::zx_handle_disposition_t, operation)
688);
689static_assertions::const_assert_eq!(
690    std::mem::offset_of!(HandleDisposition<'_>, handle),
691    std::mem::offset_of!(sys::zx_handle_disposition_t, handle)
692);
693static_assertions::const_assert_eq!(
694    std::mem::offset_of!(HandleDisposition<'_>, object_type),
695    std::mem::offset_of!(sys::zx_handle_disposition_t, type_)
696);
697static_assertions::const_assert_eq!(
698    std::mem::offset_of!(HandleDisposition<'_>, rights),
699    std::mem::offset_of!(sys::zx_handle_disposition_t, rights)
700);
701static_assertions::const_assert_eq!(
702    std::mem::offset_of!(HandleDisposition<'_>, result),
703    std::mem::offset_of!(sys::zx_handle_disposition_t, result)
704);
705
706impl<'a> HandleDisposition<'a> {
707    #[inline]
708    pub fn new(
709        handle_op: HandleOp<'a>,
710        object_type: ObjectType,
711        rights: Rights,
712        status: Status,
713    ) -> Self {
714        let (operation, handle) = match handle_op {
715            HandleOp::Move(h) => (sys::ZX_HANDLE_OP_MOVE, h.into_raw()),
716            HandleOp::Duplicate(h) => (sys::ZX_HANDLE_OP_DUPLICATE, h.raw_handle()),
717        };
718
719        Self {
720            operation,
721            handle,
722            _handle_lifetime: std::marker::PhantomData,
723            object_type,
724            rights: rights,
725            result: status,
726        }
727    }
728
729    pub fn raw_handle(&self) -> sys::zx_handle_t {
730        self.handle
731    }
732
733    pub fn is_move(&self) -> bool {
734        self.operation == sys::ZX_HANDLE_OP_MOVE
735    }
736
737    pub fn is_duplicate(&self) -> bool {
738        self.operation == sys::ZX_HANDLE_OP_DUPLICATE
739    }
740
741    pub fn take_op(&mut self) -> HandleOp<'a> {
742        match self.operation {
743            sys::ZX_HANDLE_OP_MOVE => {
744                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
745                // type's public API and the kernel's guarantees.
746                HandleOp::Move(unsafe {
747                    NullableHandle::from_raw(std::mem::replace(
748                        &mut self.handle,
749                        sys::ZX_HANDLE_INVALID,
750                    ))
751                })
752            }
753            sys::ZX_HANDLE_OP_DUPLICATE => {
754                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
755                // type's public API and the kernel's guarantees.
756                HandleOp::Duplicate(unsafe { Unowned::from_raw_handle(self.handle) })
757            }
758            _ => unreachable!(),
759        }
760    }
761
762    pub fn into_raw(mut self) -> sys::zx_handle_disposition_t {
763        match self.take_op() {
764            HandleOp::Move(mut handle) => sys::zx_handle_disposition_t {
765                operation: sys::ZX_HANDLE_OP_MOVE,
766                handle: std::mem::replace(&mut handle, NullableHandle::invalid()).into_raw(),
767                type_: self.object_type.into_raw(),
768                rights: self.rights.bits(),
769                result: self.result.into_raw(),
770            },
771            HandleOp::Duplicate(handle_ref) => sys::zx_handle_disposition_t {
772                operation: sys::ZX_HANDLE_OP_DUPLICATE,
773                handle: handle_ref.raw_handle(),
774                type_: self.object_type.into_raw(),
775                rights: self.rights.bits(),
776                result: self.result.into_raw(),
777            },
778        }
779    }
780}
781
782impl<'a> Drop for HandleDisposition<'a> {
783    fn drop(&mut self) {
784        // Ensure we clean up owned handle variants.
785        if self.operation == sys::ZX_HANDLE_OP_MOVE {
786            unsafe { drop(NullableHandle::from_raw(self.handle)) };
787        }
788    }
789}
790
791/// Information on handles that were read.
792///
793/// ABI-compatible with zx_handle_info_t.
794#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
795#[repr(C)]
796pub struct HandleInfo {
797    pub handle: NullableHandle,
798    pub object_type: ObjectType,
799    pub rights: Rights,
800
801    // Necessary for ABI compatibility with zx_handle_info_t.
802    pub(crate) _unused: u32,
803}
804
805static_assertions::assert_eq_size!(HandleInfo, sys::zx_handle_info_t);
806static_assertions::const_assert_eq!(
807    std::mem::offset_of!(HandleInfo, handle),
808    std::mem::offset_of!(sys::zx_handle_info_t, handle)
809);
810static_assertions::const_assert_eq!(
811    std::mem::offset_of!(HandleInfo, object_type),
812    std::mem::offset_of!(sys::zx_handle_info_t, ty)
813);
814static_assertions::const_assert_eq!(
815    std::mem::offset_of!(HandleInfo, rights),
816    std::mem::offset_of!(sys::zx_handle_info_t, rights)
817);
818static_assertions::const_assert_eq!(
819    std::mem::offset_of!(HandleInfo, _unused),
820    std::mem::offset_of!(sys::zx_handle_info_t, unused)
821);
822
823impl HandleInfo {
824    /// Make a new `HandleInfo`.
825    pub const fn new(handle: NullableHandle, object_type: ObjectType, rights: Rights) -> Self {
826        Self { handle, object_type, rights, _unused: 0 }
827    }
828
829    /// # Safety
830    ///
831    /// See [`Handle::from_raw`] for requirements about the validity and closing
832    /// of `raw.handle`.
833    ///
834    /// Note that while `raw.ty` _should_ correspond to the type of the handle,
835    /// that this is not required for safety.
836    pub const unsafe fn from_raw(raw: sys::zx_handle_info_t) -> HandleInfo {
837        HandleInfo::new(
838            // SAFETY: invariants to not double-close are upheld by the caller.
839            unsafe { NullableHandle::from_raw(raw.handle) },
840            ObjectType::from_raw(raw.ty),
841            Rights::from_bits_retain(raw.rights),
842        )
843    }
844}
845
846#[cfg(test)]
847mod tests {
848    use super::*;
849    // The unit tests are built with a different crate name, but fuchsia_runtime returns a "real"
850    // zx::Vmar that we need to use.
851    use zx::{
852        AsHandleRef, Channel, HandleBased, HandleDisposition, HandleInfo, HandleOp, Name,
853        NullableHandle, ObjectType, Rights, Vmo,
854    };
855    use zx_sys as sys;
856
857    #[test]
858    fn into_raw() {
859        let vmo = Vmo::create(1).unwrap();
860        let h = vmo.into_raw();
861        let vmo2 = Vmo::from(unsafe { NullableHandle::from_raw(h) });
862        assert!(vmo2.write(b"1", 0).is_ok());
863    }
864
865    #[test]
866    fn check_raw_valid() {
867        assert!(Handle::check_raw_valid(sys::ZX_HANDLE_INVALID).is_err());
868        let vmo = Vmo::create(1).unwrap();
869        let vmo_raw = vmo.raw_handle();
870        assert!(Handle::check_raw_valid(vmo_raw).is_ok());
871        drop(vmo);
872        assert!(Handle::check_raw_valid(vmo_raw).is_err());
873    }
874
875    /// Test duplication by means of a VMO
876    #[test]
877    fn duplicate() {
878        let hello_length: usize = 5;
879
880        // Create a VMO and write some data to it.
881        let vmo = Vmo::create(hello_length as u64).unwrap();
882        assert!(vmo.write(b"hello", 0).is_ok());
883
884        // Replace, reducing rights to read.
885        let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap();
886        // Make sure we can read but not write.
887        let mut read_vec = vec![0; hello_length];
888        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
889        assert_eq!(read_vec, b"hello");
890        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
891
892        // Write new data to the original handle, and read it from the new handle
893        assert!(vmo.write(b"bye", 0).is_ok());
894        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
895        assert_eq!(read_vec, b"byelo");
896    }
897
898    // Test replace by means of a VMO
899    #[test]
900    fn replace() {
901        let hello_length: usize = 5;
902
903        // Create a VMO and write some data to it.
904        let vmo = Vmo::create(hello_length as u64).unwrap();
905        assert!(vmo.write(b"hello", 0).is_ok());
906
907        // Replace, reducing rights to read.
908        let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap();
909        // Make sure we can read but not write.
910        let mut read_vec = vec![0; hello_length];
911        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
912        assert_eq!(read_vec, b"hello");
913        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
914    }
915
916    #[test]
917    fn set_get_name() {
918        // We need some concrete object to exercise the AsHandleRef<'_> set/get_name functions.
919        let vmo = Vmo::create(1).unwrap();
920        let short_name = Name::new("v").unwrap();
921        assert!(vmo.set_name(&short_name).is_ok());
922        assert_eq!(vmo.get_name().unwrap(), short_name);
923    }
924
925    #[test]
926    fn set_get_max_len_name() {
927        let vmo = Vmo::create(1).unwrap();
928        let max_len_name = Name::new("a_great_maximum_length_vmo_name").unwrap(); // 31 bytes
929        assert!(vmo.set_name(&max_len_name).is_ok());
930        assert_eq!(vmo.get_name().unwrap(), max_len_name);
931    }
932
933    #[test]
934    fn basic_info_channel() {
935        let (side1, side2) = Channel::create();
936        let info1 = side1.basic_info().expect("side1 basic_info failed");
937        let info2 = side2.basic_info().expect("side2 basic_info failed");
938
939        assert_eq!(info1.koid, info2.related_koid);
940        assert_eq!(info2.koid, info1.related_koid);
941
942        for info in &[info1, info2] {
943            assert!(info.koid.raw_koid() >= sys::ZX_KOID_FIRST);
944            assert_eq!(info.object_type, ObjectType::CHANNEL);
945            assert!(info.rights.contains(Rights::READ | Rights::WRITE | Rights::WAIT));
946        }
947
948        let side1_repl = side1.replace_handle(Rights::READ).expect("side1 replace_handle failed");
949        let info1_repl = side1_repl.basic_info().expect("side1_repl basic_info failed");
950        assert_eq!(info1_repl.koid, info1.koid);
951        assert_eq!(info1_repl.rights, Rights::READ);
952    }
953
954    #[test]
955    fn basic_info_vmar() {
956        // VMARs aren't waitable.
957        let root_vmar = fuchsia_runtime::vmar_root_self();
958        let info = root_vmar.basic_info().expect("vmar basic_info failed");
959        assert_eq!(info.object_type, ObjectType::VMAR);
960        assert!(!info.rights.contains(Rights::WAIT));
961    }
962
963    #[test]
964    fn count_info() {
965        let vmo0 = Vmo::create(1).unwrap();
966        let count_info = vmo0.count_info().expect("vmo0 count_info failed");
967        assert_eq!(count_info.handle_count, 1);
968
969        let vmo1 = vmo0.duplicate_handle(Rights::SAME_RIGHTS).expect("vmo duplicate_handle failed");
970        let count_info = vmo1.count_info().expect("vmo1 count_info failed");
971        assert_eq!(count_info.handle_count, 2);
972    }
973
974    #[test]
975    fn raw_handle_disposition() {
976        const RAW_HANDLE: sys::zx_handle_t = 1;
977        let hd = HandleDisposition::new(
978            HandleOp::Move(unsafe { NullableHandle::from_raw(RAW_HANDLE) }),
979            ObjectType::VMO,
980            Rights::EXECUTE,
981            Status::OK,
982        );
983        let raw_hd = hd.into_raw();
984        assert_eq!(raw_hd.operation, sys::ZX_HANDLE_OP_MOVE);
985        assert_eq!(raw_hd.handle, RAW_HANDLE);
986        assert_eq!(raw_hd.rights, sys::ZX_RIGHT_EXECUTE);
987        assert_eq!(raw_hd.type_, sys::ZX_OBJ_TYPE_VMO);
988        assert_eq!(raw_hd.result, sys::ZX_OK);
989    }
990
991    #[test]
992    fn regression_nullable_handle_into_raw_recursion() {
993        let h = NullableHandle::invalid();
994        // This should not stack overflow
995        assert_eq!(h.into_raw(), sys::ZX_HANDLE_INVALID);
996
997        let vmo = Vmo::create(1).unwrap();
998        let raw = vmo.raw_handle();
999        let h = vmo.into_handle();
1000        // This should not stack overflow
1001        assert_eq!(h.into_raw(), raw);
1002    }
1003
1004    #[test]
1005    fn handle_info_from_raw() {
1006        const RAW_HANDLE: sys::zx_handle_t = 1;
1007        let raw_hi = sys::zx_handle_info_t {
1008            handle: RAW_HANDLE,
1009            ty: sys::ZX_OBJ_TYPE_VMO,
1010            rights: sys::ZX_RIGHT_EXECUTE,
1011            unused: 128,
1012        };
1013        let hi = unsafe { HandleInfo::from_raw(raw_hi) };
1014        assert_eq!(hi.handle.into_raw(), RAW_HANDLE);
1015        assert_eq!(hi.object_type, ObjectType::VMO);
1016        assert_eq!(hi.rights, Rights::EXECUTE);
1017    }
1018
1019    #[test]
1020    fn basic_peer_closed() {
1021        let (lhs, rhs) = crate::EventPair::create();
1022        assert!(!lhs.is_closed().unwrap());
1023        assert!(!rhs.is_closed().unwrap());
1024        drop(rhs);
1025        assert!(lhs.is_closed().unwrap());
1026    }
1027}