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