use core::{marker::PhantomData, task::Poll};
use trussed_core::{
api::{Reply, RequestVariant},
ClientError, ClientResult, Error, FutureResult, InterruptFlag, PollClient, Result,
};
use crate::backend::CoreOnly;
use crate::pipe::TrussedRequester;
use crate::platform::Syscall;
#[cfg(feature = "crypto-client")]
mod mechanisms;
#[cfg(feature = "all-clients")]
pub trait Client:
trussed_core::CertificateClient
+ trussed_core::CryptoClient
+ trussed_core::CounterClient
+ trussed_core::FilesystemClient
+ trussed_core::ManagementClient
+ trussed_core::UiClient
{
}
#[cfg(feature = "all-clients")]
impl<S: Syscall, E> Client for ClientImplementation<'_, S, E> {}
pub struct ClientImplementation<'a, S, D = CoreOnly> {
syscall: S,
pub(crate) interchange: TrussedRequester<'a>,
pub(crate) interrupt: Option<&'static InterruptFlag>,
pending: Option<u8>,
_marker: PhantomData<D>,
}
impl<'a, S, E> ClientImplementation<'a, S, E>
where
S: Syscall,
{
pub fn new(
interchange: TrussedRequester<'a>,
syscall: S,
interrupt: Option<&'static InterruptFlag>,
) -> Self {
Self {
interchange,
pending: None,
syscall,
interrupt,
_marker: Default::default(),
}
}
}
impl<S, E> PollClient for ClientImplementation<'_, S, E>
where
S: Syscall,
{
fn poll(&mut self) -> Poll<Result<Reply, Error>> {
match self.interchange.take_response() {
Some(reply) => {
match reply {
Ok(reply) => {
if Some(u8::from(&reply)) == self.pending {
self.pending = None;
Poll::Ready(Ok(reply))
} else {
info!(
"got: {:?}, expected: {:?}",
Some(u8::from(&reply)),
self.pending
);
Poll::Ready(Err(Error::InternalError))
}
}
Err(error) => {
self.pending = None;
Poll::Ready(Err(error))
}
}
}
None => {
debug_assert_ne!(
self.interchange.state(),
interchange::State::Idle,
"requests can't be cancelled"
);
Poll::Pending
}
}
}
fn request<Rq: RequestVariant>(&mut self, req: Rq) -> ClientResult<'_, Rq::Reply, Self> {
if self.pending.is_some() {
return Err(ClientError::Pending);
}
let request = req.into();
self.pending = Some(u8::from(&request));
self.interchange.request(request).unwrap();
self.syscall.syscall();
Ok(FutureResult::new(self))
}
fn interrupt(&self) -> Option<&'static InterruptFlag> {
self.interrupt
}
}
#[cfg(feature = "certificate-client")]
impl<S: Syscall, E> trussed_core::CertificateClient for ClientImplementation<'_, S, E> {}
#[cfg(feature = "crypto-client")]
impl<S: Syscall, E> trussed_core::CryptoClient for ClientImplementation<'_, S, E> {}
#[cfg(feature = "counter-client")]
impl<S: Syscall, E> trussed_core::CounterClient for ClientImplementation<'_, S, E> {}
#[cfg(feature = "filesystem-client")]
impl<S: Syscall, E> trussed_core::FilesystemClient for ClientImplementation<'_, S, E> {}
#[cfg(feature = "management-client")]
impl<S: Syscall, E> trussed_core::ManagementClient for ClientImplementation<'_, S, E> {}
#[cfg(feature = "ui-client")]
impl<S: Syscall, E> trussed_core::UiClient for ClientImplementation<'_, S, E> {}