1use alloc::boxed::Box;
2use alloc::rc::Rc;
3use alloc::vec::Vec;
4use core::cell::RefCell;
5use core::num::NonZeroU32;
6
7use umsh_core::{NodeHint, PublicKey, RouterHint};
8use umsh_mac::{CachedRoute, LocalIdentityId, SendOptions};
9
10#[cfg(feature = "software-crypto")]
11use crate::channel::Channel;
12use crate::dispatch::EventDispatcher;
13use crate::identity_responder::{
14 IdentityRequestContext, IdentityResponder, IdentityResponsePlan, NodeIdentityProfile,
15 RespondDecision, default_respond_policy,
16};
17use crate::mac::MacBackend;
18use crate::peer::PeerConnection;
19#[cfg(feature = "software-crypto")]
20use crate::pfs::{PfsSessionManager, PfsState};
21use crate::receive::ReceivedPacketRef;
22use crate::ticket::{SendProgressTicket, SendToken};
23use crate::transport::Transport;
24use crate::{AppEncodeError, OwnedMacCommand};
25
26pub(crate) struct NodeMembership {
29 #[cfg(feature = "software-crypto")]
30 pub channels: Vec<ChannelMembershipEntry>,
31}
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
34pub(crate) struct SubscriptionHandle(NonZeroU32);
35
36pub struct Subscription {
40 cancel: Rc<RefCell<Option<Box<dyn FnMut() -> bool>>>>,
41}
42
43impl Subscription {
44 pub(crate) fn new(cancel: impl FnMut() -> bool + 'static) -> Self {
45 Self {
46 cancel: Rc::new(RefCell::new(Some(Box::new(cancel)))),
47 }
48 }
49
50 pub fn unsubscribe(self) -> bool {
52 Self::run_cancel(&self.cancel)
53 }
54
55 fn run_cancel(cancel: &Rc<RefCell<Option<Box<dyn FnMut() -> bool>>>>) -> bool {
56 let Some(mut cancel) = cancel.borrow_mut().take() else {
57 return false;
58 };
59 cancel()
60 }
61}
62
63impl Drop for Subscription {
64 fn drop(&mut self) {
65 let _ = Self::run_cancel(&self.cancel);
66 }
67}
68
69pub(crate) struct HandlerTable<T> {
70 slots: Vec<Option<T>>,
71}
72
73impl<T> Default for HandlerTable<T> {
74 fn default() -> Self {
75 Self { slots: Vec::new() }
76 }
77}
78
79impl<T> HandlerTable<T> {
80 pub(crate) fn insert(&mut self, handler: T) -> SubscriptionHandle {
81 if let Some((index, slot)) = self
82 .slots
83 .iter_mut()
84 .enumerate()
85 .find(|(_, slot)| slot.is_none())
86 {
87 *slot = Some(handler);
88 return SubscriptionHandle(NonZeroU32::new((index + 1) as u32).unwrap());
89 }
90 self.slots.push(Some(handler));
91 SubscriptionHandle(NonZeroU32::new(self.slots.len() as u32).unwrap())
92 }
93
94 pub(crate) fn remove(&mut self, handle: SubscriptionHandle) -> bool {
95 let index = handle.0.get() as usize - 1;
96 let Some(slot) = self.slots.get_mut(index) else {
97 return false;
98 };
99 slot.take().is_some()
100 }
101
102 fn any_mut(&mut self, mut f: impl FnMut(&mut T) -> bool) -> bool {
103 for slot in &mut self.slots {
104 let Some(handler) = slot.as_mut() else {
105 continue;
106 };
107 if f(handler) {
108 return true;
109 }
110 }
111 false
112 }
113
114 fn for_each_mut(&mut self, mut f: impl FnMut(&mut T)) {
115 for slot in &mut self.slots {
116 let Some(handler) = slot.as_mut() else {
117 continue;
118 };
119 f(handler);
120 }
121 }
122}
123
124pub(crate) struct PendingPing {
125 pub nonce: u16,
126 pub peer: PublicKey,
127 pub sent_at_ms: u64,
128 pub deadline_ms: u64,
129}
130
131#[derive(Clone, Debug, PartialEq, Eq)]
137pub struct PongMetadata {
138 pub round_trip_ms: u64,
139 pub hop_count: Option<u8>,
140 pub route_hints: Vec<RouterHint>,
141 pub rssi_dbm: Option<i16>,
142 pub snr_centibels: Option<i16>,
143 pub lqi: Option<u8>,
144}
145
146pub(crate) struct PeerSubscriptions {
147 peer: PublicKey,
148 pub(crate) receive_handlers: HandlerTable<Box<dyn FnMut(&ReceivedPacketRef<'_>) -> bool>>,
149 pub(crate) ack_received_handlers: HandlerTable<Box<dyn FnMut(SendToken)>>,
150 pub(crate) ack_timeout_handlers: HandlerTable<Box<dyn FnMut(SendToken)>>,
151 pub(crate) pfs_established_handlers: HandlerTable<Box<dyn FnMut()>>,
152 pub(crate) pfs_ended_handlers: HandlerTable<Box<dyn FnMut()>>,
153 pub(crate) pong_handlers: HandlerTable<Box<dyn FnMut(u64)>>,
154 pub(crate) ping_timeout_handlers: HandlerTable<Box<dyn FnMut()>>,
155}
156
157impl PeerSubscriptions {
158 fn new(peer: PublicKey) -> Self {
159 Self {
160 peer,
161 receive_handlers: HandlerTable::default(),
162 ack_received_handlers: HandlerTable::default(),
163 ack_timeout_handlers: HandlerTable::default(),
164 pfs_established_handlers: HandlerTable::default(),
165 pfs_ended_handlers: HandlerTable::default(),
166 pong_handlers: HandlerTable::default(),
167 ping_timeout_handlers: HandlerTable::default(),
168 }
169 }
170}
171
172pub(crate) struct LocalNodeState {
173 receive_handlers: HandlerTable<Box<dyn FnMut(&ReceivedPacketRef<'_>) -> bool>>,
174 node_discovered_handlers: HandlerTable<Box<dyn FnMut(PublicKey, Option<&str>)>>,
175 beacon_handlers: HandlerTable<Box<dyn FnMut(NodeHint, Option<PublicKey>)>>,
176 mac_command_handlers: HandlerTable<Box<dyn FnMut(PublicKey, &OwnedMacCommand)>>,
177 transmitted_handlers: HandlerTable<Box<dyn FnMut(&[u8])>>,
178 ack_received_handlers: HandlerTable<Box<dyn FnMut(PublicKey, SendToken)>>,
179 ack_timeout_handlers: HandlerTable<Box<dyn FnMut(PublicKey, SendToken)>>,
180 pfs_established_handlers: HandlerTable<Box<dyn FnMut(PublicKey)>>,
181 pfs_ended_handlers: HandlerTable<Box<dyn FnMut(PublicKey)>>,
182 pfs_failed_handlers: HandlerTable<Box<dyn FnMut(PublicKey, PfsFailure)>>,
183 pong_handlers: HandlerTable<Box<dyn FnMut(PublicKey, u64)>>,
184 pong_metadata_handlers: HandlerTable<Box<dyn FnMut(PublicKey, &PongMetadata)>>,
185 ping_timeout_handlers: HandlerTable<Box<dyn FnMut(PublicKey)>>,
186 pending_pings: Vec<PendingPing>,
187 peer_subscriptions: Vec<PeerSubscriptions>,
188 identity_responder: Option<IdentityResponder>,
189 #[cfg(feature = "software-crypto")]
190 pfs: PfsSessionManager,
191}
192
193impl LocalNodeState {
194 pub(crate) fn new() -> Self {
195 Self {
196 receive_handlers: HandlerTable::default(),
197 node_discovered_handlers: HandlerTable::default(),
198 beacon_handlers: HandlerTable::default(),
199 mac_command_handlers: HandlerTable::default(),
200 transmitted_handlers: HandlerTable::default(),
201 ack_received_handlers: HandlerTable::default(),
202 ack_timeout_handlers: HandlerTable::default(),
203 pfs_established_handlers: HandlerTable::default(),
204 pfs_ended_handlers: HandlerTable::default(),
205 pfs_failed_handlers: HandlerTable::default(),
206 pong_handlers: HandlerTable::default(),
207 pong_metadata_handlers: HandlerTable::default(),
208 ping_timeout_handlers: HandlerTable::default(),
209 pending_pings: Vec::new(),
210 peer_subscriptions: Vec::new(),
211 identity_responder: None,
212 #[cfg(feature = "software-crypto")]
213 pfs: PfsSessionManager::new(),
214 }
215 }
216
217 pub(crate) fn peer_subscriptions_mut(&mut self, peer: PublicKey) -> &mut PeerSubscriptions {
218 if let Some(index) = self
219 .peer_subscriptions
220 .iter()
221 .position(|entry| entry.peer == peer)
222 {
223 return &mut self.peer_subscriptions[index];
224 }
225 self.peer_subscriptions.push(PeerSubscriptions::new(peer));
226 self.peer_subscriptions
227 .last_mut()
228 .expect("peer subscriptions just inserted")
229 }
230
231 pub(crate) fn find_peer_subscriptions_mut(
232 &mut self,
233 peer: PublicKey,
234 ) -> Option<&mut PeerSubscriptions> {
235 self.peer_subscriptions
236 .iter_mut()
237 .find(|entry| entry.peer == peer)
238 }
239}
240
241#[derive(Clone, Copy, Debug, PartialEq, Eq)]
242#[cfg(feature = "software-crypto")]
243pub enum PfsStatus {
244 Inactive,
245 Requested,
246 Active {
247 local_ephemeral_id: LocalIdentityId,
248 peer_ephemeral: PublicKey,
249 expires_ms: u64,
250 },
251}
252
253#[derive(Clone, Copy, Debug, PartialEq, Eq)]
254pub(crate) enum PfsLifecycle {
255 Established(PublicKey),
256 Ended(PublicKey),
257}
258
259#[derive(Clone, Copy, Debug, PartialEq, Eq)]
263pub enum PfsFailure {
264 Capacity,
268 SessionMissing,
270 Crypto,
272 Send,
274 Timeout,
277 Other,
279}
280
281#[cfg(feature = "software-crypto")]
282pub(crate) struct ChannelMembershipEntry {
283 pub channel: Channel,
284 pub generation: u64,
287 pub active: bool,
289}
290
291impl NodeMembership {
292 pub fn new() -> Self {
293 Self {
294 #[cfg(feature = "software-crypto")]
295 channels: Vec::new(),
296 }
297 }
298}
299
300#[derive(Clone, PartialEq, Eq)]
302pub enum NodeError<M: MacBackend> {
303 Mac(crate::mac::MacBackendError<M::SendError, M::CapacityError>),
305 ChannelLeft,
307 PeerMissing,
309 AppEncode(AppEncodeError),
311 #[cfg(feature = "software-crypto")]
313 PfsSessionMissing,
314 #[cfg(feature = "software-crypto")]
316 PfsSessionTableFull,
317 #[cfg(feature = "software-crypto")]
319 Crypto(umsh_crypto::CryptoError),
320}
321
322impl<M: MacBackend> NodeError<M> {
323 pub(crate) fn pfs_failure(&self) -> PfsFailure {
327 use crate::mac::MacBackendError;
328 match self {
329 NodeError::Mac(MacBackendError::Capacity(_)) => PfsFailure::Capacity,
330 NodeError::Mac(MacBackendError::Send(_)) => PfsFailure::Send,
331 #[cfg(feature = "software-crypto")]
332 NodeError::PfsSessionTableFull => PfsFailure::Capacity,
333 #[cfg(feature = "software-crypto")]
334 NodeError::PfsSessionMissing => PfsFailure::SessionMissing,
335 #[cfg(feature = "software-crypto")]
336 NodeError::Crypto(_) => PfsFailure::Crypto,
337 _ => PfsFailure::Other,
338 }
339 }
340}
341
342impl<M> core::fmt::Debug for NodeError<M>
343where
344 M: MacBackend,
345 M::SendError: core::fmt::Debug,
346 M::CapacityError: core::fmt::Debug,
347{
348 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
349 match self {
350 Self::Mac(e) => f.debug_tuple("Mac").field(e).finish(),
351 Self::ChannelLeft => f.write_str("ChannelLeft"),
352 Self::PeerMissing => f.write_str("PeerMissing"),
353 Self::AppEncode(e) => f.debug_tuple("AppEncode").field(e).finish(),
354 #[cfg(feature = "software-crypto")]
355 Self::PfsSessionMissing => f.write_str("PfsSessionMissing"),
356 #[cfg(feature = "software-crypto")]
357 Self::PfsSessionTableFull => f.write_str("PfsSessionTableFull"),
358 #[cfg(feature = "software-crypto")]
359 Self::Crypto(e) => f.debug_tuple("Crypto").field(e).finish(),
360 }
361 }
362}
363
364impl<M: MacBackend> From<crate::mac::MacBackendError<M::SendError, M::CapacityError>>
365 for NodeError<M>
366{
367 fn from(e: crate::mac::MacBackendError<M::SendError, M::CapacityError>) -> Self {
368 Self::Mac(e)
369 }
370}
371
372impl<M: MacBackend> From<AppEncodeError> for NodeError<M> {
373 fn from(e: AppEncodeError) -> Self {
374 Self::AppEncode(e)
375 }
376}
377
378#[cfg(feature = "software-crypto")]
379impl<M: MacBackend> From<umsh_crypto::CryptoError> for NodeError<M> {
380 fn from(e: umsh_crypto::CryptoError) -> Self {
381 Self::Crypto(e)
382 }
383}
384
385#[derive(Clone)]
391pub struct LocalNode<M: MacBackend> {
392 identity_id: LocalIdentityId,
393 mac: M,
394 dispatcher: Rc<RefCell<EventDispatcher>>,
395 #[allow(dead_code)] membership: Rc<RefCell<NodeMembership>>,
397 state: Rc<RefCell<LocalNodeState>>,
398}
399
400impl<M: MacBackend> LocalNode<M> {
401 pub(crate) fn new(
403 identity_id: LocalIdentityId,
404 mac: M,
405 dispatcher: Rc<RefCell<EventDispatcher>>,
406 membership: Rc<RefCell<NodeMembership>>,
407 state: Rc<RefCell<LocalNodeState>>,
408 ) -> Self {
409 Self {
410 identity_id,
411 mac,
412 dispatcher,
413 membership,
414 state,
415 }
416 }
417
418 pub fn identity_id(&self) -> LocalIdentityId {
420 self.identity_id
421 }
422
423 pub async fn peer(&self, key: PublicKey) -> Result<PeerConnection<Self>, NodeError<M>> {
425 self.mac.add_peer(key).await?;
426 Ok(PeerConnection::new(self.clone(), key))
427 }
428
429 pub async fn remove_peer(&self, key: &PublicKey) -> bool {
434 let removed = self.mac.remove_peer(key).await;
435 let mut state = self.state.borrow_mut();
436 state.pending_pings.retain(|ping| ping.peer != *key);
437 state.peer_subscriptions.retain(|entry| entry.peer != *key);
438 removed
439 }
440
441 pub async fn frame_counter(&self) -> Option<u32> {
443 self.mac.frame_counter(self.identity_id).await
444 }
445
446 pub async fn persisted_frame_counter(&self) -> Option<u32> {
448 self.mac.persisted_frame_counter(self.identity_id).await
449 }
450
451 pub async fn for_each_peer(&self, f: &mut dyn FnMut(PublicKey)) {
455 self.mac.for_each_peer(f).await
456 }
457
458 pub async fn for_each_peer_counter(&self, f: &mut dyn FnMut(PublicKey, u32, u32)) {
461 self.mac.for_each_peer_counter(self.identity_id, f).await
462 }
463
464 pub async fn peer_route(&self, peer: &PublicKey) -> Option<CachedRoute> {
469 self.mac.peer_route(peer).await
470 }
471
472 pub async fn clear_peer_route(&self, peer: &PublicKey) -> bool {
477 self.mac.clear_peer_route(peer).await
478 }
479
480 fn add_receive_handler<F>(&self, handler: F) -> SubscriptionHandle
481 where
482 F: FnMut(&ReceivedPacketRef<'_>) -> bool + 'static,
483 {
484 self.state
485 .borrow_mut()
486 .receive_handlers
487 .insert(Box::new(handler))
488 }
489
490 pub fn on_receive<F>(&self, handler: F) -> Subscription
491 where
492 F: FnMut(&ReceivedPacketRef<'_>) -> bool + 'static,
493 {
494 let handle = self.add_receive_handler(handler);
495 let state = self.state.clone();
496 Subscription::new(move || state.borrow_mut().receive_handlers.remove(handle))
497 }
498
499 fn add_node_discovered_handler<F>(&self, handler: F) -> SubscriptionHandle
500 where
501 F: FnMut(PublicKey, Option<&str>) + 'static,
502 {
503 self.state
504 .borrow_mut()
505 .node_discovered_handlers
506 .insert(Box::new(handler))
507 }
508
509 pub fn on_node_discovered<F>(&self, handler: F) -> Subscription
510 where
511 F: FnMut(PublicKey, Option<&str>) + 'static,
512 {
513 let handle = self.add_node_discovered_handler(handler);
514 let state = self.state.clone();
515 Subscription::new(move || state.borrow_mut().node_discovered_handlers.remove(handle))
516 }
517
518 fn add_beacon_handler<F>(&self, handler: F) -> SubscriptionHandle
519 where
520 F: FnMut(NodeHint, Option<PublicKey>) + 'static,
521 {
522 self.state
523 .borrow_mut()
524 .beacon_handlers
525 .insert(Box::new(handler))
526 }
527
528 pub fn on_beacon<F>(&self, handler: F) -> Subscription
529 where
530 F: FnMut(NodeHint, Option<PublicKey>) + 'static,
531 {
532 let handle = self.add_beacon_handler(handler);
533 let state = self.state.clone();
534 Subscription::new(move || state.borrow_mut().beacon_handlers.remove(handle))
535 }
536
537 fn add_mac_command_handler<F>(&self, handler: F) -> SubscriptionHandle
538 where
539 F: FnMut(PublicKey, &OwnedMacCommand) + 'static,
540 {
541 self.state
542 .borrow_mut()
543 .mac_command_handlers
544 .insert(Box::new(handler))
545 }
546
547 pub fn on_mac_command<F>(&self, handler: F) -> Subscription
548 where
549 F: FnMut(PublicKey, &OwnedMacCommand) + 'static,
550 {
551 let handle = self.add_mac_command_handler(handler);
552 let state = self.state.clone();
553 Subscription::new(move || state.borrow_mut().mac_command_handlers.remove(handle))
554 }
555
556 pub fn enable_identity_responder<P>(&self, profile: NodeIdentityProfile, policy: P)
566 where
567 P: FnMut(&IdentityRequestContext<'_>) -> RespondDecision + 'static,
568 {
569 self.state.borrow_mut().identity_responder = Some(IdentityResponder {
570 profile,
571 policy: Box::new(policy),
572 });
573 }
574
575 pub fn enable_identity_responder_default(&self, profile: NodeIdentityProfile) {
578 self.enable_identity_responder(profile, default_respond_policy);
579 }
580
581 pub fn disable_identity_responder(&self) {
583 self.state.borrow_mut().identity_responder = None;
584 }
585
586 pub fn update_identity_profile(&self, f: impl FnOnce(&mut NodeIdentityProfile)) {
590 if let Some(responder) = self.state.borrow_mut().identity_responder.as_mut() {
591 f(&mut responder.profile);
592 }
593 }
594
595 pub fn with_identity_profile<R>(&self, f: impl FnOnce(&NodeIdentityProfile) -> R) -> Option<R> {
604 self.state
605 .borrow()
606 .identity_responder
607 .as_ref()
608 .map(|responder| f(&responder.profile))
609 }
610
611 pub(crate) fn evaluate_identity_request(
616 &self,
617 packet: &ReceivedPacketRef<'_>,
618 from: PublicKey,
619 options: &[u8],
620 ) -> Option<IdentityResponsePlan> {
621 let filters = crate::mac_command::IdentityRequestFilters::new(options);
632 if matches!(
633 packet.packet_family(),
634 crate::PacketFamily::Broadcast | crate::PacketFamily::Multicast
635 ) {
636 if packet.source_route().is_some_and(|route| !route.is_empty()) {
637 return None;
638 }
639 if !filters.hint_filtered() && packet.flood_hops().is_some_and(|hops| hops.0 != 0) {
640 return None;
641 }
642 }
643 let ctx = IdentityRequestContext {
644 from_key: from,
645 from_hint: packet.from_hint(),
646 source_authenticated: packet.source_authenticated(),
647 has_full_source: packet.has_full_source(),
648 channel: packet.channel().map(|c| c.id()),
649 family: packet.packet_family(),
650 filters,
651 rssi: packet.rssi(),
652 snr: packet.snr(),
653 };
654 self.state
655 .borrow_mut()
656 .identity_responder
657 .as_mut()?
658 .evaluate(&ctx)
659 }
660
661 const IDENTITY_RESPONSE_MAX_DELAY_MS: u16 = 30_000;
670 const IDENTITY_RESPONSE_MIN_DELAY_MS: u16 = 500;
671
672 pub(crate) async fn send_identity_response(&self, plan: IdentityResponsePlan) {
673 let mut options = SendOptions::default();
674 if plan.full_source {
675 options = options.with_full_source();
676 }
677 if plan.no_flood {
678 options = options.no_flood();
682 }
683 if plan.delayed {
684 let mut jitter = [0u8; 2];
689 self.mac.fill_random(&mut jitter).await;
690 let delay = u16::from_be_bytes(jitter)
691 % (Self::IDENTITY_RESPONSE_MAX_DELAY_MS - Self::IDENTITY_RESPONSE_MIN_DELAY_MS + 1)
692 + Self::IDENTITY_RESPONSE_MIN_DELAY_MS;
693 options = options.with_tx_delay_ms(delay);
694 }
695 let _ = self.mac.ensure_transient_peer(&plan.to).await;
700 let _ = self
701 .mac
702 .send_unicast(self.identity_id, &plan.to, &plan.framed, &options)
703 .await;
704 }
705
706 fn add_transmitted_handler<F>(&self, handler: F) -> SubscriptionHandle
707 where
708 F: FnMut(&[u8]) + 'static,
709 {
710 self.state
711 .borrow_mut()
712 .transmitted_handlers
713 .insert(Box::new(handler))
714 }
715
716 pub fn on_transmitted<F>(&self, handler: F) -> Subscription
718 where
719 F: FnMut(&[u8]) + 'static,
720 {
721 let handle = self.add_transmitted_handler(handler);
722 let state = self.state.clone();
723 Subscription::new(move || state.borrow_mut().transmitted_handlers.remove(handle))
724 }
725
726 fn add_ack_received_handler<F>(&self, handler: F) -> SubscriptionHandle
727 where
728 F: FnMut(PublicKey, SendToken) + 'static,
729 {
730 self.state
731 .borrow_mut()
732 .ack_received_handlers
733 .insert(Box::new(handler))
734 }
735
736 pub fn on_ack_received<F>(&self, handler: F) -> Subscription
737 where
738 F: FnMut(PublicKey, SendToken) + 'static,
739 {
740 let handle = self.add_ack_received_handler(handler);
741 let state = self.state.clone();
742 Subscription::new(move || state.borrow_mut().ack_received_handlers.remove(handle))
743 }
744
745 fn add_ack_timeout_handler<F>(&self, handler: F) -> SubscriptionHandle
746 where
747 F: FnMut(PublicKey, SendToken) + 'static,
748 {
749 self.state
750 .borrow_mut()
751 .ack_timeout_handlers
752 .insert(Box::new(handler))
753 }
754
755 pub fn on_ack_timeout<F>(&self, handler: F) -> Subscription
756 where
757 F: FnMut(PublicKey, SendToken) + 'static,
758 {
759 let handle = self.add_ack_timeout_handler(handler);
760 let state = self.state.clone();
761 Subscription::new(move || state.borrow_mut().ack_timeout_handlers.remove(handle))
762 }
763
764 fn add_pfs_established_handler<F>(&self, handler: F) -> SubscriptionHandle
765 where
766 F: FnMut(PublicKey) + 'static,
767 {
768 self.state
769 .borrow_mut()
770 .pfs_established_handlers
771 .insert(Box::new(handler))
772 }
773
774 pub fn on_pfs_established<F>(&self, handler: F) -> Subscription
775 where
776 F: FnMut(PublicKey) + 'static,
777 {
778 let handle = self.add_pfs_established_handler(handler);
779 let state = self.state.clone();
780 Subscription::new(move || state.borrow_mut().pfs_established_handlers.remove(handle))
781 }
782
783 fn add_pfs_ended_handler<F>(&self, handler: F) -> SubscriptionHandle
784 where
785 F: FnMut(PublicKey) + 'static,
786 {
787 self.state
788 .borrow_mut()
789 .pfs_ended_handlers
790 .insert(Box::new(handler))
791 }
792
793 pub fn on_pfs_ended<F>(&self, handler: F) -> Subscription
794 where
795 F: FnMut(PublicKey) + 'static,
796 {
797 let handle = self.add_pfs_ended_handler(handler);
798 let state = self.state.clone();
799 Subscription::new(move || state.borrow_mut().pfs_ended_handlers.remove(handle))
800 }
801
802 fn add_pfs_failed_handler<F>(&self, handler: F) -> SubscriptionHandle
803 where
804 F: FnMut(PublicKey, PfsFailure) + 'static,
805 {
806 self.state
807 .borrow_mut()
808 .pfs_failed_handlers
809 .insert(Box::new(handler))
810 }
811
812 pub fn on_pfs_failed<F>(&self, handler: F) -> Subscription
818 where
819 F: FnMut(PublicKey, PfsFailure) + 'static,
820 {
821 let handle = self.add_pfs_failed_handler(handler);
822 let state = self.state.clone();
823 Subscription::new(move || state.borrow_mut().pfs_failed_handlers.remove(handle))
824 }
825
826 fn add_pong_handler<F>(&self, handler: F) -> SubscriptionHandle
827 where
828 F: FnMut(PublicKey, u64) + 'static,
829 {
830 self.state
831 .borrow_mut()
832 .pong_handlers
833 .insert(Box::new(handler))
834 }
835
836 pub fn on_pong<F>(&self, handler: F) -> Subscription
837 where
838 F: FnMut(PublicKey, u64) + 'static,
839 {
840 let handle = self.add_pong_handler(handler);
841 let state = self.state.clone();
842 Subscription::new(move || state.borrow_mut().pong_handlers.remove(handle))
843 }
844
845 pub fn on_pong_with_metadata<F>(&self, handler: F) -> Subscription
846 where
847 F: FnMut(PublicKey, &PongMetadata) + 'static,
848 {
849 let handle = self
850 .state
851 .borrow_mut()
852 .pong_metadata_handlers
853 .insert(Box::new(handler));
854 let state = self.state.clone();
855 Subscription::new(move || state.borrow_mut().pong_metadata_handlers.remove(handle))
856 }
857
858 fn add_ping_timeout_handler<F>(&self, handler: F) -> SubscriptionHandle
859 where
860 F: FnMut(PublicKey) + 'static,
861 {
862 self.state
863 .borrow_mut()
864 .ping_timeout_handlers
865 .insert(Box::new(handler))
866 }
867
868 pub fn on_ping_timeout<F>(&self, handler: F) -> Subscription
869 where
870 F: FnMut(PublicKey) + 'static,
871 {
872 let handle = self.add_ping_timeout_handler(handler);
873 let state = self.state.clone();
874 Subscription::new(move || state.borrow_mut().ping_timeout_handlers.remove(handle))
875 }
876
877 pub(crate) fn record_ping(
878 &self,
879 nonce: u16,
880 peer: PublicKey,
881 sent_at_ms: u64,
882 deadline_ms: u64,
883 ) {
884 self.state.borrow_mut().pending_pings.push(PendingPing {
885 nonce,
886 peer,
887 sent_at_ms,
888 deadline_ms,
889 });
890 }
891
892 pub(crate) async fn now_ms(&self) -> u64 {
893 self.mac.now_ms().await
894 }
895
896 pub(crate) async fn fill_random(&self, dest: &mut [u8]) {
897 self.mac.fill_random(dest).await
898 }
899
900 pub(crate) fn match_pong(
902 &self,
903 from: PublicKey,
904 data: &[u8],
905 packet: &ReceivedPacketRef<'_>,
906 now_ms: u64,
907 ) {
908 if data.len() < 2 {
909 return;
910 }
911 let nonce = u16::from_be_bytes([data[0], data[1]]);
912 let mut state = self.state.borrow_mut();
913 let idx = state
914 .pending_pings
915 .iter()
916 .position(|p| p.nonce == nonce && p.peer == from);
917 if let Some(idx) = idx {
918 let ping = state.pending_pings.swap_remove(idx);
919 let rtt_ms = now_ms.saturating_sub(ping.sent_at_ms);
920 let route_hints = packet.trace_route_hops().collect::<Vec<_>>();
921 let hop_count = packet
922 .flood_hops()
923 .map(|hops| hops.accumulated().saturating_add(1))
924 .or_else(|| {
925 packet.trace_route().is_some().then(|| {
926 u8::try_from(route_hints.len())
927 .unwrap_or(u8::MAX)
928 .saturating_add(1)
929 })
930 });
931 let metadata = PongMetadata {
932 round_trip_ms: rtt_ms,
933 hop_count,
934 route_hints,
935 rssi_dbm: packet.rssi(),
936 snr_centibels: packet.snr().map(|snr| snr.as_centibels()),
937 lqi: packet.lqi().map(core::num::NonZeroU8::get),
938 };
939 if let Some(entry) = state.peer_subscriptions.iter_mut().find(|e| e.peer == from) {
940 entry.pong_handlers.for_each_mut(|h| h(rtt_ms));
941 }
942 state.pong_handlers.for_each_mut(|h| h(from, rtt_ms));
943 state
944 .pong_metadata_handlers
945 .for_each_mut(|handler| handler(from, &metadata));
946 }
947 }
948
949 pub(crate) fn expire_pings(&self, now_ms: u64) {
951 let mut state = self.state.borrow_mut();
952 let mut i = 0;
953 while i < state.pending_pings.len() {
954 if now_ms >= state.pending_pings[i].deadline_ms {
955 let ping = state.pending_pings.swap_remove(i);
956 if let Some(entry) = state
957 .peer_subscriptions
958 .iter_mut()
959 .find(|e| e.peer == ping.peer)
960 {
961 entry.ping_timeout_handlers.for_each_mut(|h| h());
962 }
963 state.ping_timeout_handlers.for_each_mut(|h| h(ping.peer));
964 } else {
965 i += 1;
966 }
967 }
968 }
969
970 #[cfg(feature = "software-crypto")]
971 pub async fn request_pfs(
972 &self,
973 peer: &PublicKey,
974 duration_minutes: u16,
975 options: &SendOptions,
976 ) -> Result<SendProgressTicket, NodeError<M>> {
977 let receipt = self
978 .state
979 .borrow_mut()
980 .pfs
981 .request_session(&self.mac, self.identity_id, peer, duration_minutes, options)
982 .await?;
983 Ok(self.register_ack_send(self.identity_id, receipt))
984 }
985
986 #[cfg(feature = "software-crypto")]
987 pub async fn end_pfs(
988 &self,
989 peer: &PublicKey,
990 options: &SendOptions,
991 ) -> Result<(), NodeError<M>> {
992 let _ = self
993 .state
994 .borrow_mut()
995 .pfs
996 .end_session(&self.mac, self.identity_id, peer, true, options)
997 .await?;
998 Ok(())
999 }
1000
1001 #[cfg(feature = "software-crypto")]
1002 pub async fn pfs_status(&self, peer: &PublicKey) -> Result<PfsStatus, NodeError<M>> {
1003 let now_ms = self.mac.now_ms().await;
1004 let state = self.state.borrow();
1005 if let Some(session) = state
1006 .pfs
1007 .sessions()
1008 .iter()
1009 .find(|session| session.peer_long_term == *peer)
1010 {
1011 return Ok(match session.state {
1012 PfsState::Requested => PfsStatus::Requested,
1013 PfsState::Active => PfsStatus::Active {
1014 local_ephemeral_id: session.local_ephemeral_id,
1015 peer_ephemeral: session.peer_ephemeral,
1016 expires_ms: session.expires_ms,
1017 },
1018 });
1019 }
1020 if state.pfs.active_route(peer, now_ms).is_some() {
1021 return Ok(PfsStatus::Requested);
1023 }
1024 Ok(PfsStatus::Inactive)
1025 }
1026
1027 #[cfg(feature = "software-crypto")]
1030 pub async fn join(&self, channel: &Channel) -> Result<BoundChannel<M>, NodeError<M>> {
1031 let membership = self.membership.borrow_mut();
1032
1033 if let Some(entry) = membership.channels.iter().find(|e| e.channel == *channel) {
1035 if entry.active {
1036 return Ok(BoundChannel {
1037 node: self.clone(),
1038 channel: entry.channel.clone(),
1039 join_generation: entry.generation,
1040 });
1041 }
1042 }
1043
1044 drop(membership);
1048 self.mac.add_private_channel(channel.key().clone()).await?;
1049 let mut membership = self.membership.borrow_mut();
1050
1051 if let Some(entry) = membership
1052 .channels
1053 .iter_mut()
1054 .find(|e| e.channel == *channel)
1055 {
1056 entry.active = true;
1057 entry.generation = entry.generation.wrapping_add(1);
1058 return Ok(BoundChannel {
1059 node: self.clone(),
1060 channel: entry.channel.clone(),
1061 join_generation: entry.generation,
1062 });
1063 }
1064
1065 let generation = 0;
1066 membership.channels.push(ChannelMembershipEntry {
1067 channel: channel.clone(),
1068 generation,
1069 active: true,
1070 });
1071
1072 Ok(BoundChannel {
1073 node: self.clone(),
1074 channel: channel.clone(),
1075 join_generation: generation,
1076 })
1077 }
1078
1079 #[cfg(feature = "software-crypto")]
1083 pub async fn leave(&self, channel: &Channel) -> Result<(), NodeError<M>> {
1084 {
1085 let mut membership = self.membership.borrow_mut();
1086 let Some(entry) = membership
1087 .channels
1088 .iter_mut()
1089 .find(|e| e.channel == *channel && e.active)
1090 else {
1091 return Ok(());
1092 };
1093 entry.active = false;
1094 entry.generation = entry.generation.wrapping_add(1);
1095 }
1096 self.mac.remove_channel(channel.key()).await;
1097 Ok(())
1098 }
1099
1100 #[cfg(feature = "software-crypto")]
1102 pub fn bound_channel(&self, channel: &Channel) -> Option<BoundChannel<M>> {
1103 let membership = self.membership.borrow();
1104 membership
1105 .channels
1106 .iter()
1107 .find(|e| e.channel == *channel && e.active)
1108 .map(|entry| BoundChannel {
1109 node: self.clone(),
1110 channel: entry.channel.clone(),
1111 join_generation: entry.generation,
1112 })
1113 }
1114
1115 #[cfg(feature = "software-crypto")]
1117 pub fn bound_channels(&self) -> Vec<BoundChannel<M>> {
1118 let membership = self.membership.borrow();
1119 membership
1120 .channels
1121 .iter()
1122 .filter(|e| e.active)
1123 .map(|entry| BoundChannel {
1124 node: self.clone(),
1125 channel: entry.channel.clone(),
1126 join_generation: entry.generation,
1127 })
1128 .collect()
1129 }
1130
1131 fn register_ack_send(
1133 &self,
1134 send_identity_id: LocalIdentityId,
1135 receipt: Option<umsh_mac::SendReceipt>,
1136 ) -> SendProgressTicket {
1137 match receipt {
1138 Some(receipt) => {
1139 let token = SendToken::new(send_identity_id, receipt);
1140 let state = self.dispatcher.borrow_mut().register_ticket(token, false);
1141 SendProgressTicket::new(token, state)
1142 }
1143 None => SendProgressTicket::fire_and_forget(),
1145 }
1146 }
1147
1148 fn register_non_ack_send(
1153 &self,
1154 send_identity_id: LocalIdentityId,
1155 receipt: umsh_mac::SendReceipt,
1156 ) -> SendProgressTicket {
1157 let token = SendToken::new(send_identity_id, receipt);
1158 let state = self.dispatcher.borrow_mut().register_ticket(token, true);
1159 SendProgressTicket::new(token, state)
1160 }
1161
1162 pub(crate) fn state(&self) -> &Rc<RefCell<LocalNodeState>> {
1163 &self.state
1164 }
1165
1166 #[cfg(feature = "software-crypto")]
1167 pub(crate) fn owns_ephemeral_identity(&self, identity_id: LocalIdentityId) -> bool {
1168 self.state
1169 .borrow()
1170 .pfs
1171 .sessions()
1172 .iter()
1173 .any(|session| session.local_ephemeral_id == identity_id)
1174 }
1175
1176 #[cfg(feature = "software-crypto")]
1177 pub(crate) async fn handle_pfs_command(
1178 &self,
1179 from: &PublicKey,
1180 command: &OwnedMacCommand,
1181 options: &SendOptions,
1182 ) -> Result<Option<PfsLifecycle>, NodeError<M>> {
1183 match *command {
1184 OwnedMacCommand::PfsSessionRequest {
1185 ephemeral_key,
1186 duration_minutes,
1187 } => {
1188 self.state
1189 .borrow_mut()
1190 .pfs
1191 .accept_request(
1192 &self.mac,
1193 self.identity_id,
1194 *from,
1195 ephemeral_key,
1196 duration_minutes,
1197 options,
1198 )
1199 .await?;
1200 Ok(Some(PfsLifecycle::Established(*from)))
1201 }
1202 OwnedMacCommand::PfsSessionResponse {
1203 ephemeral_key,
1204 duration_minutes,
1205 } => {
1206 if self
1207 .state
1208 .borrow_mut()
1209 .pfs
1210 .accept_response(
1211 &self.mac,
1212 self.identity_id,
1213 *from,
1214 ephemeral_key,
1215 duration_minutes,
1216 )
1217 .await?
1218 {
1219 Ok(Some(PfsLifecycle::Established(*from)))
1220 } else {
1221 Ok(None)
1222 }
1223 }
1224 OwnedMacCommand::EndPfsSession => {
1225 let _ = self
1226 .state
1227 .borrow_mut()
1228 .pfs
1229 .end_session(&self.mac, self.identity_id, from, false, options)
1230 .await?;
1231 Ok(Some(PfsLifecycle::Ended(*from)))
1232 }
1233 _ => Ok(None),
1234 }
1235 }
1236
1237 pub(crate) fn dispatch_received_packet(&self, packet: &ReceivedPacketRef<'_>) -> bool {
1238 let peer = packet.from_key();
1239 let mut state = self.state.borrow_mut();
1240
1241 if let Some(peer) = peer.map(|peer| canonical_peer(&state, peer)) {
1242 if let Some(entry) = state
1243 .peer_subscriptions
1244 .iter_mut()
1245 .find(|entry| entry.peer == peer)
1246 {
1247 if entry.receive_handlers.any_mut(|handler| handler(packet)) {
1248 return true;
1249 }
1250 }
1251 }
1252
1253 state.receive_handlers.any_mut(|handler| handler(packet))
1254 }
1255
1256 pub(crate) fn dispatch_node_discovered(&self, key: PublicKey, name: Option<&str>) {
1257 self.state
1258 .borrow_mut()
1259 .node_discovered_handlers
1260 .for_each_mut(|handler| handler(key, name));
1261 }
1262
1263 pub(crate) fn dispatch_beacon(&self, from_hint: NodeHint, from_key: Option<PublicKey>) {
1264 self.state
1265 .borrow_mut()
1266 .beacon_handlers
1267 .for_each_mut(|handler| handler(from_hint, from_key));
1268 }
1269
1270 pub(crate) fn dispatch_mac_command(&self, from: PublicKey, command: &OwnedMacCommand) {
1271 self.state
1272 .borrow_mut()
1273 .mac_command_handlers
1274 .for_each_mut(|handler| handler(from, command));
1275 }
1276
1277 pub(crate) fn dispatch_transmitted(&self, wire_bytes: &[u8]) {
1278 self.state
1279 .borrow_mut()
1280 .transmitted_handlers
1281 .for_each_mut(|handler| handler(wire_bytes));
1282 }
1283
1284 pub(crate) fn dispatch_ack_received(&self, peer: PublicKey, token: SendToken) {
1285 let mut state = self.state.borrow_mut();
1286 let peer = canonical_peer(&state, peer);
1287 if let Some(entry) = state
1288 .peer_subscriptions
1289 .iter_mut()
1290 .find(|entry| entry.peer == peer)
1291 {
1292 entry
1293 .ack_received_handlers
1294 .for_each_mut(|handler| handler(token));
1295 }
1296 state
1297 .ack_received_handlers
1298 .for_each_mut(|handler| handler(peer, token));
1299 }
1300
1301 pub(crate) fn dispatch_ack_timeout(&self, peer: PublicKey, token: SendToken) {
1302 let mut state = self.state.borrow_mut();
1303 let peer = canonical_peer(&state, peer);
1304 if let Some(entry) = state
1305 .peer_subscriptions
1306 .iter_mut()
1307 .find(|entry| entry.peer == peer)
1308 {
1309 entry
1310 .ack_timeout_handlers
1311 .for_each_mut(|handler| handler(token));
1312 }
1313 state
1314 .ack_timeout_handlers
1315 .for_each_mut(|handler| handler(peer, token));
1316 }
1317
1318 pub(crate) fn dispatch_pfs_established(&self, peer: PublicKey) {
1319 let mut state = self.state.borrow_mut();
1320 let peer = canonical_peer(&state, peer);
1321 if let Some(entry) = state
1322 .peer_subscriptions
1323 .iter_mut()
1324 .find(|entry| entry.peer == peer)
1325 {
1326 entry
1327 .pfs_established_handlers
1328 .for_each_mut(|handler| handler());
1329 }
1330 state
1331 .pfs_established_handlers
1332 .for_each_mut(|handler| handler(peer));
1333 }
1334
1335 pub(crate) fn dispatch_pfs_ended(&self, peer: PublicKey) {
1336 let mut state = self.state.borrow_mut();
1337 let peer = canonical_peer(&state, peer);
1338 if let Some(entry) = state
1339 .peer_subscriptions
1340 .iter_mut()
1341 .find(|entry| entry.peer == peer)
1342 {
1343 entry.pfs_ended_handlers.for_each_mut(|handler| handler());
1344 }
1345 state
1346 .pfs_ended_handlers
1347 .for_each_mut(|handler| handler(peer));
1348 }
1349
1350 pub(crate) fn dispatch_pfs_failed(&self, peer: PublicKey, reason: PfsFailure) {
1351 let mut state = self.state.borrow_mut();
1352 let peer = canonical_peer(&state, peer);
1353 state
1354 .pfs_failed_handlers
1355 .for_each_mut(|handler| handler(peer, reason));
1356 }
1357
1358 pub(crate) async fn expire_pfs_sessions(&self) -> Result<Vec<PublicKey>, NodeError<M>> {
1359 #[cfg(feature = "software-crypto")]
1360 {
1361 let now_ms = self.mac.now_ms().await;
1362 return self
1363 .state
1364 .borrow_mut()
1365 .pfs
1366 .expire_sessions(&self.mac, now_ms)
1367 .await;
1368 }
1369 #[cfg(not(feature = "software-crypto"))]
1370 {
1371 Ok(Vec::new())
1372 }
1373 }
1374
1375 #[cfg(feature = "software-crypto")]
1378 pub(crate) fn expire_pfs_requests(&self, now_ms: u64) -> Vec<PublicKey> {
1379 self.state.borrow_mut().pfs.expire_requests(now_ms)
1380 }
1381}
1382
1383fn canonical_peer(state: &LocalNodeState, peer: PublicKey) -> PublicKey {
1384 #[cfg(feature = "software-crypto")]
1385 {
1386 if let Some(session) = state
1387 .pfs
1388 .sessions()
1389 .iter()
1390 .find(|session| session.state == PfsState::Active && session.peer_ephemeral == peer)
1391 {
1392 return session.peer_long_term;
1393 }
1394 }
1395 peer
1396}
1397
1398impl<M: MacBackend> Transport for LocalNode<M> {
1399 type Error = NodeError<M>;
1400
1401 async fn send(
1402 &self,
1403 to: &PublicKey,
1404 payload: &[u8],
1405 options: &SendOptions,
1406 ) -> Result<SendProgressTicket, Self::Error> {
1407 #[cfg(feature = "software-crypto")]
1408 let (send_identity_id, receipt) = {
1409 let now_ms = self.mac.now_ms().await;
1410 if let Some((local_id, peer_ephemeral)) =
1411 self.state.borrow().pfs.active_route(to, now_ms)
1412 {
1413 let receipt = self
1414 .mac
1415 .send_unicast(local_id, &peer_ephemeral, payload, options)
1416 .await?;
1417 (local_id, receipt)
1418 } else {
1419 let receipt = self
1420 .mac
1421 .send_unicast(self.identity_id, to, payload, options)
1422 .await?;
1423 (self.identity_id, receipt)
1424 }
1425 };
1426 #[cfg(not(feature = "software-crypto"))]
1427 let (send_identity_id, receipt) = (
1428 self.identity_id,
1429 self.mac
1430 .send_unicast(self.identity_id, to, payload, options)
1431 .await?,
1432 );
1433 Ok(self.register_ack_send(send_identity_id, receipt))
1434 }
1435
1436 async fn send_all(
1437 &self,
1438 payload: &[u8],
1439 options: &SendOptions,
1440 ) -> Result<SendProgressTicket, Self::Error> {
1441 let receipt = self
1442 .mac
1443 .send_broadcast(self.identity_id, payload, options)
1444 .await?;
1445 Ok(self.register_non_ack_send(self.identity_id, receipt))
1446 }
1447}
1448
1449#[cfg(feature = "software-crypto")]
1455#[derive(Clone)]
1456pub struct BoundChannel<M: MacBackend> {
1457 node: LocalNode<M>,
1458 channel: Channel,
1459 join_generation: u64,
1460}
1461
1462#[cfg(feature = "software-crypto")]
1463impl<M: MacBackend> BoundChannel<M> {
1464 pub fn channel(&self) -> &Channel {
1466 &self.channel
1467 }
1468
1469 pub fn is_active(&self) -> bool {
1471 let membership = self.node.membership.borrow();
1472 membership
1473 .channels
1474 .iter()
1475 .any(|e| e.channel == self.channel && e.active && e.generation == self.join_generation)
1476 }
1477
1478 pub fn peer(&self, key: PublicKey) -> PeerConnection<Self> {
1480 PeerConnection::new(self.clone(), key)
1481 }
1482
1483 fn check_active(&self) -> Result<(), NodeError<M>> {
1485 if self.is_active() {
1486 Ok(())
1487 } else {
1488 Err(NodeError::ChannelLeft)
1489 }
1490 }
1491
1492 pub fn node(&self) -> &LocalNode<M> {
1494 &self.node
1495 }
1496}
1497
1498#[cfg(feature = "software-crypto")]
1499impl<M: MacBackend> Transport for BoundChannel<M> {
1500 type Error = NodeError<M>;
1501
1502 async fn send(
1503 &self,
1504 to: &PublicKey,
1505 payload: &[u8],
1506 options: &SendOptions,
1507 ) -> Result<SendProgressTicket, Self::Error> {
1508 self.check_active()?;
1509 let receipt = self
1510 .node
1511 .mac
1512 .send_blind_unicast(
1513 self.node.identity_id,
1514 to,
1515 self.channel.channel_id(),
1516 payload,
1517 options,
1518 )
1519 .await?;
1520 Ok(self.node.register_ack_send(self.node.identity_id, receipt))
1521 }
1522
1523 async fn send_all(
1524 &self,
1525 payload: &[u8],
1526 options: &SendOptions,
1527 ) -> Result<SendProgressTicket, Self::Error> {
1528 self.check_active()?;
1529 let receipt = self
1530 .node
1531 .mac
1532 .send_multicast(
1533 self.node.identity_id,
1534 self.channel.channel_id(),
1535 payload,
1536 options,
1537 )
1538 .await?;
1539 Ok(self
1540 .node
1541 .register_non_ack_send(self.node.identity_id, receipt))
1542 }
1543}