2026-04-24 14:25:35 -06:00
|
|
|
//! Packet ingress and local call dispatch.
|
|
|
|
|
|
2026-04-25 12:37:54 -06:00
|
|
|
use crate::protocol::types::{ArchivedCallMessage, ArchivedDataMessage, ArchivedFaultMessage};
|
2026-04-24 14:25:35 -06:00
|
|
|
use crate::protocol::{
|
2026-04-25 12:15:38 -06:00
|
|
|
CallMessage, PacketType, ProtocolFault, decode_frame, deserialize_archived_bytes,
|
|
|
|
|
introspection::INTROSPECTION_PROCEDURE_ID, validate_call, validate_header,
|
2026-04-24 14:25:35 -06:00
|
|
|
};
|
|
|
|
|
|
2026-04-25 12:15:38 -06:00
|
|
|
use super::super::{HookKey, PendingHook, RouteDecision};
|
2026-04-24 14:27:55 -06:00
|
|
|
use super::core::{
|
|
|
|
|
Endpoint, EndpointError, EndpointOutcome, Ingress, LocalEvent, ProtocolEndpoint,
|
|
|
|
|
};
|
2026-04-24 14:25:35 -06:00
|
|
|
|
|
|
|
|
impl ProtocolEndpoint {
|
|
|
|
|
pub(crate) fn handle_local_call(
|
|
|
|
|
&mut self,
|
|
|
|
|
header: crate::protocol::PacketHeader,
|
|
|
|
|
message: CallMessage,
|
|
|
|
|
) -> Result<EndpointOutcome, EndpointError> {
|
|
|
|
|
let key = message
|
|
|
|
|
.response_hook
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|hook| HookKey::new(hook.return_path.clone(), hook.hook_id));
|
|
|
|
|
|
2026-04-25 12:37:54 -06:00
|
|
|
if let Some(hook) = &message.response_hook
|
|
|
|
|
&& hook.return_path != self.path
|
|
|
|
|
&& self
|
|
|
|
|
.hooks
|
|
|
|
|
.insert_pending(PendingHook {
|
|
|
|
|
return_path: hook.return_path.clone(),
|
|
|
|
|
hook_id: hook.hook_id,
|
|
|
|
|
caller_src_path: header.src_path.clone(),
|
|
|
|
|
procedure_id: message.procedure_id.clone(),
|
|
|
|
|
dst_leaf: header.dst_leaf.clone(),
|
|
|
|
|
})
|
|
|
|
|
.is_err()
|
|
|
|
|
{
|
|
|
|
|
return self.emit_fault_if_possible(key, ProtocolFault::INTERNAL_ERROR);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 14:25:35 -06:00
|
|
|
if message.procedure_id == INTROSPECTION_PROCEDURE_ID {
|
2026-04-25 12:37:54 -06:00
|
|
|
if let Some(key) = &key {
|
|
|
|
|
self.hooks.activate_pending(key);
|
|
|
|
|
}
|
2026-04-24 14:25:35 -06:00
|
|
|
return self.handle_introspection(&header, key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let supported = match &header.dst_leaf {
|
|
|
|
|
Some(leaf_name) => self
|
|
|
|
|
.leaves
|
|
|
|
|
.get(leaf_name)
|
2026-04-25 12:41:10 -06:00
|
|
|
.map(|leaf| {
|
|
|
|
|
leaf.procedures
|
|
|
|
|
.iter()
|
|
|
|
|
.any(|procedure| procedure == &message.procedure_id)
|
|
|
|
|
})
|
2026-04-24 14:25:35 -06:00
|
|
|
.unwrap_or(false),
|
|
|
|
|
None => self.endpoint_procedures.contains(&message.procedure_id),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if !supported {
|
|
|
|
|
let fault = if header
|
|
|
|
|
.dst_leaf
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|name| !self.leaves.contains_key(name))
|
|
|
|
|
{
|
|
|
|
|
ProtocolFault::UNKNOWN_LEAF
|
|
|
|
|
} else {
|
|
|
|
|
ProtocolFault::UNKNOWN_PROCEDURE
|
|
|
|
|
};
|
|
|
|
|
return self.emit_fault_if_possible(key, fault);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-25 12:37:54 -06:00
|
|
|
if let Some(key) = &key
|
|
|
|
|
&& self.hooks.activate_pending(key).is_none()
|
2026-04-25 12:15:38 -06:00
|
|
|
{
|
2026-04-25 12:37:54 -06:00
|
|
|
return self.emit_fault_if_possible(Some(key.clone()), ProtocolFault::INTERNAL_ERROR);
|
2026-04-24 14:25:35 -06:00
|
|
|
}
|
|
|
|
|
|
2026-04-25 11:46:45 -06:00
|
|
|
Ok(EndpointOutcome::event(LocalEvent::Call { header, message }))
|
2026-04-24 14:25:35 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Endpoint for ProtocolEndpoint {
|
|
|
|
|
fn path(&self) -> &[alloc::string::String] {
|
|
|
|
|
&self.path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn receive(
|
|
|
|
|
&mut self,
|
|
|
|
|
ingress: &Ingress,
|
|
|
|
|
frame: crate::protocol::FrameBytes,
|
|
|
|
|
) -> Result<EndpointOutcome, EndpointError> {
|
|
|
|
|
let parsed = decode_frame(&frame)?;
|
|
|
|
|
let header = parsed.header();
|
|
|
|
|
validate_header(header)?;
|
|
|
|
|
|
|
|
|
|
if !self.valid_source_for_ingress(ingress, &header.src_path) {
|
2026-04-25 11:46:45 -06:00
|
|
|
return Ok(EndpointOutcome::dropped());
|
2026-04-24 14:25:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match header.packet_type {
|
|
|
|
|
PacketType::Call => {
|
|
|
|
|
if !matches!(ingress, Ingress::Parent | Ingress::Local) {
|
2026-04-25 11:46:45 -06:00
|
|
|
return Ok(EndpointOutcome::dropped());
|
2026-04-24 14:25:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match self.decide_route(&header.dst_path) {
|
2026-04-25 11:46:45 -06:00
|
|
|
RouteDecision::Child(index) => {
|
|
|
|
|
Ok(EndpointOutcome::forward(RouteDecision::Child(index), frame))
|
|
|
|
|
}
|
2026-04-25 12:41:10 -06:00
|
|
|
RouteDecision::Parent => {
|
|
|
|
|
Ok(EndpointOutcome::forward(RouteDecision::Parent, frame))
|
|
|
|
|
}
|
2026-04-25 11:46:45 -06:00
|
|
|
RouteDecision::Drop => Ok(EndpointOutcome::dropped()),
|
2026-04-25 12:15:38 -06:00
|
|
|
RouteDecision::Local => {
|
|
|
|
|
let (header, payload) = parsed.into_parts();
|
2026-04-25 12:41:10 -06:00
|
|
|
let message = deserialize_archived_bytes::<ArchivedCallMessage, CallMessage>(
|
|
|
|
|
payload,
|
|
|
|
|
)?;
|
2026-04-25 12:15:38 -06:00
|
|
|
validate_call(&header, &message)?;
|
|
|
|
|
self.handle_local_call(header, message)
|
|
|
|
|
}
|
2026-04-24 14:25:35 -06:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-25 12:37:54 -06:00
|
|
|
PacketType::Data => match self.decide_route(&header.dst_path) {
|
|
|
|
|
RouteDecision::Local => {
|
|
|
|
|
let (header, payload) = parsed.into_parts();
|
|
|
|
|
let message = deserialize_archived_bytes::<
|
|
|
|
|
ArchivedDataMessage,
|
|
|
|
|
crate::protocol::DataMessage,
|
|
|
|
|
>(payload)?;
|
|
|
|
|
self.handle_local_data(header, message)
|
2026-04-24 14:25:35 -06:00
|
|
|
}
|
2026-04-25 12:37:54 -06:00
|
|
|
RouteDecision::Child(index) => {
|
|
|
|
|
Ok(EndpointOutcome::forward(RouteDecision::Child(index), frame))
|
2026-04-24 14:25:35 -06:00
|
|
|
}
|
2026-04-25 12:37:54 -06:00
|
|
|
RouteDecision::Parent => Ok(EndpointOutcome::forward(RouteDecision::Parent, frame)),
|
|
|
|
|
RouteDecision::Drop => Ok(EndpointOutcome::dropped()),
|
|
|
|
|
},
|
|
|
|
|
PacketType::Fault => match self.decide_route(&header.dst_path) {
|
|
|
|
|
RouteDecision::Local => {
|
|
|
|
|
let (header, payload) = parsed.into_parts();
|
|
|
|
|
let message = deserialize_archived_bytes::<
|
|
|
|
|
ArchivedFaultMessage,
|
|
|
|
|
crate::protocol::FaultMessage,
|
|
|
|
|
>(payload)?;
|
|
|
|
|
self.handle_local_fault(header, message)
|
|
|
|
|
}
|
|
|
|
|
RouteDecision::Child(index) => {
|
|
|
|
|
Ok(EndpointOutcome::forward(RouteDecision::Child(index), frame))
|
|
|
|
|
}
|
|
|
|
|
RouteDecision::Parent => Ok(EndpointOutcome::forward(RouteDecision::Parent, frame)),
|
|
|
|
|
RouteDecision::Drop => Ok(EndpointOutcome::dropped()),
|
|
|
|
|
},
|
2026-04-24 14:25:35 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|