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