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