use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use tpt_archon_bridge::capability::{Capability, Resource, Right, SharedIssuer};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Message {
pub channel: u64,
pub payload: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IpcError {
Denied,
NoSuchChannel,
}
#[derive(Debug)]
pub struct MessageRouter {
inboxes: BTreeMap<u64, Vec<Message>>,
issuer: SharedIssuer,
}
impl MessageRouter {
pub fn new(issuer: SharedIssuer) -> Self {
Self {
inboxes: BTreeMap::new(),
issuer,
}
}
pub fn register_channel(&mut self, channel: u64) {
self.inboxes.entry(channel).or_default();
}
pub fn send(&mut self, cap: &Capability, message: Message) -> Result<(), IpcError> {
if !self
.issuer
.borrow()
.authorizes(cap, Resource::Channel(message.channel), Right::Write)
{
return Err(IpcError::Denied);
}
let inbox = self
.inboxes
.get_mut(&message.channel)
.ok_or(IpcError::NoSuchChannel)?;
inbox.push(message);
Ok(())
}
pub fn receive(&mut self, cap: &Capability, channel: u64) -> Result<Vec<Message>, IpcError> {
if !self
.issuer
.borrow()
.authorizes(cap, Resource::Channel(channel), Right::Read)
{
return Err(IpcError::Denied);
}
let inbox = self
.inboxes
.get_mut(&channel)
.ok_or(IpcError::NoSuchChannel)?;
Ok(core::mem::take(inbox))
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::rc::Rc;
use core::cell::RefCell;
use tpt_archon_bridge::capability::CapabilityIssuer;
fn shared_issuer() -> Rc<RefCell<CapabilityIssuer>> {
Rc::new(RefCell::new(CapabilityIssuer::new()))
}
#[test]
fn authorized_send_and_receive() {
let issuer = shared_issuer();
let mut router = MessageRouter::new(issuer.clone());
router.register_channel(7);
let send_cap = issuer.borrow_mut().mint(Resource::Channel(7), Right::Write);
let recv_cap = issuer.borrow_mut().mint(Resource::Channel(7), Right::Read);
router
.send(
&send_cap,
Message {
channel: 7,
payload: alloc::vec![1, 2, 3],
},
)
.unwrap();
let msgs = router.receive(&recv_cap, 7).unwrap();
assert_eq!(msgs.len(), 1);
assert_eq!(msgs[0].payload, alloc::vec![1, 2, 3]);
assert!(router.receive(&recv_cap, 7).unwrap().is_empty());
}
#[test]
fn send_without_write_capability_is_denied() {
let issuer = shared_issuer();
let mut router = MessageRouter::new(issuer.clone());
router.register_channel(1);
let read_only = issuer.borrow_mut().mint(Resource::Channel(1), Right::Read);
assert_eq!(
router.send(
&read_only,
Message {
channel: 1,
payload: alloc::vec![]
}
),
Err(IpcError::Denied)
);
}
#[test]
fn unknown_channel_errors() {
let issuer = shared_issuer();
let mut router = MessageRouter::new(issuer.clone());
let cap = issuer
.borrow_mut()
.mint(Resource::Channel(99), Right::Write);
assert_eq!(
router.send(
&cap,
Message {
channel: 99,
payload: alloc::vec![]
}
),
Err(IpcError::NoSuchChannel)
);
}
#[test]
fn revoked_capability_is_denied_at_send_and_receive() {
let issuer = shared_issuer();
let mut router = MessageRouter::new(issuer.clone());
router.register_channel(3);
let cap = issuer
.borrow_mut()
.mint(Resource::Channel(3), Right::ReadWrite);
router
.send(
&cap,
Message {
channel: 3,
payload: alloc::vec![9],
},
)
.unwrap();
issuer.borrow_mut().revoke(&cap);
assert_eq!(
router.send(
&cap,
Message {
channel: 3,
payload: alloc::vec![9]
}
),
Err(IpcError::Denied)
);
assert_eq!(router.receive(&cap, 3), Err(IpcError::Denied));
}
}