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