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