1 use pinweaver_storage::{ 2 current::{StorageInterface, StorageRequest, StorageResponse}, 3 util::{DeserializeExact, ForwardTipcSerialize}, 4 }; 5 use std::sync::{Arc, Mutex, MutexGuard}; 6 use tipc::{Handle, TipcError, UnbufferedService}; 7 use trusty_std::alloc::FallibleVec; 8 use trusty_sys::Error; 9 10 type Response = DeserializeExact<StorageResponse>; 11 const MAX_MESSAGE_SIZE: usize = <Response as tipc::Deserialize>::MAX_SERIALIZED_SIZE; 12 13 /// The service that initializes the given `StorageClient` upon connection. 14 /// 15 /// This is a tipc server: the storage daemon running in Android connects to 16 /// this service, acting as a tipc client. The connection remains open while 17 /// the main service sends commands to the storage daemon through the 18 /// `StorageClient`. 19 pub(crate) struct StorageClientService { 20 client: Arc<StorageClient>, 21 } 22 23 impl StorageClientService { new(client: Arc<StorageClient>) -> Self24 pub fn new(client: Arc<StorageClient>) -> Self { 25 Self { client } 26 } 27 } 28 29 impl UnbufferedService for StorageClientService { 30 type Connection = (); 31 32 /// Stores the connection handle for later use. on_connect( &self, _port: &tipc::PortCfg, handle: &tipc::Handle, _peer: &tipc::Uuid, ) -> tipc::Result<tipc::ConnectResult<Self::Connection>>33 fn on_connect( 34 &self, 35 _port: &tipc::PortCfg, 36 handle: &tipc::Handle, 37 _peer: &tipc::Uuid, 38 ) -> tipc::Result<tipc::ConnectResult<Self::Connection>> { 39 self.client.set_server_handle(handle)?; 40 Ok(tipc::ConnectResult::Accept(())) 41 } 42 43 /// Not used, as the storage daemon acts as a server. on_message( &self, _connection: &Self::Connection, _handle: &tipc::Handle, _buffer: &mut [u8], ) -> tipc::Result<tipc::MessageResult>44 fn on_message( 45 &self, 46 _connection: &Self::Connection, 47 _handle: &tipc::Handle, 48 _buffer: &mut [u8], 49 ) -> tipc::Result<tipc::MessageResult> { 50 Ok(tipc::MessageResult::MaintainConnection) 51 } 52 on_disconnect(&self, _connection: &Self::Connection)53 fn on_disconnect(&self, _connection: &Self::Connection) { 54 log::error!("Storage client disconnected"); 55 self.client.clear_server_handle(); 56 } 57 } 58 59 #[derive(Default)] 60 pub(crate) struct StorageClient { 61 /// Initialized by the [`StorageClientService`]. 62 server_handle: Mutex<Option<Handle>>, 63 } 64 65 impl StorageClient { 66 /// Locks the mutex or returns an error. lock(&self) -> tipc::Result<MutexGuard<'_, Option<Handle>>>67 fn lock(&self) -> tipc::Result<MutexGuard<'_, Option<Handle>>> { 68 self.server_handle.lock().map_err(|_| TipcError::SystemError(Error::BadState)) 69 } 70 71 /// Sets the server handle for this storage client. 72 /// 73 /// Clones the handle to send messages, if a storage daemon hasn't already connected. set_server_handle(&self, handle: &Handle) -> tipc::Result<()>74 pub fn set_server_handle(&self, handle: &Handle) -> tipc::Result<()> { 75 match &mut *self.lock()? { 76 Some(_) => Err(TipcError::SystemError(Error::AlreadyExists)), 77 server_handle @ None => { 78 *server_handle = Some(handle.try_clone()?); 79 Ok(()) 80 } 81 } 82 } 83 84 /// Clears the current server handle for this storage client. 85 /// 86 /// Ignores whether there is currently a handle set. clear_server_handle(&self)87 pub fn clear_server_handle(&self) { 88 if let Ok(mut handle) = self.lock() { 89 *handle = None; 90 } 91 } 92 } 93 94 impl StorageInterface for StorageClient { 95 type Error = tipc::TipcError; 96 request(&self, request: &StorageRequest) -> tipc::Result<StorageResponse>97 fn request(&self, request: &StorageRequest) -> tipc::Result<StorageResponse> { 98 let guard = self.lock()?; 99 let handle = guard.as_ref().ok_or(TipcError::SystemError(Error::NotReady))?; 100 handle.send(&ForwardTipcSerialize(request))?; 101 let mut buf: Vec<u8> = FallibleVec::try_with_capacity(MAX_MESSAGE_SIZE)?; 102 buf.resize(MAX_MESSAGE_SIZE, 0); 103 let response: Response = handle.recv(&mut buf)?; 104 Ok(response.0) 105 } 106 } 107