| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| //! Type-safe bindings for Zircon channel objects. |
| |
| use crate::{AsHandleRef, HandleBased, Handle, HandleRef, Peered, Status, Time, usize_into_u32, size_to_u32_sat}; |
| use crate::ok; |
| use fuchsia_zircon_sys as sys; |
| use std::mem; |
| |
| /// An object representing a Zircon |
| /// [channel](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/objects/channel.md). |
| /// |
| /// As essentially a subtype of `Handle`, it can be freely interconverted. |
| #[derive(Debug, Eq, PartialEq, Hash)] |
| #[repr(transparent)] |
| pub struct Channel(Handle); |
| impl_handle_based!(Channel); |
| impl Peered for Channel {} |
| |
| impl Channel { |
| /// Create a channel, resulting in a pair of `Channel` objects representing both |
| /// sides of the channel. Messages written into one maybe read from the opposite. |
| /// |
| /// Wraps the |
| /// [zx_channel_create](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/channel_create.md) |
| /// syscall. |
| pub fn create() -> Result<(Channel, Channel), Status> { |
| unsafe { |
| let mut handle0 = 0; |
| let mut handle1 = 0; |
| let opts = 0; |
| ok(sys::zx_channel_create(opts, &mut handle0, &mut handle1))?; |
| Ok(( |
| Self::from(Handle::from_raw(handle0)), |
| Self::from(Handle::from_raw(handle1)) |
| )) |
| } |
| } |
| |
| /// Read a message from a channel. Wraps the |
| /// [zx_channel_read](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/channel_read.md) |
| /// syscall. |
| /// |
| /// If the vectors lack the capacity to hold the pending message, |
| /// returns an `Err` with the number of bytes and number of handles needed. |
| /// Otherwise returns an `Ok` with the result as usual. |
| pub fn read_raw(&self, bytes: &mut Vec<u8>, handles: &mut Vec<Handle>) |
| -> Result<Result<(), Status>, (usize, usize)> |
| { |
| let opts = 0; |
| unsafe { |
| bytes.clear(); |
| handles.clear(); |
| let raw_handle = self.raw_handle(); |
| let mut num_bytes: u32 = size_to_u32_sat(bytes.capacity()); |
| let mut num_handles: u32 = size_to_u32_sat(handles.capacity()); |
| let status = ok(sys::zx_channel_read(raw_handle, opts, |
| bytes.as_mut_ptr(), handles.as_mut_ptr() as *mut _, |
| num_bytes, num_handles, &mut num_bytes, &mut num_handles)); |
| if status == Err(Status::BUFFER_TOO_SMALL) { |
| Err((num_bytes as usize, num_handles as usize)) |
| } else { |
| Ok(status.map(|()| { |
| bytes.set_len(num_bytes as usize); |
| handles.set_len(num_handles as usize); |
| })) |
| } |
| } |
| } |
| |
| /// Read a message from a channel. |
| /// |
| /// Note that this method can cause internal reallocations in the `MessageBuf` |
| /// if it is lacks capacity to hold the full message. If such reallocations |
| /// are not desirable, use `read_raw` instead. |
| pub fn read(&self, buf: &mut MessageBuf) -> Result<(), Status> { |
| let (bytes, handles) = buf.split_mut(); |
| self.read_split(bytes, handles) |
| } |
| |
| /// Read a message from a channel into a separate byte vector and handle vector. |
| /// |
| /// Note that this method can cause internal reallocations in the `MessageBuf` |
| /// if it is lacks capacity to hold the full message. If such reallocations |
| /// are not desirable, use `read_raw` instead. |
| pub fn read_split(&self, bytes: &mut Vec<u8>, handles: &mut Vec<Handle>) |
| -> Result<(), Status> |
| { |
| loop { |
| match self.read_raw(bytes, handles) { |
| Ok(result) => return result, |
| Err((num_bytes, num_handles)) => { |
| ensure_capacity(bytes, num_bytes); |
| ensure_capacity(handles, num_handles); |
| } |
| } |
| } |
| } |
| |
| /// Write a message to a channel. Wraps the |
| /// [zx_channel_write](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/channel_write.md) |
| /// syscall. |
| pub fn write(&self, bytes: &[u8], handles: &mut Vec<Handle>) |
| -> Result<(), Status> |
| { |
| let opts = 0; |
| let n_bytes = usize_into_u32(bytes.len()).map_err(|_| Status::OUT_OF_RANGE)?; |
| let n_handles = usize_into_u32(handles.len()).map_err(|_| Status::OUT_OF_RANGE)?; |
| unsafe { |
| let status = sys::zx_channel_write(self.raw_handle(), opts, bytes.as_ptr(), n_bytes, |
| handles.as_ptr() as *const sys::zx_handle_t, n_handles); |
| // Handles are always consumed, forget them on sender side |
| handles.set_len(0); |
| ok(status)?; |
| Ok(()) |
| } |
| } |
| |
| /// Send a message consisting of the given bytes and handles to a channel and await a reply. |
| /// |
| /// The first four bytes of the written and read back messages are treated as a transaction ID |
| /// of type `zx_txid_t`. The kernel generates a txid for the written message, replacing that |
| /// part of the message as read from userspace. In other words, the first four bytes of |
| /// `bytes` will be ignored, and the first four bytes of the response will contain a |
| /// kernel-generated txid. |
| /// |
| /// Wraps the |
| /// [zx_channel_call](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/channel_call.md) |
| /// syscall. |
| /// |
| /// Note that unlike [`read`][read], the caller must ensure that the MessageBuf has enough |
| /// capacity for the bytes and handles which will be received, as replies which are too large |
| /// are discarded. |
| /// |
| /// On failure returns the both the main and read status. |
| /// |
| /// [read]: struct.Channel.html#method.read |
| pub fn call(&self, timeout: Time, bytes: &[u8], handles: &mut Vec<Handle>, |
| buf: &mut MessageBuf) -> Result<(), Status> |
| { |
| let write_num_bytes = usize_into_u32(bytes.len()).map_err( |
| |_| Status::OUT_OF_RANGE)?; |
| let write_num_handles = usize_into_u32(handles.len()).map_err( |
| |_| Status::OUT_OF_RANGE)?; |
| buf.clear(); |
| let read_num_bytes: u32 = size_to_u32_sat(buf.bytes.capacity()); |
| let read_num_handles: u32 = size_to_u32_sat(buf.handles.capacity()); |
| let args = sys::zx_channel_call_args_t { |
| wr_bytes: bytes.as_ptr(), |
| wr_handles: handles.as_ptr() as *const sys::zx_handle_t, |
| rd_bytes: buf.bytes.as_mut_ptr(), |
| rd_handles: buf.handles.as_mut_ptr() as *mut _, |
| wr_num_bytes: write_num_bytes, |
| wr_num_handles: write_num_handles, |
| rd_num_bytes: read_num_bytes, |
| rd_num_handles: read_num_handles, |
| }; |
| let mut actual_read_bytes: u32 = 0; |
| let mut actual_read_handles: u32 = 0; |
| let options = 0; |
| let status = unsafe { |
| Status::from_raw( |
| sys::zx_channel_call( |
| self.raw_handle(), options, timeout.nanos(), &args, &mut actual_read_bytes, |
| &mut actual_read_handles)) |
| }; |
| unsafe { |
| // Handles are always consumed. |
| handles.set_len(0); |
| buf.bytes.set_len(actual_read_bytes as usize); |
| buf.handles.set_len(actual_read_handles as usize); |
| } |
| if Status::OK == status { |
| Ok(()) |
| } else { |
| Err(status) |
| } |
| } |
| } |
| |
| #[test] |
| pub fn test_handle_repr() { |
| assert_eq!(::std::mem::size_of::<sys::zx_handle_t>(), 4); |
| assert_eq!(::std::mem::size_of::<Handle>(), 4); |
| assert_eq!(::std::mem::align_of::<sys::zx_handle_t>(), ::std::mem::align_of::<Handle>()); |
| |
| // This test asserts that repr(transparent) still works for Handle -> zx_handle_t |
| |
| let n: Vec<sys::zx_handle_t> = vec![0, 100, 2<<32-1]; |
| let v: Vec<Handle> = n.iter().map(|h| unsafe { Handle::from_raw(*h) } ).collect(); |
| |
| for (handle, raw) in v.iter().zip(n.iter()) { |
| unsafe { |
| assert_eq!(*(handle as *const _ as *const [u8; 4]), *(raw as *const _ as *const [u8; 4])); |
| } |
| } |
| |
| for h in v.into_iter() { |
| ::std::mem::forget(h); |
| } |
| } |
| |
| impl AsRef<Channel> for Channel { |
| fn as_ref(&self) -> &Self { |
| &self |
| } |
| } |
| |
| /// A buffer for _receiving_ messages from a channel. |
| /// |
| /// A `MessageBuf` is essentially a byte buffer and a vector of |
| /// handles, but move semantics for "taking" handles requires special handling. |
| /// |
| /// Note that for sending messages to a channel, the caller manages the buffers, |
| /// using a plain byte slice and `Vec<Handle>`. |
| #[derive(Debug, Default)] |
| pub struct MessageBuf { |
| bytes: Vec<u8>, |
| handles: Vec<Handle>, |
| } |
| |
| impl MessageBuf { |
| /// Create a new, empty, message buffer. |
| pub fn new() -> Self { |
| Default::default() |
| } |
| |
| /// Create a new non-empty message buffer. |
| pub fn new_with(v: Vec<u8>, h: Vec<Handle>) -> Self { |
| Self{ |
| bytes: v, |
| handles: h, |
| } |
| } |
| |
| /// Splits apart the message buf into a vector of bytes and a vector of handles. |
| pub fn split_mut(&mut self) -> (&mut Vec<u8>, &mut Vec<Handle>) { |
| (&mut self.bytes, &mut self.handles) |
| } |
| |
| /// Splits apart the message buf into a vector of bytes and a vector of handles. |
| pub fn split(self) -> (Vec<u8>, Vec<Handle>) { |
| (self.bytes, self.handles) |
| } |
| |
| /// Ensure that the buffer has the capacity to hold at least `n_bytes` bytes. |
| pub fn ensure_capacity_bytes(&mut self, n_bytes: usize) { |
| ensure_capacity(&mut self.bytes, n_bytes); |
| } |
| |
| /// Ensure that the buffer has the capacity to hold at least `n_handles` handles. |
| pub fn ensure_capacity_handles(&mut self, n_handles: usize) { |
| ensure_capacity(&mut self.handles, n_handles); |
| } |
| |
| /// Ensure that at least n_bytes bytes are initialized (0 fill). |
| pub fn ensure_initialized_bytes(&mut self, n_bytes: usize) { |
| if n_bytes <= self.bytes.len() { |
| return; |
| } |
| self.bytes.resize(n_bytes, 0); |
| } |
| |
| /// Get a reference to the bytes of the message buffer, as a `&[u8]` slice. |
| pub fn bytes(&self) -> &[u8] { |
| self.bytes.as_slice() |
| } |
| |
| /// The number of handles in the message buffer. Note this counts the number |
| /// available when the message was received; `take_handle` does not affect |
| /// the count. |
| pub fn n_handles(&self) -> usize { |
| self.handles.len() |
| } |
| |
| /// Take the handle at the specified index from the message buffer. If the |
| /// method is called again with the same index, it will return `None`, as |
| /// will happen if the index exceeds the number of handles available. |
| pub fn take_handle(&mut self, index: usize) -> Option<Handle> { |
| self.handles.get_mut(index).and_then(|handle| |
| if handle.is_invalid() { |
| None |
| } else { |
| Some(mem::replace(handle, Handle::invalid())) |
| } |
| ) |
| } |
| |
| /// Clear the bytes and handles contained in the buf. This will drop any |
| /// contained handles, resulting in their resources being freed. |
| pub fn clear(&mut self) { |
| self.bytes.clear(); |
| self.handles.clear(); |
| } |
| } |
| |
| fn ensure_capacity<T>(vec: &mut Vec<T>, size: usize) { |
| let len = vec.len(); |
| if size > len { |
| vec.reserve(size - len); |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| use crate::{DurationNum, Rights, Signals, Vmo}; |
| use std::thread; |
| |
| #[test] |
| fn channel_basic() { |
| let (p1, p2) = Channel::create().unwrap(); |
| |
| let mut empty = vec![]; |
| assert!(p1.write(b"hello", &mut empty).is_ok()); |
| |
| let mut buf = MessageBuf::new(); |
| assert!(p2.read(&mut buf).is_ok()); |
| assert_eq!(buf.bytes(), b"hello"); |
| } |
| |
| #[test] |
| fn channel_read_raw_too_small() { |
| let (p1, p2) = Channel::create().unwrap(); |
| |
| let mut empty = vec![]; |
| assert!(p1.write(b"hello", &mut empty).is_ok()); |
| |
| let result = p2.read_raw(&mut vec![], &mut vec![]); |
| assert_eq!(result, Err((5, 0))); |
| } |
| |
| #[test] |
| fn channel_send_handle() { |
| let hello_length: usize = 5; |
| |
| // Create a pair of channels and a virtual memory object. |
| let (p1, p2) = Channel::create().unwrap(); |
| let vmo = Vmo::create(hello_length as u64).unwrap(); |
| |
| // Duplicate VMO handle and send it down the channel. |
| let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into(); |
| let mut handles_to_send: Vec<Handle> = vec![duplicate_vmo_handle]; |
| assert!(p1.write(b"", &mut handles_to_send).is_ok()); |
| // Handle should be removed from vector. |
| assert!(handles_to_send.is_empty()); |
| |
| // Read the handle from the receiving channel. |
| let mut buf = MessageBuf::new(); |
| assert!(p2.read(&mut buf).is_ok()); |
| assert_eq!(buf.n_handles(), 1); |
| // Take the handle from the buffer. |
| let received_handle = buf.take_handle(0).unwrap(); |
| // Should not affect number of handles. |
| assert_eq!(buf.n_handles(), 1); |
| // Trying to take it again should fail. |
| assert!(buf.take_handle(0).is_none()); |
| |
| // Now to test that we got the right handle, try writing something to it... |
| let received_vmo = Vmo::from(received_handle); |
| assert!(received_vmo.write(b"hello", 0).is_ok()); |
| |
| // ... and reading it back from the original VMO. |
| let mut read_vec = vec![0; hello_length]; |
| assert!(vmo.read(&mut read_vec, 0).is_ok()); |
| assert_eq!(read_vec, b"hello"); |
| } |
| |
| #[test] |
| fn channel_call_timeout() { |
| let ten_ms = 10.millis(); |
| |
| // Create a pair of channels and a virtual memory object. |
| let (p1, p2) = Channel::create().unwrap(); |
| let vmo = Vmo::create(0 as u64).unwrap(); |
| |
| // Duplicate VMO handle and send it along with the call. |
| let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into(); |
| let mut handles_to_send: Vec<Handle> = vec![duplicate_vmo_handle]; |
| let mut buf = MessageBuf::new(); |
| assert_eq!(p1.call(ten_ms.after_now(), b"0000call", &mut handles_to_send, &mut buf), |
| Err(Status::TIMED_OUT)); |
| // Handle should be removed from vector even though we didn't get a response, as it was |
| // still sent over the channel. |
| assert!(handles_to_send.is_empty()); |
| |
| // Should be able to read call even though it timed out waiting for a response. |
| let mut buf = MessageBuf::new(); |
| assert!(p2.read(&mut buf).is_ok()); |
| assert_eq!(&buf.bytes()[4..], b"call"); |
| assert_eq!(buf.n_handles(), 1); |
| } |
| |
| #[test] |
| fn channel_call() { |
| // Create a pair of channels |
| let (p1, p2) = Channel::create().unwrap(); |
| |
| // create an mpsc channel for communicating the call data for later assertion |
| let (tx, rx) = ::std::sync::mpsc::channel(); |
| |
| // Start a new thread to respond to the call. |
| thread::spawn(move || { |
| let mut buf = MessageBuf::new(); |
| // if either the read or the write fail, this thread will panic, |
| // resulting in tx being dropped, which will be noticed by the rx. |
| p2.wait_handle(Signals::CHANNEL_READABLE, 1.seconds().after_now()).expect("callee wait error"); |
| p2.read(&mut buf).expect("callee read error"); |
| |
| let (bytes, handles) = buf.split_mut(); |
| tx.send(bytes.clone()).expect("callee mpsc send error"); |
| assert_eq!(handles.len(), 0); |
| |
| bytes.truncate(4); // Drop the received message, leaving only the txid |
| bytes.extend_from_slice(b"response"); |
| |
| p2.write(bytes, handles).expect("callee write error"); |
| }); |
| |
| // Make the call. |
| let mut buf = MessageBuf::new(); |
| buf.ensure_capacity_bytes(12); |
| // NOTE(raggi): CQ has been seeing some long stalls from channel call, |
| // and it's as yet unclear why. The timeout here has been made much |
| // larger in order to avoid that, as the issues are not issues with this |
| // crate's concerns. The timeout is here just to prevent the tests from |
| // stalling forever if a developer makes a mistake locally in this |
| // crate. Tests of Zircon behavior or virtualization behavior should be |
| // covered elsewhere. See ZX-1324. |
| p1.call(30.seconds().after_now(), b"txidcall", &mut vec![], &mut buf).expect("channel call error"); |
| assert_eq!(&buf.bytes()[4..], b"response"); |
| assert_eq!(buf.n_handles(), 0); |
| |
| let sbuf = rx.recv().expect("mpsc channel recv error"); |
| assert_eq!(&sbuf[4..], b"call"); |
| } |
| } |