use alloc::boxed::Box;
use binder::{unstable_api::AsNative, SpIBinder};
use binder_rpc_server_bindgen::{
trusty_peer_id, AIBinder, ARpcServerTrusty, ARpcServerTrusty_delete,
ARpcServerTrusty_handleChannelCleanup, ARpcServerTrusty_handleConnect,
ARpcServerTrusty_handleDisconnect, ARpcServerTrusty_handleMessage,
ARpcServerTrusty_newPerSession,
};
use std::{ffi::c_void, ptr};
use tipc::{
ClientIdentifier, ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService,
Uuid,
};
pub trait PerSessionCallback:
Fn(ClientIdentifier) -> Option<SpIBinder> + Send + Sync + 'static
{
}
impl<T> PerSessionCallback for T where
T: Fn(ClientIdentifier) -> Option<SpIBinder> + Send + Sync + 'static
{
}
pub struct RpcServer {
inner: *mut ARpcServerTrusty,
}
unsafe impl Send for RpcServer {}
unsafe impl Sync for RpcServer {}
impl Drop for RpcServer {
fn drop(&mut self) {
unsafe {
ARpcServerTrusty_delete(self.inner);
}
}
}
impl RpcServer {
pub fn new(service: SpIBinder) -> RpcServer {
Self::new_per_session(move |_uuid| Some(service.clone()))
}
pub fn new_per_session<F: PerSessionCallback>(f: F) -> RpcServer {
let inner = unsafe {
ARpcServerTrusty_newPerSession(
Some(per_session_callback_wrapper::<F>),
Box::into_raw(Box::new(f)).cast(),
Some(per_session_callback_deleter::<F>),
)
};
RpcServer { inner }
}
}
unsafe extern "C" fn per_session_callback_wrapper<F: PerSessionCallback>(
peer: *const trusty_peer_id,
peer_len: usize,
cb_ptr: *mut c_void,
) -> *mut AIBinder {
let cb = unsafe { &mut *cb_ptr.cast::<F>() };
let peer = unsafe { &*peer };
let peer = unsafe { trusty_sys::TrustyPeerIdRef::from_raw_parts(peer, peer_len) };
cb(ClientIdentifier::from_c_repr(peer)).map_or_else(ptr::null_mut, |b| {
std::mem::ManuallyDrop::new(b).as_native_mut().cast()
})
}
unsafe extern "C" fn per_session_callback_deleter<F: PerSessionCallback>(cb: *mut c_void) {
let cb = unsafe { Box::<F>::from_raw(cb.cast()) };
drop(cb);
}
pub struct RpcServerConnection {
ctx: *mut c_void,
}
unsafe impl Send for RpcServerConnection {}
impl Drop for RpcServerConnection {
fn drop(&mut self) {
unsafe {
ARpcServerTrusty_handleChannelCleanup(self.ctx);
}
}
}
impl UnbufferedService for RpcServer {
type Connection = RpcServerConnection;
fn on_connect(
&self,
port: &PortCfg,
handle: &Handle,
peer: &Uuid,
) -> tipc::Result<ConnectResult<Self::Connection>> {
let peer = ClientIdentifier::UUID(peer.clone());
self.on_new_connection(port, handle, &peer)
}
fn on_message(
&self,
conn: &Self::Connection,
_handle: &Handle,
_buffer: &mut [u8],
) -> tipc::Result<MessageResult> {
let rc = unsafe { ARpcServerTrusty_handleMessage(conn.ctx) };
if rc < 0 {
Err(TipcError::from_uapi(rc.into()))
} else {
Ok(MessageResult::MaintainConnection)
}
}
fn on_disconnect(&self, conn: &Self::Connection) {
unsafe { ARpcServerTrusty_handleDisconnect(conn.ctx) };
}
fn on_new_connection(
&self,
_port: &PortCfg,
handle: &Handle,
peer: &ClientIdentifier,
) -> tipc::Result<ConnectResult<Self::Connection>> {
let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() };
let peer = peer.c_repr();
let (peer_ref, peer_len) = peer.as_generic().into_raw_parts();
let rc = unsafe {
ARpcServerTrusty_handleConnect(
self.inner,
handle.as_raw_fd(),
peer_ref,
peer_len,
&mut conn.ctx,
)
};
if rc < 0 {
Err(TipcError::from_uapi(rc.into()))
} else {
Ok(ConnectResult::Accept(conn))
}
}
}