umsh_node/
mac.rs

1use umsh_core::{ChannelId, ChannelKey, PublicKey};
2use umsh_mac::{
3    CapacityError, LocalIdentityId, MacHandle, MacHandleError, PeerId, Platform, SendError,
4    SendOptions, SendReceipt,
5};
6
7/// Pluggable backend that the node layer delegates to for MAC operations.
8///
9/// [`MacHandle`](umsh_mac::MacHandle) implements `MacBackend`, and test code can provide a
10/// lightweight fake.
11pub trait MacBackend: Clone {
12    /// Error type returned by send-oriented operations.
13    type SendError;
14    /// Error type returned by fixed-capacity operations.
15    type CapacityError;
16
17    /// Add or refresh a peer.
18    fn add_peer(
19        &self,
20        key: PublicKey,
21    ) -> Result<PeerId, MacBackendError<Self::SendError, Self::CapacityError>>;
22    /// Add or refresh a private channel.
23    fn add_private_channel(
24        &self,
25        key: ChannelKey,
26    ) -> Result<(), MacBackendError<Self::SendError, Self::CapacityError>>;
27    /// Add or refresh a named channel.
28    fn add_named_channel(
29        &self,
30        name: &str,
31    ) -> Result<(), MacBackendError<Self::SendError, Self::CapacityError>>;
32    /// Queue a broadcast frame.
33    async fn send_broadcast(
34        &self,
35        from: LocalIdentityId,
36        payload: &[u8],
37        options: &SendOptions,
38    ) -> Result<SendReceipt, MacBackendError<Self::SendError, Self::CapacityError>>;
39    /// Queue a multicast frame.
40    async fn send_multicast(
41        &self,
42        from: LocalIdentityId,
43        channel: &ChannelId,
44        payload: &[u8],
45        options: &SendOptions,
46    ) -> Result<SendReceipt, MacBackendError<Self::SendError, Self::CapacityError>>;
47    /// Queue a unicast frame.
48    async fn send_unicast(
49        &self,
50        from: LocalIdentityId,
51        dst: &PublicKey,
52        payload: &[u8],
53        options: &SendOptions,
54    ) -> Result<Option<SendReceipt>, MacBackendError<Self::SendError, Self::CapacityError>>;
55    /// Queue a blind-unicast frame.
56    async fn send_blind_unicast(
57        &self,
58        from: LocalIdentityId,
59        dst: &PublicKey,
60        channel: &ChannelId,
61        payload: &[u8],
62        options: &SendOptions,
63    ) -> Result<Option<SendReceipt>, MacBackendError<Self::SendError, Self::CapacityError>>;
64    /// Fill `dest` with random bytes.
65    fn fill_random(
66        &self,
67        dest: &mut [u8],
68    ) -> Result<(), MacBackendError<Self::SendError, Self::CapacityError>>;
69    /// Return the current MAC clock time.
70    fn now_ms(&self) -> Result<u64, MacBackendError<Self::SendError, Self::CapacityError>>;
71
72    #[cfg(feature = "software-crypto")]
73    fn register_ephemeral(
74        &self,
75        parent: LocalIdentityId,
76        identity: umsh_crypto::software::SoftwareIdentity,
77    ) -> Result<LocalIdentityId, MacBackendError<Self::SendError, Self::CapacityError>>;
78
79    #[cfg(feature = "software-crypto")]
80    fn remove_ephemeral(
81        &self,
82        id: LocalIdentityId,
83    ) -> Result<bool, MacBackendError<Self::SendError, Self::CapacityError>>;
84}
85
86/// Normalized wrapper around MAC-handle failures.
87#[derive(Clone, Debug, PartialEq, Eq)]
88pub enum MacBackendError<S, C> {
89    /// Shared MAC state was temporarily busy.
90    Busy,
91    /// Send-oriented MAC failure.
92    Send(S),
93    /// Capacity-related MAC failure.
94    Capacity(C),
95}
96
97impl<S, C> MacBackendError<S, C> {
98    fn from_send_error(error: MacHandleError<S>) -> Self {
99        match error {
100            MacHandleError::Busy => Self::Busy,
101            MacHandleError::Inner(inner) => Self::Send(inner),
102        }
103    }
104
105    fn from_capacity_error(error: MacHandleError<C>) -> Self {
106        match error {
107            MacHandleError::Busy => Self::Busy,
108            MacHandleError::Inner(inner) => Self::Capacity(inner),
109        }
110    }
111
112    fn from_infallible_error(error: MacHandleError<core::convert::Infallible>) -> Self {
113        match error {
114            MacHandleError::Busy => Self::Busy,
115            MacHandleError::Inner(inner) => match inner {},
116        }
117    }
118}
119
120impl<
121    'a,
122    P: Platform,
123    const IDENTITIES: usize,
124    const PEERS: usize,
125    const CHANNELS: usize,
126    const ACKS: usize,
127    const TX: usize,
128    const FRAME: usize,
129    const DUP: usize,
130> MacBackend for MacHandle<'a, P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>
131{
132    type SendError = SendError;
133    type CapacityError = CapacityError;
134
135    fn add_peer(
136        &self,
137        key: PublicKey,
138    ) -> Result<PeerId, MacBackendError<Self::SendError, Self::CapacityError>> {
139        self.add_peer(key)
140            .map_err(MacBackendError::from_capacity_error)
141    }
142
143    fn add_private_channel(
144        &self,
145        key: ChannelKey,
146    ) -> Result<(), MacBackendError<Self::SendError, Self::CapacityError>> {
147        self.add_channel(key)
148            .map_err(MacBackendError::from_capacity_error)
149    }
150
151    fn add_named_channel(
152        &self,
153        name: &str,
154    ) -> Result<(), MacBackendError<Self::SendError, Self::CapacityError>> {
155        self.add_named_channel(name)
156            .map_err(MacBackendError::from_capacity_error)
157    }
158
159    async fn send_broadcast(
160        &self,
161        from: LocalIdentityId,
162        payload: &[u8],
163        options: &SendOptions,
164    ) -> Result<SendReceipt, MacBackendError<Self::SendError, Self::CapacityError>> {
165        self.send_broadcast(from, payload, options)
166            .await
167            .map_err(MacBackendError::from_send_error)
168    }
169
170    async fn send_multicast(
171        &self,
172        from: LocalIdentityId,
173        channel: &ChannelId,
174        payload: &[u8],
175        options: &SendOptions,
176    ) -> Result<SendReceipt, MacBackendError<Self::SendError, Self::CapacityError>> {
177        self.send_multicast(from, channel, payload, options)
178            .await
179            .map_err(MacBackendError::from_send_error)
180    }
181
182    async fn send_unicast(
183        &self,
184        from: LocalIdentityId,
185        dst: &PublicKey,
186        payload: &[u8],
187        options: &SendOptions,
188    ) -> Result<Option<SendReceipt>, MacBackendError<Self::SendError, Self::CapacityError>> {
189        self.send_unicast(from, dst, payload, options)
190            .await
191            .map_err(MacBackendError::from_send_error)
192    }
193
194    async fn send_blind_unicast(
195        &self,
196        from: LocalIdentityId,
197        dst: &PublicKey,
198        channel: &ChannelId,
199        payload: &[u8],
200        options: &SendOptions,
201    ) -> Result<Option<SendReceipt>, MacBackendError<Self::SendError, Self::CapacityError>> {
202        self.send_blind_unicast(from, dst, channel, payload, options)
203            .await
204            .map_err(MacBackendError::from_send_error)
205    }
206
207    fn fill_random(
208        &self,
209        dest: &mut [u8],
210    ) -> Result<(), MacBackendError<Self::SendError, Self::CapacityError>> {
211        self.fill_random(dest)
212            .map_err(MacBackendError::from_infallible_error)
213    }
214
215    fn now_ms(&self) -> Result<u64, MacBackendError<Self::SendError, Self::CapacityError>> {
216        self.now_ms()
217            .map_err(MacBackendError::from_infallible_error)
218    }
219
220    #[cfg(feature = "software-crypto")]
221    fn register_ephemeral(
222        &self,
223        parent: LocalIdentityId,
224        identity: umsh_crypto::software::SoftwareIdentity,
225    ) -> Result<LocalIdentityId, MacBackendError<Self::SendError, Self::CapacityError>> {
226        self.register_ephemeral(parent, identity)
227            .map_err(MacBackendError::from_capacity_error)
228    }
229
230    #[cfg(feature = "software-crypto")]
231    fn remove_ephemeral(
232        &self,
233        id: LocalIdentityId,
234    ) -> Result<bool, MacBackendError<Self::SendError, Self::CapacityError>> {
235        self.remove_ephemeral(id)
236            .map_err(MacBackendError::from_infallible_error)
237    }
238}