2024-04-12 00:34:46 -07:00
|
|
|
use std::{
|
|
|
|
collections::{hash_map::Entry, HashMap},
|
|
|
|
sync::Arc,
|
|
|
|
};
|
2024-03-28 22:38:21 +00:00
|
|
|
|
2024-04-12 00:34:46 -07:00
|
|
|
use anyhow::{anyhow, Result};
|
2024-03-28 22:38:21 +00:00
|
|
|
use bytes::{Buf, BytesMut};
|
2024-04-12 00:34:46 -07:00
|
|
|
use krata::idm::{
|
2024-04-21 21:00:32 -07:00
|
|
|
client::{IdmBackend, IdmInternalClient},
|
|
|
|
internal::INTERNAL_IDM_CHANNEL,
|
|
|
|
transport::IdmTransportPacket,
|
2024-04-12 00:34:46 -07:00
|
|
|
};
|
2024-03-28 07:36:48 +00:00
|
|
|
use kratart::channel::ChannelService;
|
2024-08-08 12:11:51 -07:00
|
|
|
use log::{debug, error, warn};
|
2024-03-28 22:38:21 +00:00
|
|
|
use prost::Message;
|
|
|
|
use tokio::{
|
2024-04-12 00:34:46 -07:00
|
|
|
select,
|
2024-03-28 22:38:21 +00:00
|
|
|
sync::{
|
2024-04-14 04:54:21 -07:00
|
|
|
broadcast,
|
2024-04-12 00:34:46 -07:00
|
|
|
mpsc::{channel, Receiver, Sender},
|
2024-03-28 22:38:21 +00:00
|
|
|
Mutex,
|
|
|
|
},
|
|
|
|
task::JoinHandle,
|
|
|
|
};
|
2024-04-21 21:00:32 -07:00
|
|
|
use uuid::Uuid;
|
2024-03-28 22:38:21 +00:00
|
|
|
|
2024-07-18 20:47:18 -07:00
|
|
|
use crate::zlt::ZoneLookupTable;
|
2024-04-21 21:00:32 -07:00
|
|
|
|
|
|
|
type BackendFeedMap = Arc<Mutex<HashMap<u32, Sender<IdmTransportPacket>>>>;
|
|
|
|
type ClientMap = Arc<Mutex<HashMap<u32, IdmInternalClient>>>;
|
2024-03-28 22:38:21 +00:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct DaemonIdmHandle {
|
2024-08-22 15:52:38 -07:00
|
|
|
zlt: ZoneLookupTable,
|
2024-04-12 00:34:46 -07:00
|
|
|
clients: ClientMap,
|
|
|
|
feeds: BackendFeedMap,
|
2024-04-21 21:00:32 -07:00
|
|
|
tx_sender: Sender<(u32, IdmTransportPacket)>,
|
2024-03-28 22:38:21 +00:00
|
|
|
task: Arc<JoinHandle<()>>,
|
2024-04-14 04:54:21 -07:00
|
|
|
snoop_sender: broadcast::Sender<DaemonIdmSnoopPacket>,
|
2024-03-28 22:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DaemonIdmHandle {
|
2024-04-14 04:54:21 -07:00
|
|
|
pub fn snoop(&self) -> broadcast::Receiver<DaemonIdmSnoopPacket> {
|
|
|
|
self.snoop_sender.subscribe()
|
|
|
|
}
|
|
|
|
|
2024-04-21 21:00:32 -07:00
|
|
|
pub async fn client(&self, uuid: Uuid) -> Result<IdmInternalClient> {
|
2024-08-22 15:52:38 -07:00
|
|
|
let Some(domid) = self.zlt.lookup_domid_by_uuid(&uuid).await else {
|
2024-04-21 21:00:32 -07:00
|
|
|
return Err(anyhow!("unable to find domain {}", uuid));
|
|
|
|
};
|
|
|
|
self.client_by_domid(domid).await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn client_by_domid(&self, domid: u32) -> Result<IdmInternalClient> {
|
2024-04-12 00:34:46 -07:00
|
|
|
client_or_create(domid, &self.tx_sender, &self.clients, &self.feeds).await
|
2024-03-28 22:38:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for DaemonIdmHandle {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
if Arc::strong_count(&self.task) <= 1 {
|
|
|
|
self.task.abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-28 07:36:48 +00:00
|
|
|
|
2024-04-14 04:54:21 -07:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct DaemonIdmSnoopPacket {
|
|
|
|
pub from: u32,
|
|
|
|
pub to: u32,
|
2024-04-21 21:00:32 -07:00
|
|
|
pub packet: IdmTransportPacket,
|
2024-04-14 04:54:21 -07:00
|
|
|
}
|
|
|
|
|
2024-03-28 07:36:48 +00:00
|
|
|
pub struct DaemonIdm {
|
2024-08-22 15:52:38 -07:00
|
|
|
zlt: ZoneLookupTable,
|
2024-04-12 00:34:46 -07:00
|
|
|
clients: ClientMap,
|
|
|
|
feeds: BackendFeedMap,
|
2024-04-21 21:00:32 -07:00
|
|
|
tx_sender: Sender<(u32, IdmTransportPacket)>,
|
2024-04-12 00:34:46 -07:00
|
|
|
tx_raw_sender: Sender<(u32, Vec<u8>)>,
|
2024-04-21 21:00:32 -07:00
|
|
|
tx_receiver: Receiver<(u32, IdmTransportPacket)>,
|
2024-04-12 00:34:46 -07:00
|
|
|
rx_receiver: Receiver<(u32, Option<Vec<u8>>)>,
|
2024-04-14 04:54:21 -07:00
|
|
|
snoop_sender: broadcast::Sender<DaemonIdmSnoopPacket>,
|
2024-03-28 07:36:48 +00:00
|
|
|
task: JoinHandle<()>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DaemonIdm {
|
2024-08-22 15:52:38 -07:00
|
|
|
pub async fn new(zlt: ZoneLookupTable) -> Result<DaemonIdm> {
|
2024-08-13 23:17:47 -07:00
|
|
|
debug!("allocating channel service for idm");
|
2024-04-12 00:34:46 -07:00
|
|
|
let (service, tx_raw_sender, rx_receiver) =
|
|
|
|
ChannelService::new("krata-channel".to_string(), None).await?;
|
|
|
|
let (tx_sender, tx_receiver) = channel(100);
|
2024-04-14 04:54:21 -07:00
|
|
|
let (snoop_sender, _) = broadcast::channel(100);
|
2024-08-08 12:11:51 -07:00
|
|
|
|
2024-08-13 23:17:47 -07:00
|
|
|
debug!("starting idm channel service");
|
2024-03-28 07:36:48 +00:00
|
|
|
let task = service.launch().await?;
|
2024-08-08 12:11:51 -07:00
|
|
|
|
2024-04-12 00:34:46 -07:00
|
|
|
let clients = Arc::new(Mutex::new(HashMap::new()));
|
|
|
|
let feeds = Arc::new(Mutex::new(HashMap::new()));
|
2024-08-08 12:11:51 -07:00
|
|
|
|
2024-03-28 22:38:21 +00:00
|
|
|
Ok(DaemonIdm {
|
2024-08-22 15:52:38 -07:00
|
|
|
zlt,
|
2024-04-12 00:34:46 -07:00
|
|
|
rx_receiver,
|
|
|
|
tx_receiver,
|
|
|
|
tx_sender,
|
|
|
|
tx_raw_sender,
|
2024-04-14 04:54:21 -07:00
|
|
|
snoop_sender,
|
2024-03-28 22:38:21 +00:00
|
|
|
task,
|
2024-04-12 00:34:46 -07:00
|
|
|
clients,
|
|
|
|
feeds,
|
2024-03-28 22:38:21 +00:00
|
|
|
})
|
2024-03-28 07:36:48 +00:00
|
|
|
}
|
|
|
|
|
2024-03-28 22:38:21 +00:00
|
|
|
pub async fn launch(mut self) -> Result<DaemonIdmHandle> {
|
2024-08-22 15:52:38 -07:00
|
|
|
let zlt = self.zlt.clone();
|
2024-04-12 00:34:46 -07:00
|
|
|
let clients = self.clients.clone();
|
|
|
|
let feeds = self.feeds.clone();
|
|
|
|
let tx_sender = self.tx_sender.clone();
|
2024-04-14 04:54:21 -07:00
|
|
|
let snoop_sender = self.snoop_sender.clone();
|
2024-03-28 22:38:21 +00:00
|
|
|
let task = tokio::task::spawn(async move {
|
|
|
|
let mut buffers: HashMap<u32, BytesMut> = HashMap::new();
|
2024-04-14 04:54:21 -07:00
|
|
|
|
|
|
|
while let Err(error) = self.process(&mut buffers).await {
|
2024-03-28 07:36:48 +00:00
|
|
|
error!("failed to process idm: {}", error);
|
|
|
|
}
|
2024-03-28 22:38:21 +00:00
|
|
|
});
|
|
|
|
Ok(DaemonIdmHandle {
|
2024-08-22 15:52:38 -07:00
|
|
|
zlt,
|
2024-04-12 00:34:46 -07:00
|
|
|
clients,
|
|
|
|
feeds,
|
|
|
|
tx_sender,
|
2024-04-14 04:54:21 -07:00
|
|
|
snoop_sender,
|
2024-03-28 22:38:21 +00:00
|
|
|
task: Arc::new(task),
|
|
|
|
})
|
2024-03-28 07:36:48 +00:00
|
|
|
}
|
|
|
|
|
2024-08-13 23:17:47 -07:00
|
|
|
async fn process_rx_packet(
|
|
|
|
&mut self,
|
|
|
|
domid: u32,
|
|
|
|
data: Option<Vec<u8>>,
|
|
|
|
buffers: &mut HashMap<u32, BytesMut>,
|
|
|
|
) -> Result<()> {
|
|
|
|
// check if data is present, if it is not, that signals a closed channel.
|
|
|
|
if let Some(data) = data {
|
|
|
|
let buffer = buffers.entry(domid).or_insert_with_key(|_| BytesMut::new());
|
|
|
|
buffer.extend_from_slice(&data);
|
|
|
|
loop {
|
|
|
|
// check if the buffer is less than the header size, if so, wait for more data
|
|
|
|
if buffer.len() < 6 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for the magic bytes 0xff, 0xff at the start of the message, if that doesn't
|
|
|
|
// exist, clear the buffer. this ensures that partial messages won't be processed.
|
|
|
|
if buffer[0] != 0xff || buffer[1] != 0xff {
|
|
|
|
buffer.clear();
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
// read the size from the buffer as a little endian u32
|
|
|
|
let size = (buffer[2] as u32
|
|
|
|
| (buffer[3] as u32) << 8
|
|
|
|
| (buffer[4] as u32) << 16
|
|
|
|
| (buffer[5] as u32) << 24) as usize;
|
|
|
|
let needed = size + 6;
|
|
|
|
if buffer.len() < needed {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
let mut packet = buffer.split_to(needed);
|
|
|
|
// advance the buffer by the header, leaving only the raw data.
|
|
|
|
packet.advance(6);
|
|
|
|
match IdmTransportPacket::decode(packet) {
|
|
|
|
Ok(packet) => {
|
|
|
|
let _ =
|
|
|
|
client_or_create(domid, &self.tx_sender, &self.clients, &self.feeds)
|
|
|
|
.await?;
|
|
|
|
let guard = self.feeds.lock().await;
|
|
|
|
if let Some(feed) = guard.get(&domid) {
|
|
|
|
let _ = feed.try_send(packet.clone());
|
|
|
|
}
|
|
|
|
let _ = self.snoop_sender.send(DaemonIdmSnoopPacket {
|
|
|
|
from: domid,
|
|
|
|
to: 0,
|
|
|
|
packet,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(packet) => {
|
|
|
|
warn!("received invalid packet from domain {}: {}", domid, packet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let mut clients = self.clients.lock().await;
|
|
|
|
let mut feeds = self.feeds.lock().await;
|
|
|
|
clients.remove(&domid);
|
|
|
|
feeds.remove(&domid);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn tx_packet(&mut self, domid: u32, packet: IdmTransportPacket) -> Result<()> {
|
|
|
|
let data = packet.encode_to_vec();
|
|
|
|
let mut buffer = vec![0u8; 6];
|
|
|
|
let length = data.len() as u32;
|
|
|
|
// magic bytes
|
|
|
|
buffer[0] = 0xff;
|
|
|
|
buffer[1] = 0xff;
|
|
|
|
// little endian u32 for message size
|
|
|
|
buffer[2] = length as u8;
|
|
|
|
buffer[3] = (length << 8) as u8;
|
|
|
|
buffer[4] = (length << 16) as u8;
|
|
|
|
buffer[5] = (length << 24) as u8;
|
|
|
|
buffer.extend_from_slice(&data);
|
|
|
|
self.tx_raw_sender.send((domid, buffer)).await?;
|
|
|
|
let _ = self.snoop_sender.send(DaemonIdmSnoopPacket {
|
|
|
|
from: 0,
|
|
|
|
to: domid,
|
|
|
|
packet,
|
|
|
|
});
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-03-28 22:38:21 +00:00
|
|
|
async fn process(&mut self, buffers: &mut HashMap<u32, BytesMut>) -> Result<()> {
|
2024-03-28 07:36:48 +00:00
|
|
|
loop {
|
2024-04-12 00:34:46 -07:00
|
|
|
select! {
|
|
|
|
x = self.rx_receiver.recv() => match x {
|
|
|
|
Some((domid, data)) => {
|
2024-08-13 23:17:47 -07:00
|
|
|
self.process_rx_packet(domid, data, buffers).await?;
|
2024-04-12 00:34:46 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
None => {
|
|
|
|
break;
|
2024-03-28 22:38:21 +00:00
|
|
|
}
|
2024-04-12 00:34:46 -07:00
|
|
|
},
|
|
|
|
x = self.tx_receiver.recv() => match x {
|
|
|
|
Some((domid, packet)) => {
|
2024-08-13 23:17:47 -07:00
|
|
|
self.tx_packet(domid, packet).await?;
|
2024-04-12 00:34:46 -07:00
|
|
|
},
|
2024-03-28 22:38:21 +00:00
|
|
|
|
2024-04-12 00:34:46 -07:00
|
|
|
None => {
|
|
|
|
break;
|
|
|
|
}
|
2024-03-28 22:38:21 +00:00
|
|
|
}
|
2024-08-13 23:17:47 -07:00
|
|
|
}
|
2024-03-28 07:36:48 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for DaemonIdm {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.task.abort();
|
|
|
|
}
|
|
|
|
}
|
2024-04-12 00:34:46 -07:00
|
|
|
|
|
|
|
async fn client_or_create(
|
|
|
|
domid: u32,
|
2024-04-21 21:00:32 -07:00
|
|
|
tx_sender: &Sender<(u32, IdmTransportPacket)>,
|
2024-04-12 00:34:46 -07:00
|
|
|
clients: &ClientMap,
|
|
|
|
feeds: &BackendFeedMap,
|
2024-04-21 21:00:32 -07:00
|
|
|
) -> Result<IdmInternalClient> {
|
2024-04-12 00:34:46 -07:00
|
|
|
let mut clients = clients.lock().await;
|
|
|
|
let mut feeds = feeds.lock().await;
|
|
|
|
match clients.entry(domid) {
|
|
|
|
Entry::Occupied(entry) => Ok(entry.get().clone()),
|
|
|
|
Entry::Vacant(entry) => {
|
|
|
|
let (rx_sender, rx_receiver) = channel(100);
|
|
|
|
feeds.insert(domid, rx_sender);
|
|
|
|
let backend = IdmDaemonBackend {
|
|
|
|
domid,
|
|
|
|
rx_receiver,
|
|
|
|
tx_sender: tx_sender.clone(),
|
|
|
|
};
|
2024-04-21 21:00:32 -07:00
|
|
|
let client = IdmInternalClient::new(
|
|
|
|
INTERNAL_IDM_CHANNEL,
|
|
|
|
Box::new(backend) as Box<dyn IdmBackend>,
|
|
|
|
)
|
|
|
|
.await?;
|
2024-04-12 00:34:46 -07:00
|
|
|
entry.insert(client.clone());
|
|
|
|
Ok(client)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct IdmDaemonBackend {
|
|
|
|
domid: u32,
|
2024-04-21 21:00:32 -07:00
|
|
|
rx_receiver: Receiver<IdmTransportPacket>,
|
|
|
|
tx_sender: Sender<(u32, IdmTransportPacket)>,
|
2024-04-12 00:34:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
impl IdmBackend for IdmDaemonBackend {
|
2024-08-13 16:18:27 -07:00
|
|
|
async fn recv(&mut self) -> Result<Vec<IdmTransportPacket>> {
|
2024-04-12 00:34:46 -07:00
|
|
|
if let Some(packet) = self.rx_receiver.recv().await {
|
2024-08-13 16:18:27 -07:00
|
|
|
Ok(vec![packet])
|
2024-04-12 00:34:46 -07:00
|
|
|
} else {
|
|
|
|
Err(anyhow!("idm receive channel closed"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-21 21:00:32 -07:00
|
|
|
async fn send(&mut self, packet: IdmTransportPacket) -> Result<()> {
|
2024-04-12 00:34:46 -07:00
|
|
|
self.tx_sender.send((self.domid, packet)).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|