Skip to main content

zx/channel/
mod.rs

1// Copyright 2017 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 channel objects.
6
7use crate::{
8    HandleDisposition, HandleInfo, MonotonicInstant, NullableHandle, Peered, Status, ok, sys,
9};
10use std::mem::MaybeUninit;
11
12mod io_slice;
13mod message_buf;
14pub use self::io_slice::*;
15pub use self::message_buf::*;
16
17/// An object representing a Zircon
18/// [channel](https://fuchsia.dev/fuchsia-src/concepts/objects/channel.md).
19///
20/// As essentially a subtype of `NullableHandle`, it can be freely interconverted.
21#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
22#[repr(transparent)]
23pub struct Channel(NullableHandle);
24impl_handle_based!(Channel);
25impl Peered for Channel {}
26
27impl Channel {
28    /// Create a channel, resulting in a pair of `Channel` objects representing both
29    /// sides of the channel. Messages written into one may be read from the opposite.
30    ///
31    /// Wraps the
32    /// [zx_channel_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_create.md)
33    /// syscall.
34    ///
35    /// # Panics
36    ///
37    /// If the process' job policy denies channel creation or the kernel reports no memory
38    /// available to create a new channel.
39    pub fn create() -> (Self, Self) {
40        unsafe {
41            let mut handle0 = 0;
42            let mut handle1 = 0;
43            let opts = 0;
44            ok(sys::zx_channel_create(opts, &mut handle0, &mut handle1)).expect(
45                "channel creation always succeeds except with OOM or when job policy denies it",
46            );
47            (Self(NullableHandle::from_raw(handle0)), Self(NullableHandle::from_raw(handle1)))
48        }
49    }
50
51    /// Read a message from a channel. Wraps the
52    /// [zx_channel_read](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_read.md)
53    /// syscall. Care should be taken to avoid handle leaks by either transferring the
54    /// returned handles out to another type or dropping them explicitly.
55    pub fn read_uninit<'b, 'h>(
56        &self,
57        bytes: &'b mut [MaybeUninit<u8>],
58        handles: &'h mut [MaybeUninit<NullableHandle>],
59    ) -> ChannelReadResult<(&'b mut [u8], &'h mut [NullableHandle])> {
60        // SAFETY: bytes and handles are valid to write to for their lengths
61        match unsafe {
62            self.read_raw(
63                bytes.as_mut_ptr().cast::<u8>(),
64                bytes.len(),
65                handles.as_mut_ptr().cast::<NullableHandle>(),
66                handles.len(),
67            )
68        } {
69            ChannelReadResult::Ok((actual_bytes, actual_handles)) => {
70                // SAFETY: if the above call succeeded, the buffers are initialized up to actual_*
71                ChannelReadResult::Ok(unsafe {
72                    (
73                        std::slice::from_raw_parts_mut(
74                            bytes.as_mut_ptr().cast::<u8>(),
75                            actual_bytes as usize,
76                        ),
77                        std::slice::from_raw_parts_mut(
78                            handles.as_mut_ptr().cast::<NullableHandle>(),
79                            actual_handles as usize,
80                        ),
81                    )
82                })
83            }
84            ChannelReadResult::BufferTooSmall { bytes_avail, handles_avail } => {
85                ChannelReadResult::BufferTooSmall { bytes_avail, handles_avail }
86            }
87            ChannelReadResult::Err(e) => ChannelReadResult::Err(e),
88        }
89    }
90
91    /// Read a message from a channel. Wraps the
92    /// [zx_channel_read](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_read.md)
93    /// syscall.
94    ///
95    /// # Safety
96    ///
97    /// `bytes` must be valid to write to for `bytes_len` bytes. `handles` must be valid to write
98    /// to for `handles_len` elements.
99    pub unsafe fn read_raw(
100        &self,
101        bytes: *mut u8,
102        bytes_len: usize,
103        handles: *mut NullableHandle,
104        handles_len: usize,
105    ) -> ChannelReadResult<(usize, usize)> {
106        // SAFETY: invariants for these pointers are upheld by our caller.
107        unsafe {
108            let raw_handle = self.raw_handle();
109            let mut actual_bytes = 0;
110            let mut actual_handles = 0;
111            let status = ok(sys::zx_channel_read(
112                raw_handle,
113                0, // opts
114                bytes,
115                handles.cast::<sys::zx_handle_t>(),
116                bytes_len as u32,
117                handles_len as u32,
118                &mut actual_bytes,
119                &mut actual_handles,
120            ));
121            match status {
122                Ok(()) => ChannelReadResult::Ok((actual_bytes as usize, actual_handles as usize)),
123                Err(Status::BUFFER_TOO_SMALL) => ChannelReadResult::BufferTooSmall {
124                    bytes_avail: actual_bytes as usize,
125                    handles_avail: actual_handles as usize,
126                },
127                Err(e) => ChannelReadResult::Err(e),
128            }
129        }
130    }
131
132    /// Read a message from a channel.
133    ///
134    /// Note that this method can cause internal reallocations in the `MessageBuf`
135    /// if it is lacks capacity to hold the full message. If such reallocations
136    /// are not desirable, use `read_raw` instead.
137    pub fn read(&self, buf: &mut MessageBuf) -> Result<(), Status> {
138        let (bytes, handles) = buf.split_mut();
139        self.read_split(bytes, handles)
140    }
141
142    /// Read a message from a channel into a separate byte vector and handle vector.
143    ///
144    /// If the provided `handles` has any elements, they will be dropped before reading from the
145    /// channel.
146    ///
147    /// Note that this method can cause internal reallocations in the `Vec`s
148    /// if they lacks capacity to hold the full message. If such reallocations
149    /// are not desirable, use `read_uninit` instead.
150    pub fn read_split(
151        &self,
152        bytes: &mut Vec<u8>,
153        handles: &mut Vec<NullableHandle>,
154    ) -> Result<(), Status> {
155        loop {
156            // Ensure the capacity slices are the entire `Vec`s.
157            bytes.truncate(0);
158            handles.truncate(0);
159            match self.read_uninit(bytes.spare_capacity_mut(), handles.spare_capacity_mut()) {
160                ChannelReadResult::Ok((byte_slice, handle_slice)) => {
161                    // Drop the output slices before mutating the input buffers.
162                    let (bytes_len, handles_len) = (byte_slice.len(), handle_slice.len());
163                    drop((byte_slice, handle_slice));
164
165                    // SAFETY: the kernel has initialized the vecs up to the length of these slices.
166                    unsafe {
167                        bytes.set_len(bytes_len);
168                        handles.set_len(handles_len);
169                    }
170                    return Ok(());
171                }
172                ChannelReadResult::BufferTooSmall { bytes_avail, handles_avail } => {
173                    ensure_capacity(bytes, bytes_avail);
174                    ensure_capacity(handles, handles_avail);
175                }
176                ChannelReadResult::Err(e) => return Err(e),
177            }
178        }
179    }
180
181    /// Read a message from a channel. Care should be taken to avoid handle leaks by either
182    /// transferring the returned handles out to another type or dropping them explicitly.
183    ///
184    /// This differs from `read_uninit`, in that it uses extended handle info.
185    ///
186    /// Wraps the
187    /// [zx_channel_read](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_read.md)
188    /// syscall.
189    pub fn read_etc_uninit<'b, 'h>(
190        &self,
191        bytes: &'b mut [MaybeUninit<u8>],
192        handles: &'h mut [MaybeUninit<HandleInfo>],
193    ) -> ChannelReadResult<(&'b mut [u8], &'h mut [HandleInfo])> {
194        // SAFETY: bytes and handles are valid to write to for their lengths
195        match unsafe {
196            self.read_etc_raw(
197                bytes.as_mut_ptr().cast::<u8>(),
198                bytes.len(),
199                handles.as_mut_ptr().cast::<HandleInfo>(),
200                handles.len(),
201            )
202        } {
203            ChannelReadResult::Ok((actual_bytes, actual_handles)) => {
204                // SAFETY: if the above call succeeded, the buffers are initialized up to actual_*
205                ChannelReadResult::Ok(unsafe {
206                    (
207                        std::slice::from_raw_parts_mut(
208                            bytes.as_mut_ptr().cast::<u8>(),
209                            actual_bytes as usize,
210                        ),
211                        std::slice::from_raw_parts_mut(
212                            handles.as_mut_ptr().cast::<HandleInfo>(),
213                            actual_handles as usize,
214                        ),
215                    )
216                })
217            }
218            ChannelReadResult::BufferTooSmall { bytes_avail, handles_avail } => {
219                ChannelReadResult::BufferTooSmall { bytes_avail, handles_avail }
220            }
221            ChannelReadResult::Err(e) => ChannelReadResult::Err(e),
222        }
223    }
224
225    /// Read a message from a channel.
226    /// Wraps the [zx_channel_read_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_read_etc.md)
227    /// syscall.
228    ///
229    /// This differs from `read_raw` in that it returns extended information on
230    /// the handles.
231    ///
232    /// On success, returns the number of bytes and handles read.
233    ///
234    /// # Safety
235    ///
236    /// `bytes` must be valid to write to for `bytes_len` bytes.
237    ///
238    /// `handles` must be valid to write to for `handles_len` elements.
239    pub unsafe fn read_etc_raw(
240        &self,
241        bytes: *mut u8,
242        bytes_len: usize,
243        handles: *mut HandleInfo,
244        handles_len: usize,
245    ) -> ChannelReadResult<(usize, usize)> {
246        // SAFETY: our caller upholds the require invariants. It is sound to interpret
247        // HandleInfo as zx_handle_info_t as they have identical layouts.
248        unsafe {
249            let mut actual_bytes = 0;
250            let mut actual_handles = 0;
251            let status = ok(sys::zx_channel_read_etc(
252                self.raw_handle(),
253                0, // options
254                bytes,
255                handles.cast::<sys::zx_handle_info_t>(),
256                bytes_len as u32,
257                handles_len as u32,
258                &mut actual_bytes,
259                &mut actual_handles,
260            ));
261            match status {
262                Ok(()) => ChannelReadResult::Ok((actual_bytes as usize, actual_handles as usize)),
263                Err(Status::BUFFER_TOO_SMALL) => ChannelReadResult::BufferTooSmall {
264                    bytes_avail: actual_bytes as usize,
265                    handles_avail: actual_handles as usize,
266                },
267                Err(e) => ChannelReadResult::Err(e),
268            }
269        }
270    }
271
272    /// Read a message from a channel.
273    ///
274    /// This differs from `read` in that it returns extended information on
275    /// the handles.
276    ///
277    /// Note that this method can cause internal reallocations in the `MessageBufEtc`
278    /// if it is lacks capacity to hold the full message. If such reallocations
279    /// are not desirable, use `read_etc_uninit` or `read_etc_raw` instead.
280    pub fn read_etc(&self, buf: &mut MessageBufEtc) -> Result<(), Status> {
281        let (bytes, handles) = buf.split_mut();
282        self.read_etc_split(bytes, handles)
283    }
284
285    /// Read a message from a channel into a separate byte vector and handle vector.
286    ///
287    /// This differs from `read_split` in that it returns extended information on
288    /// the handles.
289    ///
290    /// Note that this method can cause internal reallocations in the `Vec`s
291    /// if they lacks capacity to hold the full message. If such reallocations
292    /// are not desirable, use `read_etc_uninit` or `read_etc_raw` instead.
293    pub fn read_etc_split(
294        &self,
295        bytes: &mut Vec<u8>,
296        handles: &mut Vec<HandleInfo>,
297    ) -> Result<(), Status> {
298        loop {
299            bytes.clear();
300            handles.clear();
301            match self.read_etc_uninit(bytes.spare_capacity_mut(), handles.spare_capacity_mut()) {
302                ChannelReadResult::Ok((byte_slice, handle_slice)) => {
303                    // Drop the output slices before mutating the input buffers.
304                    let (bytes_len, handles_len) = (byte_slice.len(), handle_slice.len());
305                    drop((byte_slice, handle_slice));
306
307                    // SAFETY: the kernel has initialized the vecs up to the length of these slices.
308                    unsafe {
309                        bytes.set_len(bytes_len);
310                        handles.set_len(handles_len);
311                    }
312                    return Ok(());
313                }
314                ChannelReadResult::BufferTooSmall { bytes_avail, handles_avail } => {
315                    ensure_capacity(bytes, bytes_avail);
316                    ensure_capacity(handles, handles_avail);
317                }
318                ChannelReadResult::Err(e) => return Err(e),
319            }
320        }
321    }
322
323    /// Write a message to a channel. Wraps the
324    /// [zx_channel_write](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_write.md)
325    /// syscall.
326    ///
327    /// On return, the elements pointed to by `handles` will have been zeroed to reflect
328    /// the fact that the handles have been transferred.
329    pub fn write(&self, bytes: &[u8], handles: &mut [NullableHandle]) -> Result<(), Status> {
330        // SAFETY: provided pointers are valid because they come from references.
331        unsafe { self.write_raw(bytes.as_ptr(), bytes.len(), handles.as_mut_ptr(), handles.len()) }
332    }
333
334    /// Write a message to a channel from a set of disjoint buffers. Wraps the
335    /// [zx_channel_write](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_write.md)
336    /// syscall.
337    ///
338    /// On return, the elements pointed to by `handles` will have been zeroed to reflect
339    /// the fact that the handles have been transferred.
340    pub fn writev(
341        &self,
342        buffers: &[ChannelIoSlice<'_>],
343        handles: &mut [NullableHandle],
344    ) -> Result<(), Status> {
345        // SAFETY: provided pointers are valid because they come from references.
346        unsafe {
347            self.writev_raw(buffers.as_ptr(), buffers.len(), handles.as_mut_ptr(), handles.len())
348        }
349    }
350
351    /// Write a message to a channel. Wraps the
352    /// [zx_channel_write](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_write.md)
353    /// syscall.
354    ///
355    /// On return, the elements pointed to by `handles` will have been zeroed to reflect the
356    /// fact that the handles have been transferred.
357    ///
358    /// # Safety
359    ///
360    /// `bytes` must be valid to read from for `bytes_len` elements.
361    ///
362    /// `handles` must be valid to read from and write to for `handles_len` elements.
363    pub unsafe fn write_raw(
364        &self,
365        bytes: *const u8,
366        bytes_len: usize,
367        handles: *mut NullableHandle,
368        handles_len: usize,
369    ) -> Result<(), Status> {
370        // SAFETY: caller is responsible for upholding pointer invariants. `NullableHandle` is a
371        // `repr(transparent)` wrapper around `zx_handle_t`.
372        let res = unsafe {
373            ok(sys::zx_channel_write(
374                self.raw_handle(),
375                0, // options
376                bytes,
377                bytes_len as u32,
378                handles.cast::<sys::zx_handle_t>(),
379                handles_len as u32,
380            ))
381        };
382
383        // Outgoing handles have been consumed by zx_channel_write_etc. Zero them to inhibit drop
384        // implementations.
385        // SAFETY: caller guarantees that `handles` is valid to write to for `handles_len`
386        // elements. `NullableHandle` is valid when it is all zeroes.
387        unsafe {
388            std::ptr::write_bytes(handles, 0, handles_len);
389        }
390
391        res
392    }
393
394    /// Write a message to a channel from a set of disjoint buffers. Wraps the
395    /// [zx_channel_write](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_write.md)
396    /// syscall.
397    ///
398    /// On return, the elements pointed to by `handles` will have been zeroed to reflect the
399    /// fact that the handles have been transferred.
400    ///
401    /// # Safety
402    ///
403    /// `buffers` must be valid to read from for `buffers_len` elements.
404    ///
405    /// `handles` must be valid to read from and write to for `handles_len` elements.
406    pub unsafe fn writev_raw(
407        &self,
408        buffers: *const ChannelIoSlice<'_>,
409        buffers_len: usize,
410        handles: *mut NullableHandle,
411        handles_len: usize,
412    ) -> Result<(), Status> {
413        // SAFETY: caller is responsible for upholding pointer invariants. `NullableHandle` is a
414        // `repr(transparent)` wrapper around `zx_handle_t`.
415        let res = unsafe {
416            ok(sys::zx_channel_write(
417                self.raw_handle(),
418                sys::ZX_CHANNEL_WRITE_USE_IOVEC,
419                buffers.cast::<u8>(),
420                buffers_len as u32,
421                handles.cast::<sys::zx_handle_t>(),
422                handles_len as u32,
423            ))
424        };
425
426        // Outgoing handles have been consumed by zx_channel_write_etc. Zero them to inhibit drop
427        // implementations.
428        // SAFETY: caller guarantees that `handles` is valid to write to for `handles_len`
429        // elements. `NullableHandle` is valid when it is all zeroes.
430        unsafe {
431            std::ptr::write_bytes(handles, 0, handles_len);
432        }
433
434        res
435    }
436
437    /// Write a message to a channel. Wraps the
438    /// [zx_channel_write_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_write_etc.md)
439    /// syscall.
440    ///
441    /// This differs from `write`, in that it uses extended handle info.
442    ///
443    /// On return, the elements pointed to by `handles` will have been zeroed to reflect the
444    /// fact that the handles have been transferred.
445    pub fn write_etc(
446        &self,
447        bytes: &[u8],
448        handles: &mut [HandleDisposition<'_>],
449    ) -> Result<(), Status> {
450        // SAFETY: provided pointers come from valid references.
451        unsafe {
452            self.write_etc_raw(bytes.as_ptr(), bytes.len(), handles.as_mut_ptr(), handles.len())
453        }
454    }
455
456    /// Write a message to a channel from a set of disjoint buffers. Wraps the
457    /// [zx_channel_write_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_write_etc.md)
458    /// syscall.
459    ///
460    /// This differs from `writev`, in that it uses extended handle info.
461    ///
462    /// On return, the elements pointed to by `handles` will have been zeroed to reflect the
463    /// fact that the handles have been transferred.
464    pub fn writev_etc(
465        &self,
466        buffers: &[ChannelIoSlice<'_>],
467        handles: &mut [HandleDisposition<'_>],
468    ) -> Result<(), Status> {
469        // SAFETY: provided pointers come from valid references.
470        unsafe {
471            self.writev_etc_raw(
472                buffers.as_ptr(),
473                buffers.len(),
474                handles.as_mut_ptr(),
475                handles.len(),
476            )
477        }
478    }
479
480    /// Write a message to a channel. Wraps the
481    /// [zx_channel_write_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_write_etc.md)
482    /// syscall.
483    ///
484    /// This differs from `write_raw`, in that it uses extended handle info.
485    ///
486    /// On return, the elements pointed to by `handles` will have been zeroed to reflect the
487    /// fact that the handles have been transferred.
488    ///
489    /// # Safety
490    ///
491    /// `bytes` must be valid to read from for `bytes_len` bytes.
492    ///
493    /// `handles` must be valid to read from and write to for `handles_len` elements.
494    pub unsafe fn write_etc_raw(
495        &self,
496        bytes: *const u8,
497        bytes_len: usize,
498        handles: *mut HandleDisposition<'_>,
499        handles_len: usize,
500    ) -> Result<(), Status> {
501        // SAFETY: caller is responsible for upholding pointer invariants. HandleDisposition is
502        // ABI-compatible with zx_handle_disposition_t, we can treat them interchangeably.
503        let res = unsafe {
504            ok(sys::zx_channel_write_etc(
505                self.raw_handle(),
506                0, // options
507                bytes,
508                bytes_len as u32,
509                handles.cast::<sys::zx_handle_disposition_t>(),
510                handles_len as u32,
511            ))
512        };
513
514        // Outgoing handles are consumed by zx_channel_write_etc so prevent the destructor from
515        // being called. Don't overwrite the status field so that callers can inspect it.
516        // SAFETY: mutable slice invariants are upheld by this method's caller
517        let handles = unsafe { std::slice::from_raw_parts_mut(handles, handles_len) };
518        for disposition in handles {
519            std::mem::forget(disposition.take_op());
520        }
521
522        res
523    }
524
525    /// Write a message to a channel from a set of disjoint buffers. Wraps the
526    /// [zx_channel_write_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_write_etc.md)
527    /// syscall.
528    ///
529    /// This differs from `writev_raw`, in that it uses extended handle info.
530    ///
531    /// On return, the elements pointed to by `handles` will have been zeroed to reflect the
532    /// fact that the handles have been transferred.
533    ///
534    /// # Safety
535    ///
536    /// `buffers` must be valid to read from for `buffers_len` elements.
537    ///
538    /// `handles` must be valid to read from and write to for `handles_len` elements.
539    pub unsafe fn writev_etc_raw(
540        &self,
541        buffers: *const ChannelIoSlice<'_>,
542        buffers_len: usize,
543        handles: *mut HandleDisposition<'_>,
544        handles_len: usize,
545    ) -> Result<(), Status> {
546        // SAFETY: caller is responsible for upholding pointer invariants. HandleDisposition is
547        // ABI-compatible with zx_handle_disposition_t, we can treat them interchangeably.
548        let res = unsafe {
549            ok(sys::zx_channel_write_etc(
550                self.raw_handle(),
551                sys::ZX_CHANNEL_WRITE_USE_IOVEC,
552                buffers.cast::<u8>(),
553                buffers_len as u32,
554                handles.cast::<sys::zx_handle_disposition_t>(),
555                handles_len as u32,
556            ))
557        };
558
559        // Outgoing handles are consumed by zx_channel_write_etc so prevent the destructor from
560        // being called. Don't overwrite the status field so that callers can inspect it.
561        // SAFETY: mutable slice invariants are upheld by this method's caller
562        let handles = unsafe { std::slice::from_raw_parts_mut(handles, handles_len) };
563        for disposition in handles {
564            std::mem::forget(disposition.take_op());
565        }
566
567        res
568    }
569
570    /// Send a message consisting of the given bytes and handles to a channel and block until a
571    /// reply is received or the timeout is reached.
572    ///
573    /// On return, the elements pointed to by `handles` will have been zeroed to reflect the
574    /// fact that the handles have been transferred.
575    ///
576    /// The first four bytes of the written and read back messages are treated as a transaction ID
577    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
578    /// part of the message as read from userspace. In other words, the first four bytes of
579    /// `bytes` will be ignored, and the first four bytes of the response will contain a
580    /// kernel-generated txid.
581    ///
582    /// In order to avoid dropping replies, the provided `MessageBuf` will be resized to accommodate
583    /// the maximum channel message size. For performance-sensitive code, consider reusing
584    /// `MessageBuf`s or calling `call_uninit` with a stack-allocated buffer.
585    ///
586    /// Wraps the
587    /// [zx_channel_call](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call.md)
588    /// syscall.
589    ///
590    /// On failure returns the both the main and read status.
591    pub fn call(
592        &self,
593        timeout: MonotonicInstant,
594        bytes: &[u8],
595        handles: &mut [NullableHandle],
596        buf: &mut MessageBuf,
597    ) -> Result<(), Status> {
598        buf.clear();
599        buf.ensure_capacity_bytes(sys::ZX_CHANNEL_MAX_MSG_BYTES as usize);
600        buf.ensure_capacity_handles(sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize);
601
602        let (actual_bytes, actual_handles) = self.call_uninit(
603            timeout,
604            bytes,
605            handles,
606            buf.bytes.spare_capacity_mut(),
607            buf.handles.spare_capacity_mut(),
608        )?;
609
610        // Drop the output slices before mutating the input buffers.
611        let (bytes_len, handles_len) = (actual_bytes.len(), actual_handles.len());
612        drop((actual_bytes, actual_handles));
613
614        // SAFETY: the kernel has initialized these slices with valid values after the call above
615        // succeeded.
616        unsafe {
617            buf.bytes.set_len(bytes_len);
618            buf.handles.set_len(handles_len);
619        }
620
621        Ok(())
622    }
623
624    /// Send a message consisting of the given disjoint buffers and handles to a channel and block
625    /// until a reply is received or the timeout is reached.
626    ///
627    /// On return, the elements pointed to by `handles` will have been zeroed to reflect the
628    /// fact that the handles have been transferred.
629    ///
630    /// The first four bytes of the written and read back messages are treated as a transaction ID
631    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
632    /// part of the message as read from userspace. In other words, the first four bytes pointed to
633    /// by `buffers_in` will be ignored, and the first four bytes of the response will contain a
634    /// kernel-generated txid.
635    ///
636    /// In order to avoid dropping replies, the provided `MessageBuf` will be resized to accommodate
637    /// the maximum channel message size. For performance-sensitive code, consider reusing
638    /// `MessageBuf`s or calling `callv_uninit` with a stack-allocated buffer.
639    ///
640    /// Wraps the
641    /// [zx_channel_call](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call.md)
642    /// syscall.
643    ///
644    /// On failure returns the both the main and read status.
645    pub fn callv(
646        &self,
647        timeout: MonotonicInstant,
648        buffers_in: &[ChannelIoSlice<'_>],
649        handles: &mut [NullableHandle],
650        buf: &mut MessageBuf,
651    ) -> Result<(), Status> {
652        buf.clear();
653        buf.ensure_capacity_bytes(sys::ZX_CHANNEL_MAX_MSG_BYTES as usize);
654        buf.ensure_capacity_handles(sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize);
655
656        let (actual_bytes, actual_handles) = self.callv_uninit(
657            timeout,
658            buffers_in,
659            handles,
660            buf.bytes.spare_capacity_mut(),
661            buf.handles.spare_capacity_mut(),
662        )?;
663
664        // Drop the output slices before mutating the input buffers.
665        let (bytes_len, handles_len) = (actual_bytes.len(), actual_handles.len());
666        drop((actual_bytes, actual_handles));
667
668        // SAFETY: the kernel has initialized these slices with valid values after the call above
669        // succeeded.
670        unsafe {
671            buf.bytes.set_len(bytes_len);
672            buf.handles.set_len(handles_len);
673        }
674
675        Ok(())
676    }
677
678    /// Send a message consisting of the given bytes and handles to a channel and block until a
679    /// reply is received or the timeout is reached. Returns initialized slices of byte message and
680    /// handles on success. Care should be taken to avoid handle leaks by either transferring the
681    /// returned handles out to another type or dropping them explicitly.
682    ///
683    /// On return, the elements pointed to by `handles_in` will have been zeroed to reflect the
684    /// fact that the handles have been transferred.
685    ///
686    /// The first four bytes of the written and read back messages are treated as a transaction ID
687    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
688    /// part of the message as read from userspace. In other words, the first four bytes of
689    /// `bytes_in` will be ignored, and the first four bytes of the response will contain a
690    /// kernel-generated txid.
691    ///
692    /// In order to avoid dropping replies, this wrapper requires that the provided out buffers have
693    /// enough space to handle the largest channel messages possible.
694    ///
695    /// Wraps the
696    /// [zx_channel_call](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call.md)
697    /// syscall.
698    ///
699    /// On failure returns the both the main and read status.
700    pub fn call_uninit<'b, 'h>(
701        &self,
702        timeout: MonotonicInstant,
703        bytes_in: &[u8],
704        handles_in: &mut [NullableHandle],
705        bytes_out: &'b mut [MaybeUninit<u8>],
706        handles_out: &'h mut [MaybeUninit<NullableHandle>],
707    ) -> Result<(&'b mut [u8], &'h mut [NullableHandle]), Status> {
708        // SAFETY: in-pointers are both valid to read from for their provided lengths, and
709        // out-pointers are both valid to write to for their provided lengths.
710        let (actual_bytes, actual_handles) = unsafe {
711            self.call_raw(
712                timeout,
713                bytes_in.as_ptr(),
714                bytes_in.len(),
715                handles_in.as_mut_ptr(),
716                handles_in.len(),
717                bytes_out.as_mut_ptr().cast::<u8>(),
718                bytes_out.len(),
719                handles_out.as_mut_ptr().cast::<NullableHandle>(),
720                handles_out.len(),
721            )?
722        };
723
724        // SAFETY: the kernel has initialized these slices with valid values.
725        unsafe {
726            Ok((
727                std::slice::from_raw_parts_mut(
728                    bytes_out.as_mut_ptr().cast::<u8>(),
729                    actual_bytes as usize,
730                ),
731                std::slice::from_raw_parts_mut(
732                    handles_out.as_mut_ptr().cast::<NullableHandle>(),
733                    actual_handles as usize,
734                ),
735            ))
736        }
737    }
738
739    /// Send a message consisting of the given disjoint buffers and handles to a channel and block
740    /// until a reply is received or the timeout is reached. Returns initialized slices of byte
741    /// message and handles on success. Care should be taken to avoid handle leaks by either
742    /// transferring the returned handles out to another type or dropping them explicitly.
743    ///
744    /// On return, the elements pointed to by `handles_in` will have been zeroed to reflect the
745    /// fact that the handles have been transferred.
746    ///
747    /// The first four bytes of the written and read back messages are treated as a transaction ID
748    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
749    /// part of the message as read from userspace. In other words, the first four bytes pointed to
750    /// by `buffers_in` will be ignored, and the first four bytes of the response will contain a
751    /// kernel-generated txid.
752    ///
753    /// In order to avoid dropping replies, this wrapper requires that the provided out buffers have
754    /// enough space to handle the largest channel messages possible.
755    ///
756    /// Wraps the
757    /// [zx_channel_call](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call.md)
758    /// syscall.
759    ///
760    /// On failure returns the both the main and read status.
761    pub fn callv_uninit<'b, 'h>(
762        &self,
763        timeout: MonotonicInstant,
764        buffers_in: &[ChannelIoSlice<'_>],
765        handles_in: &mut [NullableHandle],
766        bytes_out: &'b mut [MaybeUninit<u8>],
767        handles_out: &'h mut [MaybeUninit<NullableHandle>],
768    ) -> Result<(&'b mut [u8], &'h mut [NullableHandle]), Status> {
769        // SAFETY: in-pointers are both valid to read from for their provided lengths, and
770        // out-pointers are both valid to write to for their provided lengths.
771        let (actual_bytes, actual_handles) = unsafe {
772            self.callv_raw(
773                timeout,
774                buffers_in.as_ptr(),
775                buffers_in.len(),
776                handles_in.as_mut_ptr(),
777                handles_in.len(),
778                bytes_out.as_mut_ptr().cast::<u8>(),
779                bytes_out.len(),
780                handles_out.as_mut_ptr().cast::<NullableHandle>(),
781                handles_out.len(),
782            )?
783        };
784
785        // SAFETY: the kernel has initialized these slices with valid values.
786        unsafe {
787            Ok((
788                std::slice::from_raw_parts_mut(
789                    bytes_out.as_mut_ptr().cast::<u8>(),
790                    actual_bytes as usize,
791                ),
792                std::slice::from_raw_parts_mut(
793                    handles_out.as_mut_ptr().cast::<NullableHandle>(),
794                    actual_handles as usize,
795                ),
796            ))
797        }
798    }
799
800    /// Send a message consisting of the given bytes and handles to a channel and block until a
801    /// reply is received or the timeout is reached. On success, returns the number of bytes and
802    /// handles read from the reply, in that order.
803    ///
804    /// The first four bytes of the written and read back messages are treated as a transaction ID
805    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
806    /// part of the message as read from userspace. In other words, the first four bytes of
807    /// `bytes_in` will be ignored, and the first four bytes of the response will contain a
808    /// kernel-generated txid.
809    ///
810    /// In order to avoid dropping replies, this wrapper requires that the provided out buffers have
811    /// enough space to handle the largest channel messages possible.
812    ///
813    /// On return, the elements pointed to by `handles_in` will have been zeroed to reflect the
814    /// fact that the handles have been transferred.
815    ///
816    /// Wraps the
817    /// [zx_channel_call](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call.md)
818    /// syscall.
819    ///
820    /// On failure returns the both the main and read status.
821    ///
822    /// # Safety
823    ///
824    /// `bytes_in` must be valid to read from for `bytes_in_len` bytes.
825    ///
826    /// `handles_in` must be valid to read from and write to for `handles_in_len` elements.
827    ///
828    /// `bytes_out` must be valid to write to for `bytes_out_len` bytes.
829    ///
830    /// `handles_out` must be valid to write to for `handles_out_len` elements.
831    ///
832    /// `bytes_in` and `bytes_out` may overlap. `handles_in` and `handles_out` may not overlap.
833    pub unsafe fn call_raw(
834        &self,
835        timeout: MonotonicInstant,
836        bytes_in: *const u8,
837        bytes_in_len: usize,
838        handles_in: *mut NullableHandle,
839        handles_in_len: usize,
840        bytes_out: *mut u8,
841        bytes_out_len: usize,
842        handles_out: *mut NullableHandle,
843        handles_out_len: usize,
844    ) -> Result<(usize, usize), Status> {
845        // Don't let replies get silently dropped.
846        if bytes_out_len < sys::ZX_CHANNEL_MAX_MSG_BYTES as usize
847            || handles_out_len < sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize
848        {
849            return Err(Status::BUFFER_TOO_SMALL);
850        }
851
852        let mut actual_read_bytes: u32 = 0;
853        let mut actual_read_handles: u32 = 0;
854
855        // SAFETY: pointer invariants are upheld by this method's caller, see Safety section in
856        // docs. NullableHandle is ABI-compatible with zx_handle_t, this allows the kernel to safely
857        // write the latter and and for us to later interpret them as the former.
858        let res = unsafe {
859            ok(sys::zx_channel_call(
860                self.raw_handle(),
861                0, // options
862                timeout.into_nanos(),
863                &sys::zx_channel_call_args_t {
864                    wr_bytes: bytes_in,
865                    wr_num_bytes: bytes_in_len as u32,
866                    wr_handles: handles_in.cast::<sys::zx_handle_t>(),
867                    wr_num_handles: handles_in_len as u32,
868                    rd_bytes: bytes_out,
869                    rd_num_bytes: bytes_out_len as u32,
870                    rd_handles: handles_out.cast::<sys::zx_handle_t>(),
871                    rd_num_handles: handles_out_len as u32,
872                },
873                &mut actual_read_bytes,
874                &mut actual_read_handles,
875            ))
876        };
877
878        // Outgoing handles have been consumed by zx_channel_call_etc. Zero them to inhibit drop
879        // implementations.
880        // SAFETY: caller guarantees that `handles_in` is valid to write to for `handles_in_len`
881        // elements. `HandleDisposition` is valid when it is all zeroes.
882        unsafe {
883            std::ptr::write_bytes(handles_in, 0, handles_in_len);
884        }
885
886        // Only error-return after zeroing out handles.
887        res?;
888
889        Ok((actual_read_bytes as usize, actual_read_handles as usize))
890    }
891
892    /// Send a message consisting of the given disjoint buffers and handles to a channel and block
893    /// until a reply is received or the timeout is reached. On success, returns the number of bytes
894    /// and handles read from the reply, in that order.
895    ///
896    /// The first four bytes of the written and read back messages are treated as a transaction ID
897    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
898    /// part of the message as read from userspace. In other words, the first four bytes pointed to
899    /// by `buffers_in` will be ignored, and the first four bytes of the response will contain a
900    /// kernel-generated txid.
901    ///
902    /// In order to avoid dropping replies, this wrapper requires that the provided out buffers have
903    /// enough space to handle the largest channel messages possible.
904    ///
905    /// On return, the elements pointed to by `handles_in` will have been zeroed to reflect the
906    /// fact that the handles have been transferred.
907    ///
908    /// Wraps the
909    /// [zx_channel_call](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call.md)
910    /// syscall.
911    ///
912    /// On failure returns the both the main and read status.
913    ///
914    /// # Safety
915    ///
916    /// `buffers_in` must be valid to read from for `buffers_in_len` elements.
917    ///
918    /// `handles_in` must be valid to read from and write to for `handles_in_len` elements.
919    ///
920    /// `bytes_out` must be valid to write to for `bytes_out_len` bytes.
921    ///
922    /// `handles_out` must be valid to write to for `handles_out_len` elements.
923    ///
924    /// None of the provided pointers may overlap.
925    pub unsafe fn callv_raw(
926        &self,
927        timeout: MonotonicInstant,
928        buffers_in: *const ChannelIoSlice<'_>,
929        buffers_in_len: usize,
930        handles_in: *mut NullableHandle,
931        handles_in_len: usize,
932        bytes_out: *mut u8,
933        bytes_out_len: usize,
934        handles_out: *mut NullableHandle,
935        handles_out_len: usize,
936    ) -> Result<(usize, usize), Status> {
937        // Don't let replies get silently dropped.
938        if bytes_out_len < sys::ZX_CHANNEL_MAX_MSG_BYTES as usize
939            || handles_out_len < sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize
940        {
941            return Err(Status::BUFFER_TOO_SMALL);
942        }
943
944        let mut actual_read_bytes: u32 = 0;
945        let mut actual_read_handles: u32 = 0;
946
947        // SAFETY: pointer invariants are upheld by this method's caller, see Safety section in
948        // docs. NullableHandle is ABI-compatible with zx_handle_t, this allows the kernel to safely
949        // write the latter and and for us to later interpret them as the former.
950        let res = unsafe {
951            ok(sys::zx_channel_call(
952                self.raw_handle(),
953                sys::ZX_CHANNEL_WRITE_USE_IOVEC,
954                timeout.into_nanos(),
955                &sys::zx_channel_call_args_t {
956                    wr_bytes: buffers_in.cast::<u8>(),
957                    wr_num_bytes: buffers_in_len as u32,
958                    wr_handles: handles_in.cast::<sys::zx_handle_t>(),
959                    wr_num_handles: handles_in_len as u32,
960                    rd_bytes: bytes_out,
961                    rd_num_bytes: bytes_out_len as u32,
962                    rd_handles: handles_out.cast::<sys::zx_handle_t>(),
963                    rd_num_handles: handles_out_len as u32,
964                },
965                &mut actual_read_bytes,
966                &mut actual_read_handles,
967            ))
968        };
969
970        // Outgoing handles have been consumed by zx_channel_call_etc. Zero them to inhibit drop
971        // implementations.
972        // SAFETY: caller guarantees that `handles_in` is valid to write to for `handles_in_len`
973        // elements. `HandleDisposition` is valid when it is all zeroes.
974        unsafe {
975            std::ptr::write_bytes(handles_in, 0, handles_in_len);
976        }
977
978        // Only error-return after zeroing out handles.
979        res?;
980
981        Ok((actual_read_bytes as usize, actual_read_handles as usize))
982    }
983
984    /// Send a message consisting of the given bytes and handles to a channel and block until a
985    /// reply is received or the timeout is reached.
986    ///
987    /// On return, the elements pointed to by `handle_dispositions` will have been zeroed to reflect
988    /// the fact that the handles have been transferred.
989    ///
990    /// The first four bytes of the written and read back messages are treated as a transaction ID
991    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
992    /// part of the message as read from userspace. In other words, the first four bytes of
993    /// `bytes` will be ignored, and the first four bytes of the response will contain a
994    /// kernel-generated txid.
995    ///
996    /// In order to avoid dropping replies, the provided `MessageBufEtc` will be resized to
997    /// accommodate the maximum channel message size. For performance-sensitive code, consider
998    /// reusing `MessageBufEtc`s or calling `call_etc_uninit` with a stack-allocated buffer.
999    ///
1000    /// This differs from `call`, in that it uses extended handle info.
1001    ///
1002    /// Wraps the
1003    /// [zx_channel_call_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call_etc.md)
1004    /// syscall.
1005    ///
1006    /// On failure returns the both the main and read status.
1007    pub fn call_etc(
1008        &self,
1009        timeout: MonotonicInstant,
1010        bytes: &[u8],
1011        handle_dispositions: &mut [HandleDisposition<'_>],
1012        buf: &mut MessageBufEtc,
1013    ) -> Result<(), Status> {
1014        buf.clear();
1015        buf.ensure_capacity_bytes(sys::ZX_CHANNEL_MAX_MSG_BYTES as usize);
1016        buf.ensure_capacity_handle_infos(sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize);
1017
1018        let (actual_bytes, actual_handles) = self.call_etc_uninit(
1019            timeout,
1020            bytes,
1021            handle_dispositions,
1022            buf.bytes.spare_capacity_mut(),
1023            buf.handle_infos.spare_capacity_mut(),
1024        )?;
1025
1026        // Drop the output slices before mutating the input buffers.
1027        let (bytes_len, handles_len) = (actual_bytes.len(), actual_handles.len());
1028        drop((actual_bytes, actual_handles));
1029
1030        // SAFETY: the kernel has initialized these slices with valid values after the call above
1031        // succeeded.
1032        unsafe {
1033            buf.bytes.set_len(bytes_len);
1034            buf.handle_infos.set_len(handles_len);
1035        }
1036
1037        Ok(())
1038    }
1039
1040    /// Send a message consisting of the given disjoint buffers and handles to a channel and block
1041    /// until a reply is received or the timeout is reached.
1042    ///
1043    /// On return, the elements pointed to by `handle_dispositions` will have been zeroed to reflect
1044    /// the fact that the handles have been transferred.
1045    ///
1046    /// The first four bytes of the written and read back messages are treated as a transaction ID
1047    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
1048    /// part of the message as read from userspace. In other words, the first four bytes pointed to
1049    /// by `buffers_in` will be ignored, and the first four bytes of the response will contain a
1050    /// kernel-generated txid.
1051    ///
1052    /// In order to avoid dropping replies, the provided `MessageBufEtc` will be resized to
1053    /// accommodate the maximum channel message size. For performance-sensitive code, consider
1054    /// reusing `MessageBufEtc`s or calling `call_etc_uninit` with a stack-allocated buffer.
1055    ///
1056    /// This differs from `callv`, in that it uses extended handle info.
1057    ///
1058    /// Wraps the
1059    /// [zx_channel_call_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call_etc.md)
1060    /// syscall.
1061    ///
1062    /// On failure returns the both the main and read status.
1063    pub fn callv_etc(
1064        &self,
1065        timeout: MonotonicInstant,
1066        buffers_in: &[ChannelIoSlice<'_>],
1067        handle_dispositions: &mut [HandleDisposition<'_>],
1068        buf: &mut MessageBufEtc,
1069    ) -> Result<(), Status> {
1070        buf.clear();
1071        buf.ensure_capacity_bytes(sys::ZX_CHANNEL_MAX_MSG_BYTES as usize);
1072        buf.ensure_capacity_handle_infos(sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize);
1073
1074        let (actual_bytes, actual_handles) = self.callv_etc_uninit(
1075            timeout,
1076            buffers_in,
1077            handle_dispositions,
1078            buf.bytes.spare_capacity_mut(),
1079            buf.handle_infos.spare_capacity_mut(),
1080        )?;
1081
1082        // Drop the output slices before mutating the input buffers.
1083        let (bytes_len, handles_len) = (actual_bytes.len(), actual_handles.len());
1084        drop((actual_bytes, actual_handles));
1085
1086        // SAFETY: the kernel has initialized these slices with valid values after the call above
1087        // succeeded.
1088        unsafe {
1089            buf.bytes.set_len(bytes_len);
1090            buf.handle_infos.set_len(handles_len);
1091        }
1092
1093        Ok(())
1094    }
1095
1096    /// Send a message consisting of the given bytes and handles to a channel and block until a
1097    /// reply is received or the timeout is reached. Returns initialized slices of byte message and
1098    /// handles on success. Care should be taken to avoid handle leaks by either transferring the
1099    /// returned handles out to another type or dropping them explicitly.
1100    ///
1101    /// On return, the elements pointed to by `handles_in` will have been zeroed to reflect
1102    /// the fact that the handles have been transferred.
1103    ///
1104    /// The first four bytes of the written and read back messages are treated as a transaction ID
1105    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
1106    /// part of the message as read from userspace. In other words, the first four bytes of
1107    /// `bytes_in` will be ignored, and the first four bytes of the response will contain a
1108    /// kernel-generated txid.
1109    ///
1110    /// This differs from `call_uninit`, in that it uses extended handle info.
1111    ///
1112    /// In order to avoid dropping replies, this wrapper requires that the provided out buffers have
1113    /// enough space to handle the largest channel messages possible.
1114    ///
1115    /// Wraps the
1116    /// [zx_channel_call_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call_etc.md)
1117    /// syscall.
1118    ///
1119    /// On failure returns the both the main and read status.
1120    pub fn call_etc_uninit<'b, 'h>(
1121        &self,
1122        timeout: MonotonicInstant,
1123        bytes_in: &[u8],
1124        handles_in: &mut [HandleDisposition<'_>],
1125        bytes_out: &'b mut [MaybeUninit<u8>],
1126        handles_out: &'h mut [MaybeUninit<HandleInfo>],
1127    ) -> Result<(&'b mut [u8], &'h mut [HandleInfo]), Status> {
1128        // SAFETY: in-pointers are both valid to read from for their provided lengths, and
1129        // out-pointers are both valid to write to for their provided lengths.
1130        let (actual_bytes, actual_handles) = unsafe {
1131            self.call_etc_raw(
1132                timeout,
1133                bytes_in.as_ptr(),
1134                bytes_in.len(),
1135                handles_in.as_mut_ptr(),
1136                handles_in.len(),
1137                bytes_out.as_mut_ptr().cast::<u8>(),
1138                bytes_out.len(),
1139                handles_out.as_mut_ptr().cast::<HandleInfo>(),
1140                handles_out.len(),
1141            )?
1142        };
1143
1144        // SAFETY: the kernel has initialized these slices with valid values.
1145        unsafe {
1146            Ok((
1147                std::slice::from_raw_parts_mut(
1148                    bytes_out.as_mut_ptr().cast::<u8>(),
1149                    actual_bytes as usize,
1150                ),
1151                std::slice::from_raw_parts_mut(
1152                    handles_out.as_mut_ptr().cast::<HandleInfo>(),
1153                    actual_handles as usize,
1154                ),
1155            ))
1156        }
1157    }
1158
1159    /// Send a message consisting of the given disjoint buffers and handles to a channel and block
1160    /// until a reply is received or the timeout is reached. Returns initialized slices of byte
1161    /// message and handles on success. Care should be taken to avoid handle leaks by either
1162    /// transferring the returned handles out to another type or dropping them explicitly.
1163    ///
1164    /// On return, the elements pointed to by `handles_in` will have been zeroed to reflect
1165    /// the fact that the handles have been transferred.
1166    ///
1167    /// The first four bytes of the written and read back messages are treated as a transaction ID
1168    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
1169    /// part of the message as read from userspace. In other words, the first four bytes pointed to
1170    /// by `buffers_in` will be ignored, and the first four bytes of the response will contain a
1171    /// kernel-generated txid.
1172    ///
1173    /// This differs from `callv_uninit`, in that it uses extended handle info.
1174    ///
1175    /// In order to avoid dropping replies, this wrapper requires that the provided out buffers have
1176    /// enough space to handle the largest channel messages possible.
1177    ///
1178    /// Wraps the
1179    /// [zx_channel_call_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call_etc.md)
1180    /// syscall.
1181    ///
1182    /// On failure returns the both the main and read status.
1183    pub fn callv_etc_uninit<'b, 'h>(
1184        &self,
1185        timeout: MonotonicInstant,
1186        buffers_in: &[ChannelIoSlice<'_>],
1187        handles_in: &mut [HandleDisposition<'_>],
1188        bytes_out: &'b mut [MaybeUninit<u8>],
1189        handles_out: &'h mut [MaybeUninit<HandleInfo>],
1190    ) -> Result<(&'b mut [u8], &'h mut [HandleInfo]), Status> {
1191        // SAFETY: in-pointers are both valid to read from for their provided lengths, and
1192        // out-pointers are both valid to write to for their provided lengths.
1193        let (actual_bytes, actual_handles) = unsafe {
1194            self.callv_etc_raw(
1195                timeout,
1196                buffers_in.as_ptr(),
1197                buffers_in.len(),
1198                handles_in.as_mut_ptr(),
1199                handles_in.len(),
1200                bytes_out.as_mut_ptr().cast::<u8>(),
1201                bytes_out.len(),
1202                handles_out.as_mut_ptr().cast::<HandleInfo>(),
1203                handles_out.len(),
1204            )?
1205        };
1206
1207        // SAFETY: the kernel has initialized these slices with valid values.
1208        unsafe {
1209            Ok((
1210                std::slice::from_raw_parts_mut(
1211                    bytes_out.as_mut_ptr().cast::<u8>(),
1212                    actual_bytes as usize,
1213                ),
1214                std::slice::from_raw_parts_mut(
1215                    handles_out.as_mut_ptr().cast::<HandleInfo>(),
1216                    actual_handles as usize,
1217                ),
1218            ))
1219        }
1220    }
1221
1222    /// Send a message consisting of the given bytes and handles to a channel and block until a
1223    /// reply is received or the timeout is reached. On success, returns the number of bytes and
1224    /// handles read from the reply, in that order.
1225    ///
1226    /// The first four bytes of the written and read back messages are treated as a transaction ID
1227    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
1228    /// part of the message as read from userspace. In other words, the first four bytes of
1229    /// `bytes_in` will be ignored, and the first four bytes of the response will contain a
1230    /// kernel-generated txid.
1231    ///
1232    /// This differs from `call_raw`, in that it uses extended handle info.
1233    ///
1234    /// In order to avoid dropping replies, this wrapper requires that the provided out buffers have
1235    /// enough space to handle the largest channel messages possible.
1236    ///
1237    /// On return, the elements pointed to by `handles_in` will have been zeroed to reflect the
1238    /// fact that the handles have been transferred.
1239    ///
1240    /// Wraps the
1241    /// [zx_channel_call_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call_etc.md)
1242    /// syscall.
1243    ///
1244    /// On failure returns the both the main and read status.
1245    ///
1246    /// # Safety
1247    ///
1248    /// `bytes_in` must be valid to read from for `bytes_in_len` bytes.
1249    ///
1250    /// `handles_in` must be valid to read from and write to for `handles_in_len` elements.
1251    ///
1252    /// `bytes_out` must be valid to write to for `bytes_out_len` bytes.
1253    ///
1254    /// `handles_out` must be valid to write to for `handles_out_len` elements.
1255    ///
1256    /// `bytes_in` and `bytes_out` may overlap.
1257    pub unsafe fn call_etc_raw(
1258        &self,
1259        timeout: MonotonicInstant,
1260        bytes_in: *const u8,
1261        bytes_in_len: usize,
1262        handles_in: *mut HandleDisposition<'_>,
1263        handles_in_len: usize,
1264        bytes_out: *mut u8,
1265        bytes_out_len: usize,
1266        handles_out: *mut HandleInfo,
1267        handles_out_len: usize,
1268    ) -> Result<(usize, usize), Status> {
1269        // Don't let replies get silently dropped.
1270        if bytes_out_len < sys::ZX_CHANNEL_MAX_MSG_BYTES as usize
1271            || handles_out_len < sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize
1272        {
1273            return Err(Status::BUFFER_TOO_SMALL);
1274        }
1275
1276        let mut actual_read_bytes: u32 = 0;
1277        let mut actual_read_handles: u32 = 0;
1278
1279        // SAFETY: pointer invariants are upheld by this method's caller, see Safety section in
1280        // docs. HandleDisposition is ABI-compatible with zx_handle_disposition_t and HandleInfo is
1281        // ABI-compatible with zx_handle_info_t, this allows the kernel to safely write the latter
1282        // and and for us to later interpret them as the former.
1283        let res = unsafe {
1284            ok(sys::zx_channel_call_etc(
1285                self.raw_handle(),
1286                0, // options
1287                timeout.into_nanos(),
1288                &mut sys::zx_channel_call_etc_args_t {
1289                    wr_bytes: bytes_in,
1290                    wr_num_bytes: bytes_in_len as u32,
1291                    wr_handles: handles_in.cast::<sys::zx_handle_disposition_t>(),
1292                    wr_num_handles: handles_in_len as u32,
1293                    rd_bytes: bytes_out,
1294                    rd_num_bytes: bytes_out_len as u32,
1295                    rd_handles: handles_out.cast::<sys::zx_handle_info_t>(),
1296                    rd_num_handles: handles_out_len as u32,
1297                },
1298                &mut actual_read_bytes,
1299                &mut actual_read_handles,
1300            ))
1301        };
1302
1303        // Outgoing handles are consumed by zx_channel_call so prevent the destructor from being
1304        // called. Don't overwrite the status field so that callers can inspect it.
1305        // SAFETY: slice invariants must be upheld by this method's caller.
1306        let handles = unsafe { std::slice::from_raw_parts_mut(handles_in, handles_in_len) };
1307        for disposition in handles {
1308            std::mem::forget(disposition.take_op());
1309        }
1310
1311        // Only error-return after zeroing out handles.
1312        res?;
1313
1314        Ok((actual_read_bytes as usize, actual_read_handles as usize))
1315    }
1316
1317    /// Send a message consisting of the given disjoint buffers and handles to a channel and block
1318    /// until a reply is received or the timeout is reached. On success, returns the number of bytes
1319    /// and handles read from the reply, in that order.
1320    ///
1321    /// The first four bytes of the written and read back messages are treated as a transaction ID
1322    /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that
1323    /// part of the message as read from userspace. In other words, the first four bytes pointed to
1324    /// by `buffers_in` will be ignored, and the first four bytes of the response will contain a
1325    /// kernel-generated txid.
1326    ///
1327    /// This differs from `callv_raw`, in that it uses extended handle info.
1328    ///
1329    /// In order to avoid dropping replies, this wrapper requires that the provided out buffers have
1330    /// enough space to handle the largest channel messages possible.
1331    ///
1332    /// On return, the elements pointed to by `handles_in` will have been zeroed to reflect the
1333    /// fact that the handles have been transferred.
1334    ///
1335    /// Wraps the
1336    /// [zx_channel_call_etc](https://fuchsia.dev/fuchsia-src/reference/syscalls/channel_call_etc.md)
1337    /// syscall.
1338    ///
1339    /// On failure returns the both the main and read status.
1340    ///
1341    /// # Safety
1342    ///
1343    /// `buffers_in` must be valid to read from for `buffers_in_len` elements.
1344    ///
1345    /// `handles_in` must be valid to read from and write to for `handles_in_len` elements.
1346    ///
1347    /// `bytes_out` must be valid to write to for `bytes_out_len` bytes.
1348    ///
1349    /// `handles_out` must be valid to write to for `handles_out_len` elements.
1350    ///
1351    /// None of the provided pointers may overlap.
1352    pub unsafe fn callv_etc_raw(
1353        &self,
1354        timeout: MonotonicInstant,
1355        buffers_in: *const ChannelIoSlice<'_>,
1356        buffers_in_len: usize,
1357        handles_in: *mut HandleDisposition<'_>,
1358        handles_in_len: usize,
1359        bytes_out: *mut u8,
1360        bytes_out_len: usize,
1361        handles_out: *mut HandleInfo,
1362        handles_out_len: usize,
1363    ) -> Result<(usize, usize), Status> {
1364        // Don't let replies get silently dropped.
1365        if bytes_out_len < sys::ZX_CHANNEL_MAX_MSG_BYTES as usize
1366            || handles_out_len < sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize
1367        {
1368            return Err(Status::BUFFER_TOO_SMALL);
1369        }
1370
1371        let mut actual_read_bytes: u32 = 0;
1372        let mut actual_read_handles: u32 = 0;
1373
1374        // SAFETY: pointer invariants are upheld by this method's caller, see Safety section in
1375        // docs. HandleDisposition is ABI-compatible with zx_handle_disposition_t and HandleInfo is
1376        // ABI-compatible with zx_handle_info_t, this allows the kernel to safely write the latter
1377        // and and for us to later interpret them as the former.
1378        let res = unsafe {
1379            ok(sys::zx_channel_call_etc(
1380                self.raw_handle(),
1381                sys::ZX_CHANNEL_WRITE_USE_IOVEC,
1382                timeout.into_nanos(),
1383                &mut sys::zx_channel_call_etc_args_t {
1384                    wr_bytes: buffers_in.cast::<u8>(),
1385                    wr_num_bytes: buffers_in_len as u32,
1386                    wr_handles: handles_in.cast::<sys::zx_handle_disposition_t>(),
1387                    wr_num_handles: handles_in_len as u32,
1388                    rd_bytes: bytes_out,
1389                    rd_num_bytes: bytes_out_len as u32,
1390                    rd_handles: handles_out.cast::<sys::zx_handle_info_t>(),
1391                    rd_num_handles: handles_out_len as u32,
1392                },
1393                &mut actual_read_bytes,
1394                &mut actual_read_handles,
1395            ))
1396        };
1397
1398        // Outgoing handles are consumed by zx_channel_call so prevent the destructor from being
1399        // called. Don't overwrite the status field so that callers can inspect it.
1400        // SAFETY: slice invariants must be upheld by this method's caller.
1401        let handles = unsafe { std::slice::from_raw_parts_mut(handles_in, handles_in_len) };
1402        for disposition in handles {
1403            std::mem::forget(disposition.take_op());
1404        }
1405
1406        // Only error-return after zeroing out handles.
1407        res?;
1408
1409        Ok((actual_read_bytes as usize, actual_read_handles as usize))
1410    }
1411}
1412
1413impl AsRef<Channel> for Channel {
1414    fn as_ref(&self) -> &Self {
1415        &self
1416    }
1417}
1418
1419#[derive(Debug, Eq, PartialEq)]
1420pub enum ChannelReadResult<T> {
1421    Ok(T),
1422    BufferTooSmall { bytes_avail: usize, handles_avail: usize },
1423    Err(Status),
1424}
1425
1426impl<T: std::fmt::Debug> ChannelReadResult<T> {
1427    #[track_caller]
1428    pub fn unwrap(self) -> T {
1429        match self {
1430            Self::Ok(t) => t,
1431            other => panic!("unwrap() on {other:?}"),
1432        }
1433    }
1434
1435    #[track_caller]
1436    pub fn expect(self, msg: &str) -> T {
1437        match self {
1438            Self::Ok(t) => t,
1439            other => panic!("expect() on {other:?}: {msg}"),
1440        }
1441    }
1442}
1443
1444#[cfg(test)]
1445mod tests {
1446    use super::*;
1447    use crate::{Duration, HandleOp, ObjectType, Port, Rights, Signals, Vmo};
1448    use std::thread;
1449
1450    #[test]
1451    fn channel_basic() {
1452        let (p1, p2) = Channel::create();
1453
1454        let mut empty = vec![];
1455        assert!(p1.write(b"hello", &mut empty).is_ok());
1456
1457        let mut buf = MessageBuf::new();
1458        assert!(p2.read(&mut buf).is_ok());
1459        assert_eq!(buf.bytes(), b"hello");
1460    }
1461
1462    #[test]
1463    fn channel_basic_vectored() {
1464        let (p1, p2) = Channel::create();
1465
1466        let mut empty = vec![];
1467        assert!(
1468            p1.writev(&[ChannelIoSlice::new(b"hel"), ChannelIoSlice::new(b"lo")], &mut empty)
1469                .is_ok()
1470        );
1471
1472        let mut buf = MessageBuf::new();
1473        assert!(p2.read(&mut buf).is_ok());
1474        assert_eq!(buf.bytes(), b"hello");
1475    }
1476
1477    #[test]
1478    fn channel_basic_etc() {
1479        let (p1, p2) = Channel::create();
1480
1481        let mut empty = vec![];
1482        assert!(p1.write_etc(b"hello", &mut empty).is_ok());
1483
1484        let mut buf = MessageBufEtc::new();
1485        assert!(p2.read_etc(&mut buf).is_ok());
1486        assert_eq!(buf.bytes(), b"hello");
1487    }
1488
1489    #[test]
1490    fn channel_basic_etc_vectored() {
1491        let (p1, p2) = Channel::create();
1492
1493        let mut empty = vec![];
1494        assert!(
1495            p1.writev_etc(&[ChannelIoSlice::new(b"he"), ChannelIoSlice::new(b"llo")], &mut empty)
1496                .is_ok()
1497        );
1498
1499        let mut buf = MessageBufEtc::new();
1500        assert!(p2.read_etc(&mut buf).is_ok());
1501        assert_eq!(buf.bytes(), b"hello");
1502    }
1503
1504    #[test]
1505    fn channel_basic_etc_with_handle_move() {
1506        let (p1, p2) = Channel::create();
1507
1508        let mut handles = vec![HandleDisposition::new(
1509            HandleOp::Move(Port::create().into()),
1510            ObjectType::PORT,
1511            Rights::TRANSFER,
1512            Status::OK,
1513        )];
1514        match p1.write_etc(b"", &mut handles) {
1515            Err(err) => {
1516                panic!("error: {}", err);
1517            }
1518            _ => {}
1519        }
1520
1521        let mut buf = MessageBufEtc::new();
1522        assert!(p2.read_etc(&mut buf).is_ok());
1523        assert_eq!(buf.bytes(), b"");
1524        assert_eq!(buf.n_handle_infos(), 1);
1525        let out_handles = buf.handle_infos;
1526        assert_eq!(out_handles.len(), 1);
1527        assert_ne!(out_handles[0].handle, NullableHandle::invalid());
1528        assert_eq!(out_handles[0].rights, Rights::TRANSFER);
1529        assert_eq!(out_handles[0].object_type, ObjectType::PORT);
1530    }
1531
1532    #[test]
1533    fn channel_basic_etc_vectored_with_handle_move() {
1534        let (p1, p2) = Channel::create();
1535
1536        let mut handles = vec![HandleDisposition::new(
1537            HandleOp::Move(Port::create().into()),
1538            ObjectType::PORT,
1539            Rights::TRANSFER,
1540            Status::OK,
1541        )];
1542        match p1.writev_etc(&[], &mut handles) {
1543            Err(err) => {
1544                panic!("error: {}", err);
1545            }
1546            _ => {}
1547        }
1548
1549        let mut buf = MessageBufEtc::new();
1550        assert!(p2.read_etc(&mut buf).is_ok());
1551        assert_eq!(buf.bytes(), b"");
1552        assert_eq!(buf.n_handle_infos(), 1);
1553        let out_handles = buf.handle_infos;
1554        assert_eq!(out_handles.len(), 1);
1555        assert_ne!(out_handles[0].handle, NullableHandle::invalid());
1556        assert_eq!(out_handles[0].rights, Rights::TRANSFER);
1557        assert_eq!(out_handles[0].object_type, ObjectType::PORT);
1558    }
1559
1560    #[test]
1561    fn channel_basic_etc_with_handle_duplicate() {
1562        let (p1, p2) = Channel::create();
1563
1564        let port = Port::create();
1565        let mut handles = vec![HandleDisposition::new(
1566            HandleOp::Duplicate(port.as_handle_ref()),
1567            ObjectType::NONE,
1568            Rights::SAME_RIGHTS,
1569            Status::OK,
1570        )];
1571        p1.write_etc(b"", &mut handles).unwrap();
1572
1573        let orig_port_info = port.basic_info().unwrap();
1574        let mut buf = MessageBufEtc::new();
1575        assert!(p2.read_etc(&mut buf).is_ok());
1576        assert_eq!(buf.bytes(), b"");
1577        assert_eq!(buf.n_handle_infos(), 1);
1578        let out_handles = buf.handle_infos;
1579        assert_eq!(out_handles.len(), 1);
1580        assert_ne!(out_handles[0].handle.raw_handle(), 0);
1581        assert_ne!(out_handles[0].handle.raw_handle(), port.raw_handle());
1582        assert_eq!(out_handles[0].rights, orig_port_info.rights);
1583        assert_eq!(out_handles[0].object_type, ObjectType::PORT);
1584    }
1585
1586    #[test]
1587    fn channel_basic_etc_vectored_with_handle_duplicate() {
1588        let (p1, p2) = Channel::create();
1589
1590        let port = Port::create();
1591        let mut handles = vec![HandleDisposition::new(
1592            HandleOp::Duplicate(port.as_handle_ref()),
1593            ObjectType::NONE,
1594            Rights::SAME_RIGHTS,
1595            Status::OK,
1596        )];
1597        p1.writev_etc(&[], &mut handles).unwrap();
1598
1599        let orig_port_info = port.basic_info().unwrap();
1600        let mut buf = MessageBufEtc::new();
1601        assert!(p2.read_etc(&mut buf).is_ok());
1602        assert_eq!(buf.bytes(), b"");
1603        assert_eq!(buf.n_handle_infos(), 1);
1604        let out_handles = buf.handle_infos;
1605        assert_eq!(out_handles.len(), 1);
1606        assert_ne!(out_handles[0].handle.raw_handle(), 0);
1607        assert_ne!(out_handles[0].handle.raw_handle(), port.raw_handle());
1608        assert_eq!(out_handles[0].rights, orig_port_info.rights);
1609        assert_eq!(out_handles[0].object_type, ObjectType::PORT);
1610    }
1611
1612    #[test]
1613    fn channel_read_uninit_too_small() {
1614        let (p1, p2) = Channel::create();
1615
1616        let mut empty = vec![];
1617        assert!(p1.write(b"hello", &mut empty).is_ok());
1618
1619        let mut bytes = vec![];
1620        let mut handles = vec![];
1621        let result = p2.read_uninit(&mut bytes, &mut handles);
1622        assert_eq!(result, ChannelReadResult::BufferTooSmall { bytes_avail: 5, handles_avail: 0 });
1623    }
1624
1625    #[test]
1626    fn channel_read_etc_uninit_too_small() {
1627        let (p1, p2) = Channel::create();
1628
1629        let mut empty = vec![];
1630        assert!(p1.write_etc(b"hello", &mut empty).is_ok());
1631
1632        let mut bytes = vec![];
1633        let mut handles = vec![];
1634        let result = p2.read_etc_uninit(&mut bytes, &mut handles);
1635        assert_eq!(result, ChannelReadResult::BufferTooSmall { bytes_avail: 5, handles_avail: 0 });
1636    }
1637
1638    fn too_many_bytes() -> Vec<u8> {
1639        vec![b'A'; (sys::ZX_CHANNEL_MAX_MSG_BYTES + 1) as usize]
1640    }
1641
1642    fn too_many_slices() -> Vec<ChannelIoSlice<'static>> {
1643        vec![ChannelIoSlice::new(b"123"); sys::ZX_CHANNEL_MAX_MSG_IOVEC as usize + 1]
1644    }
1645
1646    fn too_many_bytes_vectored() -> Vec<ChannelIoSlice<'static>> {
1647        static BACKING_BYTES: std::sync::LazyLock<Vec<Vec<u8>>> = std::sync::LazyLock::new(|| {
1648            let mut backing = vec![];
1649            while backing.len() <= sys::ZX_CHANNEL_MAX_MSG_BYTES as usize {
1650                backing.push(vec![b'l'; 8192]);
1651            }
1652            backing
1653        });
1654        BACKING_BYTES.iter().map(|v| ChannelIoSlice::new(&*v)).collect()
1655    }
1656
1657    fn too_many_handles() -> Vec<NullableHandle> {
1658        let mut handles = vec![];
1659        for _ in 0..sys::ZX_CHANNEL_MAX_MSG_HANDLES + 1 {
1660            handles.push(crate::Event::create().into());
1661        }
1662        handles
1663    }
1664
1665    fn too_many_dispositions() -> Vec<HandleDisposition<'static>> {
1666        let mut handles = vec![];
1667        for _ in 0..sys::ZX_CHANNEL_MAX_MSG_HANDLES + 1 {
1668            handles.push(HandleDisposition::new(
1669                HandleOp::Move(crate::Event::create().into()),
1670                ObjectType::EVENT,
1671                Rights::TRANSFER,
1672                Status::OK,
1673            ));
1674        }
1675        handles
1676    }
1677
1678    #[test]
1679    fn channel_write_too_many_bytes() {
1680        Channel::create().0.write(&too_many_bytes(), &mut vec![]).unwrap_err();
1681    }
1682
1683    #[test]
1684    fn channel_write_vectored_too_many_bytes() {
1685        Channel::create().0.writev(&too_many_bytes_vectored(), &mut vec![]).unwrap_err();
1686    }
1687
1688    #[test]
1689    fn channel_write_vectored_too_many_slices() {
1690        Channel::create().0.writev(&too_many_slices(), &mut vec![]).unwrap_err();
1691    }
1692
1693    #[test]
1694    fn channel_write_too_many_handles() {
1695        Channel::create().0.write(&vec![], &mut too_many_handles()[..]).unwrap_err();
1696    }
1697
1698    #[test]
1699    fn channel_write_vectored_too_many_handles() {
1700        Channel::create().0.writev(&[], &mut too_many_handles()[..]).unwrap_err();
1701    }
1702
1703    #[test]
1704    fn channel_write_consumes_handles_on_failure() {
1705        let (send, recv) = Channel::create();
1706        drop(recv);
1707        let mut handles = vec![crate::Event::create().into()];
1708        send.write(&[], &mut handles).unwrap_err();
1709        assert!(handles[0].is_invalid());
1710    }
1711
1712    #[test]
1713    fn channel_write_consumes_multiple_handles_on_failure() {
1714        let (send, _recv) = Channel::create();
1715        let event = crate::Event::create();
1716        let event_dup_no_transfer =
1717            event.duplicate_handle(crate::Rights::BASIC & !crate::Rights::TRANSFER).unwrap();
1718        let mut handles = vec![event.into(), event_dup_no_transfer.into()];
1719        let send_result = send.write(&[], &mut handles);
1720        assert!(send_result.is_err());
1721    }
1722    #[test]
1723    fn channel_write_vectored_consumes_handles_on_failure() {
1724        let (send, recv) = Channel::create();
1725        drop(recv);
1726        let mut handles = vec![crate::Event::create().into()];
1727        send.writev(&[], &mut handles).unwrap_err();
1728        assert!(handles[0].is_invalid());
1729    }
1730
1731    #[test]
1732    fn channel_write_etc_too_many_bytes() {
1733        Channel::create().0.write_etc(&too_many_bytes(), &mut []).unwrap_err();
1734    }
1735
1736    #[test]
1737    fn channel_write_etc_vectored_too_many_bytes() {
1738        Channel::create().0.writev_etc(&too_many_bytes_vectored(), &mut []).unwrap_err();
1739    }
1740
1741    #[test]
1742    fn channel_write_etc_vectored_too_many_slices() {
1743        Channel::create().0.writev_etc(&too_many_slices(), &mut []).unwrap_err();
1744    }
1745
1746    #[test]
1747    fn channel_write_etc_too_many_handles() {
1748        Channel::create().0.write_etc(&vec![], &mut too_many_dispositions()[..]).unwrap_err();
1749    }
1750
1751    #[test]
1752    fn channel_write_etc_vectored_too_many_handles() {
1753        Channel::create().0.writev_etc(&vec![], &mut too_many_dispositions()[..]).unwrap_err();
1754    }
1755
1756    #[test]
1757    fn channel_write_etc_consumes_moved_handles_on_failure() {
1758        let (send, recv) = Channel::create();
1759        drop(recv);
1760        let mut handles = vec![HandleDisposition::new(
1761            HandleOp::Move(crate::Event::create().into()),
1762            ObjectType::EVENT,
1763            Rights::NONE,
1764            Status::OK,
1765        )];
1766        send.write_etc(&[], &mut handles).unwrap_err();
1767        assert_eq!(handles[0].raw_handle(), sys::ZX_HANDLE_INVALID);
1768        assert_eq!(handles[0].result, Status::OK);
1769    }
1770
1771    #[test]
1772    fn channel_write_etc_vectored_consumes_moved_handles_on_failure() {
1773        let (send, recv) = Channel::create();
1774        drop(recv);
1775        let mut handles = vec![HandleDisposition::new(
1776            HandleOp::Move(crate::Event::create().into()),
1777            ObjectType::EVENT,
1778            Rights::NONE,
1779            Status::OK,
1780        )];
1781        send.writev_etc(&[], &mut handles).unwrap_err();
1782        assert_eq!(handles[0].raw_handle(), sys::ZX_HANDLE_INVALID);
1783        assert_eq!(handles[0].result, Status::OK);
1784    }
1785
1786    #[test]
1787    fn channel_write_etc_preserves_per_disposition_failures() {
1788        let (send, _recv) = Channel::create();
1789
1790        let event = crate::Event::create();
1791        let event_no_rights = event.duplicate_handle(Rights::NONE).unwrap();
1792
1793        let mut handles = vec![
1794            HandleDisposition::new(
1795                HandleOp::Move(event.into()),
1796                ObjectType::EVENT,
1797                Rights::SAME_RIGHTS,
1798                Status::OK,
1799            ),
1800            HandleDisposition::new(
1801                HandleOp::Move(event_no_rights.into()),
1802                ObjectType::EVENT,
1803                Rights::SAME_RIGHTS,
1804                Status::OK,
1805            ),
1806        ];
1807
1808        send.write_etc(&[], &mut handles).unwrap_err();
1809
1810        // Both handles should be moved.
1811        assert_eq!(handles[0].raw_handle(), sys::ZX_HANDLE_INVALID);
1812        assert_eq!(handles[1].raw_handle(), sys::ZX_HANDLE_INVALID);
1813
1814        // Each handle should separately report the status of transferring/duplicating that handle.
1815        assert_eq!(handles[0].result, Status::OK);
1816        assert_ne!(handles[1].result, Status::OK, "must have transfer rights to succeed");
1817    }
1818
1819    #[test]
1820    fn channel_write_etc_vectored_preserves_per_disposition_failures() {
1821        let (send, _recv) = Channel::create();
1822
1823        let event = crate::Event::create();
1824        let event_no_rights = event.duplicate_handle(Rights::NONE).unwrap();
1825
1826        let mut handles = vec![
1827            HandleDisposition::new(
1828                HandleOp::Move(event.into()),
1829                ObjectType::EVENT,
1830                Rights::SAME_RIGHTS,
1831                Status::OK,
1832            ),
1833            HandleDisposition::new(
1834                HandleOp::Move(event_no_rights.into()),
1835                ObjectType::EVENT,
1836                Rights::SAME_RIGHTS,
1837                Status::OK,
1838            ),
1839        ];
1840
1841        send.writev_etc(&[], &mut handles).unwrap_err();
1842
1843        // Both handles should be moved.
1844        assert_eq!(handles[0].raw_handle(), sys::ZX_HANDLE_INVALID);
1845        assert_eq!(handles[1].raw_handle(), sys::ZX_HANDLE_INVALID);
1846
1847        // Each handle should separately report the status of transferring/duplicating that handle.
1848        assert_eq!(handles[0].result, Status::OK);
1849        assert_ne!(handles[1].result, Status::OK, "must have transfer rights to succeed");
1850    }
1851
1852    #[test]
1853    fn channel_call_too_many_bytes() {
1854        Channel::create()
1855            .0
1856            .call(
1857                MonotonicInstant::INFINITE,
1858                &too_many_bytes(),
1859                &mut vec![],
1860                &mut MessageBuf::new(),
1861            )
1862            .unwrap_err();
1863    }
1864
1865    #[test]
1866    fn channel_call_vectored_too_many_bytes() {
1867        Channel::create()
1868            .0
1869            .callv(
1870                MonotonicInstant::INFINITE,
1871                &too_many_bytes_vectored(),
1872                &mut vec![],
1873                &mut MessageBuf::new(),
1874            )
1875            .unwrap_err();
1876    }
1877
1878    #[test]
1879    fn channel_call_vectored_too_many_slices() {
1880        Channel::create()
1881            .0
1882            .callv(
1883                MonotonicInstant::INFINITE,
1884                &too_many_slices(),
1885                &mut vec![],
1886                &mut MessageBuf::new(),
1887            )
1888            .unwrap_err();
1889    }
1890
1891    #[test]
1892    fn channel_call_too_many_handles() {
1893        Channel::create()
1894            .0
1895            .call(
1896                MonotonicInstant::INFINITE,
1897                &vec![],
1898                &mut too_many_handles()[..],
1899                &mut MessageBuf::new(),
1900            )
1901            .unwrap_err();
1902    }
1903
1904    #[test]
1905    fn channel_callv_too_many_handles() {
1906        Channel::create()
1907            .0
1908            .callv(
1909                MonotonicInstant::INFINITE,
1910                &[],
1911                &mut too_many_handles()[..],
1912                &mut MessageBuf::new(),
1913            )
1914            .unwrap_err();
1915    }
1916
1917    #[test]
1918    fn channel_call_etc_too_many_bytes() {
1919        Channel::create()
1920            .0
1921            .call_etc(
1922                MonotonicInstant::INFINITE,
1923                &too_many_bytes(),
1924                &mut vec![],
1925                &mut MessageBufEtc::new(),
1926            )
1927            .unwrap_err();
1928    }
1929
1930    #[test]
1931    fn channel_call_etc_vectored_too_many_bytes() {
1932        Channel::create()
1933            .0
1934            .callv_etc(
1935                MonotonicInstant::INFINITE,
1936                &too_many_bytes_vectored(),
1937                &mut vec![],
1938                &mut MessageBufEtc::new(),
1939            )
1940            .unwrap_err();
1941    }
1942
1943    #[test]
1944    fn channel_call_etc_too_many_handles() {
1945        Channel::create()
1946            .0
1947            .call_etc(
1948                MonotonicInstant::INFINITE,
1949                &vec![],
1950                &mut too_many_dispositions()[..],
1951                &mut MessageBufEtc::new(),
1952            )
1953            .unwrap_err();
1954    }
1955
1956    #[test]
1957    fn channel_call_etc_vectored_too_many_handles() {
1958        Channel::create()
1959            .0
1960            .callv_etc(
1961                MonotonicInstant::INFINITE,
1962                &vec![],
1963                &mut too_many_dispositions()[..],
1964                &mut MessageBufEtc::new(),
1965            )
1966            .unwrap_err();
1967    }
1968
1969    #[test]
1970    fn channel_send_handle() {
1971        let hello_length: usize = 5;
1972
1973        // Create a pair of channels and a virtual memory object.
1974        let (p1, p2) = Channel::create();
1975        let vmo = Vmo::create(hello_length as u64).unwrap();
1976
1977        // Duplicate VMO handle and send it down the channel.
1978        let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into();
1979        let mut handles_to_send: Vec<NullableHandle> = vec![duplicate_vmo_handle];
1980        assert!(p1.write(b"", &mut handles_to_send).is_ok());
1981        // The handle vector should only contain invalid handles.
1982        for handle in handles_to_send {
1983            assert!(handle.is_invalid());
1984        }
1985
1986        // Read the handle from the receiving channel.
1987        let mut buf = MessageBuf::new();
1988        assert!(p2.read(&mut buf).is_ok());
1989        assert_eq!(buf.n_handles(), 1);
1990        // Take the handle from the buffer.
1991        let received_handle = buf.take_handle(0).unwrap();
1992        // Should not affect number of handles.
1993        assert_eq!(buf.n_handles(), 1);
1994        // Trying to take it again should fail.
1995        assert!(buf.take_handle(0).is_none());
1996
1997        // Now to test that we got the right handle, try writing something to it...
1998        let received_vmo = Vmo::from(received_handle);
1999        assert!(received_vmo.write(b"hello", 0).is_ok());
2000
2001        // ... and reading it back from the original VMO.
2002        let mut read_vec = vec![0; hello_length];
2003        assert!(vmo.read(&mut read_vec, 0).is_ok());
2004        assert_eq!(read_vec, b"hello");
2005    }
2006
2007    #[test]
2008    fn channel_send_handle_vectored() {
2009        let hello_length: usize = 5;
2010
2011        // Create a pair of channels and a virtual memory object.
2012        let (p1, p2) = Channel::create();
2013        let vmo = Vmo::create(hello_length as u64).unwrap();
2014
2015        // Duplicate VMO handle and send it down the channel.
2016        let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into();
2017        let mut handles_to_send: Vec<NullableHandle> = vec![duplicate_vmo_handle];
2018        assert!(p1.writev(&[], &mut handles_to_send).is_ok());
2019        // The handle vector should only contain invalid handles.
2020        for handle in handles_to_send {
2021            assert!(handle.is_invalid());
2022        }
2023
2024        // Read the handle from the receiving channel.
2025        let mut buf = MessageBuf::new();
2026        assert!(p2.read(&mut buf).is_ok());
2027        assert_eq!(buf.n_handles(), 1);
2028        // Take the handle from the buffer.
2029        let received_handle = buf.take_handle(0).unwrap();
2030        // Should not affect number of handles.
2031        assert_eq!(buf.n_handles(), 1);
2032        // Trying to take it again should fail.
2033        assert!(buf.take_handle(0).is_none());
2034
2035        // Now to test that we got the right handle, try writing something to it...
2036        let received_vmo = Vmo::from(received_handle);
2037        assert!(received_vmo.write(b"hello", 0).is_ok());
2038
2039        // ... and reading it back from the original VMO.
2040        let mut read_vec = vec![0; hello_length];
2041        assert!(vmo.read(&mut read_vec, 0).is_ok());
2042        assert_eq!(read_vec, b"hello");
2043    }
2044
2045    #[test]
2046    fn channel_call_timeout() {
2047        let ten_ms = Duration::from_millis(10);
2048
2049        // Create a pair of channels and a virtual memory object.
2050        let (p1, p2) = Channel::create();
2051        let vmo = Vmo::create(0 as u64).unwrap();
2052
2053        // Duplicate VMO handle and send it along with the call.
2054        let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into();
2055        let mut handles_to_send: Vec<NullableHandle> = vec![duplicate_vmo_handle];
2056        let mut buf = MessageBuf::new();
2057        assert_eq!(
2058            p1.call(MonotonicInstant::after(ten_ms), b"0000call", &mut handles_to_send, &mut buf),
2059            Err(Status::TIMED_OUT)
2060        );
2061        // Despite not getting a response, the handles were sent so the handle slice
2062        // should only contain invalid handles.
2063        for handle in handles_to_send {
2064            assert!(handle.is_invalid());
2065        }
2066
2067        // Should be able to read call even though it timed out waiting for a response.
2068        let mut buf = MessageBuf::new();
2069        assert!(p2.read(&mut buf).is_ok());
2070        assert_eq!(&buf.bytes()[4..], b"call");
2071        assert_eq!(buf.n_handles(), 1);
2072    }
2073
2074    #[test]
2075    fn channel_call_vectored_timeout() {
2076        let ten_ms = Duration::from_millis(10);
2077
2078        // Create a pair of channels and a virtual memory object.
2079        let (p1, p2) = Channel::create();
2080        let vmo = Vmo::create(0 as u64).unwrap();
2081
2082        // Duplicate VMO handle and send it along with the call.
2083        let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into();
2084        let mut handles_to_send: Vec<NullableHandle> = vec![duplicate_vmo_handle];
2085        let mut buf = MessageBuf::new();
2086        assert_eq!(
2087            p1.callv(
2088                MonotonicInstant::after(ten_ms),
2089                &[ChannelIoSlice::new(b"00"), ChannelIoSlice::new(b"00call")],
2090                &mut handles_to_send,
2091                &mut buf
2092            ),
2093            Err(Status::TIMED_OUT)
2094        );
2095        // Despite not getting a response, the handles were sent so the handle slice
2096        // should only contain invalid handles.
2097        for handle in handles_to_send {
2098            assert!(handle.is_invalid());
2099        }
2100
2101        // Should be able to read call even though it timed out waiting for a response.
2102        let mut buf = MessageBuf::new();
2103        assert!(p2.read(&mut buf).is_ok());
2104        assert_eq!(&buf.bytes()[4..], b"call");
2105        assert_eq!(buf.n_handles(), 1);
2106    }
2107
2108    #[test]
2109    fn channel_call_etc_timeout() {
2110        let ten_ms = Duration::from_millis(10);
2111
2112        // Create a pair of channels and a virtual memory object.
2113        let (p1, p2) = Channel::create();
2114
2115        // Duplicate VMO handle and send it along with the call.
2116        let mut empty: Vec<HandleDisposition<'_>> = vec![];
2117        let mut buf = MessageBufEtc::new();
2118        assert_eq!(
2119            p1.call_etc(MonotonicInstant::after(ten_ms), b"0000call", &mut empty, &mut buf),
2120            Err(Status::TIMED_OUT)
2121        );
2122
2123        // Should be able to read call even though it timed out waiting for a response.
2124        let mut buf = MessageBuf::new();
2125        assert!(p2.read(&mut buf).is_ok());
2126        assert_eq!(&buf.bytes()[4..], b"call");
2127        assert_eq!(buf.n_handles(), 0);
2128    }
2129
2130    #[test]
2131    fn channel_call_etc_vectored_timeout() {
2132        let ten_ms = Duration::from_millis(10);
2133
2134        // Create a pair of channels and a virtual memory object.
2135        let (p1, p2) = Channel::create();
2136
2137        // Duplicate VMO handle and send it along with the call.
2138        let mut empty: Vec<HandleDisposition<'_>> = vec![];
2139        let mut buf = MessageBufEtc::new();
2140        assert_eq!(
2141            p1.callv_etc(
2142                MonotonicInstant::after(ten_ms),
2143                &[ChannelIoSlice::new(b"0"), ChannelIoSlice::new(b"000call")],
2144                &mut empty,
2145                &mut buf
2146            ),
2147            Err(Status::TIMED_OUT)
2148        );
2149
2150        // Should be able to read call even though it timed out waiting for a response.
2151        let mut buf = MessageBuf::new();
2152        assert!(p2.read(&mut buf).is_ok());
2153        assert_eq!(&buf.bytes()[4..], b"call");
2154        assert_eq!(buf.n_handles(), 0);
2155    }
2156
2157    #[test]
2158    fn channel_call() {
2159        // Create a pair of channels
2160        let (p1, p2) = Channel::create();
2161
2162        // create an mpsc channel for communicating the call data for later assertion
2163        let (tx, rx) = ::std::sync::mpsc::channel();
2164
2165        // Start a new thread to respond to the call.
2166        thread::spawn(move || {
2167            let mut buf = MessageBuf::new();
2168            // if either the read or the write fail, this thread will panic,
2169            // resulting in tx being dropped, which will be noticed by the rx.
2170            p2.wait_one(
2171                Signals::CHANNEL_READABLE,
2172                MonotonicInstant::after(Duration::from_seconds(1)),
2173            )
2174            .expect("callee wait error");
2175            p2.read(&mut buf).expect("callee read error");
2176
2177            let (bytes, handles) = buf.split_mut();
2178            tx.send(bytes.clone()).expect("callee mpsc send error");
2179            assert_eq!(handles.len(), 0);
2180
2181            bytes.truncate(4); // Drop the received message, leaving only the txid
2182            bytes.extend_from_slice(b"response");
2183
2184            p2.write(bytes, handles).expect("callee write error");
2185        });
2186
2187        // Make the call.
2188        let mut buf = MessageBuf::new();
2189        buf.ensure_capacity_bytes(12);
2190        // NOTE(raggi): CQ has been seeing some long stalls from channel call,
2191        // and it's as yet unclear why. The timeout here has been made much
2192        // larger in order to avoid that, as the issues are not issues with this
2193        // crate's concerns. The timeout is here just to prevent the tests from
2194        // stalling forever if a developer makes a mistake locally in this
2195        // crate. Tests of Zircon behavior or virtualization behavior should be
2196        // covered elsewhere. See https://fxbug.dev/42106187.
2197        p1.call(
2198            MonotonicInstant::after(Duration::from_seconds(30)),
2199            b"txidcall",
2200            &mut vec![],
2201            &mut buf,
2202        )
2203        .expect("channel call error");
2204        assert_eq!(&buf.bytes()[4..], b"response");
2205        assert_eq!(buf.n_handles(), 0);
2206
2207        let sbuf = rx.recv().expect("mpsc channel recv error");
2208        assert_eq!(&sbuf[4..], b"call");
2209    }
2210
2211    #[test]
2212    fn channel_call_vectored() {
2213        // Create a pair of channels
2214        let (p1, p2) = Channel::create();
2215
2216        // create an mpsc channel for communicating the call data for later assertion
2217        let (tx, rx) = ::std::sync::mpsc::channel();
2218
2219        // Start a new thread to respond to the call.
2220        thread::spawn(move || {
2221            let mut buf = MessageBuf::new();
2222            // if either the read or the write fail, this thread will panic,
2223            // resulting in tx being dropped, which will be noticed by the rx.
2224            p2.wait_one(
2225                Signals::CHANNEL_READABLE,
2226                MonotonicInstant::after(Duration::from_seconds(1)),
2227            )
2228            .expect("callee wait error");
2229            p2.read(&mut buf).expect("callee read error");
2230
2231            let (bytes, handles) = buf.split_mut();
2232            tx.send(bytes.clone()).expect("callee mpsc send error");
2233            assert_eq!(handles.len(), 0);
2234
2235            bytes.truncate(4); // Drop the received message, leaving only the txid
2236            bytes.extend_from_slice(b"response");
2237
2238            p2.write(bytes, handles).expect("callee write error");
2239        });
2240
2241        // Make the call.
2242        let mut buf = MessageBuf::new();
2243        buf.ensure_capacity_bytes(12);
2244        // NOTE(raggi): CQ has been seeing some long stalls from channel call,
2245        // and it's as yet unclear why. The timeout here has been made much
2246        // larger in order to avoid that, as the issues are not issues with this
2247        // crate's concerns. The timeout is here just to prevent the tests from
2248        // stalling forever if a developer makes a mistake locally in this
2249        // crate. Tests of Zircon behavior or virtualization behavior should be
2250        // covered elsewhere. See https://fxbug.dev/42106187.
2251        p1.callv(
2252            MonotonicInstant::after(Duration::from_seconds(30)),
2253            &[ChannelIoSlice::new(b"txid"), ChannelIoSlice::new(b"call")],
2254            &mut vec![],
2255            &mut buf,
2256        )
2257        .expect("channel call error");
2258        assert_eq!(&buf.bytes()[4..], b"response");
2259        assert_eq!(buf.n_handles(), 0);
2260
2261        let sbuf = rx.recv().expect("mpsc channel recv error");
2262        assert_eq!(&sbuf[4..], b"call");
2263    }
2264
2265    #[test]
2266    fn channel_call_etc() {
2267        // Create a pair of channels
2268        let (p1, p2) = Channel::create();
2269
2270        // create an mpsc channel for communicating the call data for later assertion
2271        let (tx, rx) = ::std::sync::mpsc::channel();
2272
2273        // Start a new thread to respond to the call.
2274        thread::spawn(move || {
2275            let mut buf = MessageBuf::new();
2276            // if either the read or the write fail, this thread will panic,
2277            // resulting in tx being dropped, which will be noticed by the rx.
2278            p2.wait_one(
2279                Signals::CHANNEL_READABLE,
2280                MonotonicInstant::after(Duration::from_seconds(1)),
2281            )
2282            .expect("callee wait error");
2283            p2.read(&mut buf).expect("callee read error");
2284
2285            let (bytes, handles) = buf.split_mut();
2286            tx.send(bytes.clone()).expect("callee mpsc send error");
2287            assert_eq!(handles.len(), 1);
2288
2289            bytes.truncate(4); // Drop the received message, leaving only the txid
2290            bytes.extend_from_slice(b"response");
2291
2292            p2.write(bytes, handles).expect("callee write error");
2293        });
2294
2295        // Make the call.
2296        let mut buf = MessageBufEtc::new();
2297        buf.ensure_capacity_bytes(12);
2298        buf.ensure_capacity_handle_infos(1);
2299        let mut handle_dispositions = [HandleDisposition::new(
2300            HandleOp::Move(Port::create().into()),
2301            ObjectType::PORT,
2302            Rights::TRANSFER,
2303            Status::OK,
2304        )];
2305        // NOTE(raggi): CQ has been seeing some long stalls from channel call,
2306        // and it's as yet unclear why. The timeout here has been made much
2307        // larger in order to avoid that, as the issues are not issues with this
2308        // crate's concerns. The timeout is here just to prevent the tests from
2309        // stalling forever if a developer makes a mistake locally in this
2310        // crate. Tests of Zircon behavior or virtualization behavior should be
2311        // covered elsewhere. See https://fxbug.dev/42106187.
2312        p1.call_etc(
2313            MonotonicInstant::after(Duration::from_seconds(30)),
2314            b"txidcall",
2315            &mut handle_dispositions,
2316            &mut buf,
2317        )
2318        .expect("channel call error");
2319        assert_eq!(&buf.bytes()[4..], b"response");
2320        assert_eq!(buf.n_handle_infos(), 1);
2321        assert_ne!(buf.handle_infos[0].handle.raw_handle(), 0);
2322        assert_eq!(buf.handle_infos[0].object_type, ObjectType::PORT);
2323        assert_eq!(buf.handle_infos[0].rights, Rights::TRANSFER);
2324
2325        let sbuf = rx.recv().expect("mpsc channel recv error");
2326        assert_eq!(&sbuf[4..], b"call");
2327    }
2328
2329    #[test]
2330    fn channel_call_etc_vectored() {
2331        // Create a pair of channels
2332        let (p1, p2) = Channel::create();
2333
2334        // create an mpsc channel for communicating the call data for later assertion
2335        let (tx, rx) = ::std::sync::mpsc::channel();
2336
2337        // Start a new thread to respond to the call.
2338        thread::spawn(move || {
2339            let mut buf = MessageBuf::new();
2340            // if either the read or the write fail, this thread will panic,
2341            // resulting in tx being dropped, which will be noticed by the rx.
2342            p2.wait_one(
2343                Signals::CHANNEL_READABLE,
2344                MonotonicInstant::after(Duration::from_seconds(1)),
2345            )
2346            .expect("callee wait error");
2347            p2.read(&mut buf).expect("callee read error");
2348
2349            let (bytes, handles) = buf.split_mut();
2350            tx.send(bytes.clone()).expect("callee mpsc send error");
2351            assert_eq!(handles.len(), 1);
2352
2353            bytes.truncate(4); // Drop the received message, leaving only the txid
2354            bytes.extend_from_slice(b"response");
2355
2356            p2.write(bytes, handles).expect("callee write error");
2357        });
2358
2359        // Make the call.
2360        let mut buf = MessageBufEtc::new();
2361        buf.ensure_capacity_bytes(12);
2362        buf.ensure_capacity_handle_infos(1);
2363        let mut handle_dispositions = [HandleDisposition::new(
2364            HandleOp::Move(Port::create().into()),
2365            ObjectType::PORT,
2366            Rights::TRANSFER,
2367            Status::OK,
2368        )];
2369        // NOTE(raggi): CQ has been seeing some long stalls from channel call,
2370        // and it's as yet unclear why. The timeout here has been made much
2371        // larger in order to avoid that, as the issues are not issues with this
2372        // crate's concerns. The timeout is here just to prevent the tests from
2373        // stalling forever if a developer makes a mistake locally in this
2374        // crate. Tests of Zircon behavior or virtualization behavior should be
2375        // covered elsewhere. See https://fxbug.dev/42106187.
2376        p1.callv_etc(
2377            MonotonicInstant::after(Duration::from_seconds(30)),
2378            &[ChannelIoSlice::new(b"txi"), ChannelIoSlice::new(b"dcall")],
2379            &mut handle_dispositions,
2380            &mut buf,
2381        )
2382        .expect("channel call error");
2383        assert_eq!(&buf.bytes()[4..], b"response");
2384        assert_eq!(buf.n_handle_infos(), 1);
2385        assert_ne!(buf.handle_infos[0].handle.raw_handle(), 0);
2386        assert_eq!(buf.handle_infos[0].object_type, ObjectType::PORT);
2387        assert_eq!(buf.handle_infos[0].rights, Rights::TRANSFER);
2388
2389        let sbuf = rx.recv().expect("mpsc channel recv error");
2390        assert_eq!(&sbuf[4..], b"call");
2391    }
2392
2393    #[test]
2394    fn channel_call_etc_preserves_per_disposition_failures() {
2395        let (send, _recv) = Channel::create();
2396
2397        let event = crate::Event::create();
2398        let event_no_rights = event.duplicate_handle(Rights::NONE).unwrap();
2399
2400        let mut handles = vec![
2401            HandleDisposition::new(
2402                HandleOp::Move(event.into()),
2403                ObjectType::EVENT,
2404                Rights::SAME_RIGHTS,
2405                Status::OK,
2406            ),
2407            HandleDisposition::new(
2408                HandleOp::Move(event_no_rights.into()),
2409                ObjectType::EVENT,
2410                Rights::SAME_RIGHTS,
2411                Status::OK,
2412            ),
2413        ];
2414
2415        send.call_etc(
2416            MonotonicInstant::INFINITE,
2417            &[0, 0, 0, 0],
2418            &mut handles,
2419            &mut MessageBufEtc::default(),
2420        )
2421        .unwrap_err();
2422
2423        // Both handles should be invalidated.
2424        assert_eq!(handles[0].raw_handle(), sys::ZX_HANDLE_INVALID);
2425        assert_eq!(handles[1].raw_handle(), sys::ZX_HANDLE_INVALID);
2426
2427        // Each handle should separately report the status of transferring/duplicating that handle.
2428        assert_eq!(handles[0].result, Status::OK);
2429        assert_ne!(handles[1].result, Status::OK, "must have duplicate rights to succeed");
2430    }
2431
2432    #[test]
2433    fn channel_call_etc_vectored_preserves_per_disposition_failures() {
2434        let (send, _recv) = Channel::create();
2435
2436        let event = crate::Event::create();
2437        let event_no_rights = event.duplicate_handle(Rights::NONE).unwrap();
2438
2439        let mut handles = vec![
2440            HandleDisposition::new(
2441                HandleOp::Move(event.into()),
2442                ObjectType::EVENT,
2443                Rights::SAME_RIGHTS,
2444                Status::OK,
2445            ),
2446            HandleDisposition::new(
2447                HandleOp::Move(event_no_rights.into()),
2448                ObjectType::EVENT,
2449                Rights::SAME_RIGHTS,
2450                Status::OK,
2451            ),
2452        ];
2453
2454        send.callv_etc(
2455            MonotonicInstant::INFINITE,
2456            &[ChannelIoSlice::new(&[0, 0]), ChannelIoSlice::new(&[0, 0])],
2457            &mut handles,
2458            &mut MessageBufEtc::default(),
2459        )
2460        .unwrap_err();
2461
2462        // Both handles should be invalidated.
2463        assert_eq!(handles[0].raw_handle(), sys::ZX_HANDLE_INVALID);
2464        assert_eq!(handles[1].raw_handle(), sys::ZX_HANDLE_INVALID);
2465
2466        // Each handle should separately report the status of transferring/duplicating that handle.
2467        assert_eq!(handles[0].result, Status::OK);
2468        assert_ne!(handles[1].result, Status::OK, "must have duplicate rights to succeed");
2469    }
2470}