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