ergot_base/interface_manager/
mod.rs

1//! The Interface Manager
2//!
3//! The [`NetStack`] is generic over a "Profile", which is how it handles
4//! any external interfaces of the current program or device.
5//!
6//! Different profiles may support a various number of external
7//! interfaces. The simplest profile is the "Null Profile",
8//! Which supports no external interfaces, meaning that messages may only be
9//! routed locally.
10//!
11//! The next simplest profile is one that only supports zero or one
12//! active interfaces, for example if a device is directly connected to a PC
13//! using USB. In this case, routing is again simple: if messages are not
14//! intended for the local device, they should be routed out of the one external
15//! interface. Similarly, if we support an interface, but it is not connected
16//! (e.g. the USB cable is unplugged), all packets with external destinations
17//! will fail to send.
18//!
19//! For more complex devices, a profile with multiple (bounded or
20//! unbounded) interfaces, and more complex routing capabilities, may be
21//! selected.
22//!
23//! Unlike Sockets, which might be various and diverse on all systems, a system
24//! is expected to have one statically-known profile, which may
25//! manage various and diverse interfaces.
26//!
27//! In general when sending a message, the [`NetStack`] will check if the
28//! message is definitively for the local device (e.g. Net ID = 0, Node ID = 0),
29//! and if not the NetStack will pass the message to the Interface Manager. If
30//! the profile can route this packet, it informs the NetStack it has
31//! done so. If the Interface Manager realizes that the packet is still for us
32//! (e.g. matching a Net ID and Node ID of the local device), it may bounce the
33//! message back to the NetStack to locally route.
34//!
35//! [`NetStack`]: crate::NetStack
36
37use crate::{AnyAllAppendix, Header, ProtocolError, wire_frames::CommonHeader};
38use serde::Serialize;
39
40pub mod interface_impls;
41pub mod profiles;
42pub mod utils;
43
44pub trait ConstInit {
45    const INIT: Self;
46}
47
48// An interface send is very similar to a socket send, with the exception
49// that interface sends are ALWAYS a serializing operation (or required
50// serialization has already been done), which means we don't need to
51// differentiate between "send owned" and "send borrowed". The exception
52// to this is "send raw", where serialization has already been done, e.g.
53// if we are routing a packet.
54pub trait Profile {
55    /// The kind of type that is used to identify a single interface.
56    /// If a Profile only supports a single interface, this is often the `()` type.
57    /// If a Profile supports many interfaces, this could be an enum or integer type.
58    type InterfaceIdent;
59
60    fn send<T: Serialize>(&mut self, hdr: &Header, data: &T) -> Result<(), InterfaceSendError>;
61    fn send_err(&mut self, hdr: &Header, err: ProtocolError) -> Result<(), InterfaceSendError>;
62    fn send_raw(
63        &mut self,
64        hdr: &Header,
65        hdr_raw: &[u8],
66        data: &[u8],
67    ) -> Result<(), InterfaceSendError>;
68
69    fn interface_state(&mut self, ident: Self::InterfaceIdent) -> Option<InterfaceState>;
70    fn set_interface_state(
71        &mut self,
72        ident: Self::InterfaceIdent,
73        state: InterfaceState,
74    ) -> Result<(), SetStateError>;
75}
76
77/// Interfaces define how messages are transported over the wire
78pub trait Interface {
79    /// The Sink is the type used to send messages out of the Profile
80    type Sink: InterfaceSink;
81}
82
83/// The "Sink" side of the interface.
84///
85/// This is typically held by a profile, and feeds data to the interface's
86/// TX worker.
87#[allow(clippy::result_unit_err)]
88pub trait InterfaceSink {
89    fn send_ty<T: Serialize>(
90        &mut self,
91        hdr: &CommonHeader,
92        apdx: Option<&AnyAllAppendix>,
93        body: &T,
94    ) -> Result<(), ()>;
95    fn send_raw(&mut self, hdr: &CommonHeader, hdr_raw: &[u8], body: &[u8]) -> Result<(), ()>;
96    fn send_err(&mut self, hdr: &CommonHeader, err: ProtocolError) -> Result<(), ()>;
97}
98
99#[derive(Debug, PartialEq, Eq)]
100#[non_exhaustive]
101pub enum InterfaceSendError {
102    /// Refusing to send local destination remotely
103    DestinationLocal,
104    /// Profile does not know how to route to requested destination
105    NoRouteToDest,
106    /// Profile found a destination interface, but that interface
107    /// was full in space/slots
108    InterfaceFull,
109    /// TODO: Remove
110    PlaceholderOhNo,
111    /// Destination was an "any" port, but a key was not provided
112    AnyPortMissingKey,
113    /// TTL has reached the terminal value
114    TtlExpired,
115}
116
117/// An error when deregistering an interface
118#[derive(Debug, PartialEq, Eq)]
119#[non_exhaustive]
120pub enum DeregisterError {
121    NoSuchInterface,
122}
123
124#[derive(Clone, Copy, Debug, PartialEq)]
125pub enum InterfaceState {
126    // Missing sink, no net id
127    Down,
128    // Has sink, no net id
129    Inactive,
130    // Has sink, has node_id but not net_id
131    ActiveLocal { node_id: u8 },
132    // Has sink, has net id
133    Active { net_id: u16, node_id: u8 },
134}
135
136#[derive(Clone, Copy, Debug, PartialEq)]
137#[non_exhaustive]
138pub enum RegisterSinkError {
139    AlreadyActive,
140}
141
142#[derive(Clone, Copy, Debug, PartialEq)]
143#[non_exhaustive]
144pub enum SetStateError {
145    InterfaceNotFound,
146    InvalidNodeId,
147}
148
149impl InterfaceSendError {
150    pub fn to_error(&self) -> ProtocolError {
151        match self {
152            InterfaceSendError::DestinationLocal => ProtocolError::ISE_DESTINATION_LOCAL,
153            InterfaceSendError::NoRouteToDest => ProtocolError::ISE_NO_ROUTE_TO_DEST,
154            InterfaceSendError::InterfaceFull => ProtocolError::ISE_INTERFACE_FULL,
155            InterfaceSendError::PlaceholderOhNo => ProtocolError::ISE_PLACEHOLDER_OH_NO,
156            InterfaceSendError::AnyPortMissingKey => ProtocolError::ISE_ANY_PORT_MISSING_KEY,
157            InterfaceSendError::TtlExpired => ProtocolError::ISE_TTL_EXPIRED,
158        }
159    }
160}