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