diff options
Diffstat (limited to 'trusty/libtrusty-rs/src/lib.rs')
-rw-r--r-- | trusty/libtrusty-rs/src/lib.rs | 224 |
1 files changed, 0 insertions, 224 deletions
diff --git a/trusty/libtrusty-rs/src/lib.rs b/trusty/libtrusty-rs/src/lib.rs deleted file mode 100644 index 28ea07505..000000000 --- a/trusty/libtrusty-rs/src/lib.rs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Functionality for communicating with Trusty services. -//! -//! This crate provides the [`TipcChannel`] type, which allows you to establish a -//! connection to a Trusty service and then communicate with that service. -//! -//! # Usage -//! -//! To connect to a Trusty service you need two things: -//! -//! * The filesystem path to the Trusty IPC device. This is usually -//! `/dev/trusty-ipc-dev0`, which is exposed in the constant [`DEFAULT_DEVICE`]. -//! * The port name defined by the service, e.g. `com.android.ipc-unittest.srv.echo`. -//! -//! Pass these values to [`TipcChannel::connect`] to establish a connection to a -//! service. -//! -//! Once connected use the [`send`][TipcChannel::send] and [`recv`][TipcChannel::recv] -//! methods to communicate with the service. Messages are passed as byte buffers, and -//! each Trusty service has its own protocol for what data messages are expected to -//! contain. Consult the documentation for the service you are communicating with to -//! determine how to format outgoing messages and interpret incoming ones. -//! -//! The connection is closed automatically when [`TipcChannel`] is dropped. -//! -//! # Examples -//! -//! This example is a simplified version of the echo test from `tipc-test-rs`: -//! -//! ```no_run -//! use trusty::{DEFAULT_DEVICE, TipcChannel}; -//! use std::io::{Read, Write}; -//! -//! let mut chann = TipcChannel::connect( -//! DEFAULT_DEVICE, -//! "com.android.ipc-unittest.srv.echo", -//! ).unwrap(); -//! -//! chann.send("Hello, world!".as_bytes()).unwrap(); -//! -//! let mut read_buf = Vec::new(); -//! let read_len = stream.recv(&mut read_buf).unwrap(); -//! -//! let response = std::str::from_utf8(&read_buf[..read_len]).unwrap(); -//! assert_eq!("Hello, world!", response); -//! -//! // The connection is closed here. -//! ``` - -use crate::sys::tipc_connect; -use std::ffi::CString; -use std::fs::File; -use std::io::prelude::*; -use std::io::{ErrorKind, Result}; -use std::os::unix::prelude::AsRawFd; -use std::path::Path; - -mod sys; - -/// The default filesystem path for the Trusty IPC device. -pub const DEFAULT_DEVICE: &str = "/dev/trusty-ipc-dev0"; - -/// The maximum size an incoming TIPC message can be. -/// -/// This can be used to pre-allocate buffer space in order to ensure that your -/// read buffer can always hold an incoming message. -pub const MAX_MESSAGE_SIZE: usize = 4096; - -/// A channel for communicating with a Trusty service. -/// -/// See the [crate-level documentation][crate] for usage details and examples. -#[derive(Debug)] -pub struct TipcChannel(File); - -impl TipcChannel { - /// Attempts to establish a connection to the specified Trusty service. - /// - /// The first argument is the path of the Trusty device in the local filesystem, - /// e.g. `/dev/trusty-ipc-dev0`. The second argument is the name of the service - /// to connect to, e.g. `com.android.ipc-unittest.srv.echo`. - /// - /// # Panics - /// - /// This function will panic if `service` contains any intermediate `NUL` - /// bytes. This is handled with a panic because the service names are all - /// hard-coded constants, and so such an error should always be indicative of a - /// bug in the calling code. - pub fn connect(device: impl AsRef<Path>, service: &str) -> Result<Self> { - let file = File::options().read(true).write(true).open(device)?; - - let srv_name = CString::new(service).expect("Service name contained null bytes"); - unsafe { - tipc_connect(file.as_raw_fd(), srv_name.as_ptr())?; - } - - Ok(TipcChannel(file)) - } - - /// Sends a message to the connected service. - /// - /// The entire contents of `buf` will be sent as a single message to the - /// connected service. - pub fn send(&mut self, buf: &[u8]) -> Result<()> { - let write_len = self.0.write(buf)?; - - // Verify that the expected number of bytes were written. The entire message - // should always be written with a single `write` call, or an error should have - // been returned if the message couldn't be written. An assertion failure here - // potentially means a bug in the kernel driver. - assert_eq!( - buf.len(), - write_len, - "Failed to send full message ({} of {} bytes written)", - write_len, - buf.len(), - ); - - Ok(()) - } - - /// Reads the next incoming message. - /// - /// Attempts to read the next incoming message from the connected service if any - /// exist. If the initial capacity of `buf` is not enough to hold the incoming - /// message the function repeatedly attempts to reserve additional space until - /// it is able to fully read the message. - /// - /// Blocks until there is an incoming message if there is not already a message - /// ready to be received. - /// - /// # Errors - /// - /// If this function encounters an error of the kind [`ErrorKind::Interrupted`] - /// then the error is ignored and the operation will be tried again. - /// - /// If this function encounters an error with the error code `EMSGSIZE` then - /// additional space will be reserved in `buf` and the operation will be tried - /// again. - /// - /// If any other read error is encountered then this function immediately - /// returns the error to the caller, and the length of `buf` is set to 0. - pub fn recv(&mut self, buf: &mut Vec<u8>) -> Result<()> { - // If no space has been allocated in the buffer reserve enough space to hold any - // incoming message. - if buf.capacity() == 0 { - buf.reserve(MAX_MESSAGE_SIZE); - } - - loop { - // Resize the vec to make its full capacity available to write into. - buf.resize(buf.capacity(), 0); - - match self.0.read(buf.as_mut_slice()) { - Ok(len) => { - buf.truncate(len); - return Ok(()); - } - - Err(err) => { - if let Some(libc::EMSGSIZE) = err.raw_os_error() { - // Ensure that we didn't get `EMSGSIZE` when we already had enough capacity - // to contain the maximum message size. This should never happen, but if it - // does we don't want to hang by looping infinitely. - assert!( - buf.capacity() < MAX_MESSAGE_SIZE, - "Received `EMSGSIZE` error when buffer capacity was already at maximum", - ); - - // If we didn't have enough space to hold the incoming message, reserve - // enough space to fit the maximum message size regardless of how much - // capacity the buffer already had. - buf.reserve(MAX_MESSAGE_SIZE - buf.capacity()); - } else if err.kind() == ErrorKind::Interrupted { - // If we get an interrupted error the operation can be retried as-is, i.e. - // we don't need to allocate additional space. - continue; - } else { - buf.truncate(0); - return Err(err); - } - } - } - } - } - - /// Reads the next incoming message without allocating. - /// - /// Returns the number of bytes in the received message, or any error that - /// occurred when reading the message. - /// - /// Blocks until there is an incoming message if there is not already a message - /// ready to be received. - /// - /// # Errors - /// - /// Returns an error with native error code `EMSGSIZE` if `buf` isn't large - /// enough to contain the incoming message. Use - /// [`raw_os_error`][std::io::Error::raw_os_error] to check the error code to - /// determine if you need to increase the size of `buf`. If error code - /// `EMSGSIZE` is returned the incoming message will not be dropped, and a - /// subsequent call to `recv_no_alloc` can still read it. - /// - /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read - /// operation should be retried if there is nothing else to do. - pub fn recv_no_alloc(&mut self, buf: &mut [u8]) -> Result<usize> { - self.0.read(buf) - } - - // TODO: Add method that is equivalent to `tipc_send`, i.e. that supports - // sending shared memory buffers. -} |