1use crate::config::RuntimeMemoryConfig;
12use crate::diagnostics::{
13 AdaptiveLinkStats, DiscoveryRuntimeStats, QueueRuntimeStats, ReliableRuntimeStats,
14 RouteModeStats, RouteOverrideStats, RoutePriorityStats, RouteWeightStats, RuntimeSideStats,
15 RuntimeStatsSnapshot, RuntimeTypeStats, TypedRouteOverrideStats,
16};
17#[cfg(feature = "discovery")]
18use crate::discovery::{
19 self, ClientStatsSnapshot, DISCOVERY_ROUTE_TTL_MS, DISCOVERY_SLOW_LINK_FULL_INTERVAL_MS,
20 DISCOVERY_SLOW_LINK_PING_INTERVAL_MS, DiscoveryCadenceState,
21 TIMESYNC_SLOW_LINK_MIN_INTERVAL_MS, TopologyAnnouncerRoute, TopologyBoardNode,
22 TopologySideRoute, TopologySnapshot,
23};
24use crate::packet::{hash_bytes_u64, sender_address_u32};
25use crate::queue::{BoundedDeque, ByteCost};
26#[cfg(all(not(feature = "std"), target_os = "none"))]
27use crate::seds_error_msg;
28#[cfg(feature = "timesync")]
29use crate::timesync::{
30 INTERNAL_TIMESYNC_SOURCE_ID, LOCAL_TIMESYNC_DATE_SOURCE_ID, LOCAL_TIMESYNC_FULL_SOURCE_ID,
31 LOCAL_TIMESYNC_SUBSEC_SOURCE_ID, LOCAL_TIMESYNC_TOD_SOURCE_ID, NetworkClock,
32 NetworkTimeReading, PartialNetworkTime, SlewedNetworkClock, TimeSyncConfig, TimeSyncLeader,
33 TimeSyncTracker, advance_network_time, compute_network_time_sample, decode_timesync_announce,
34 decode_timesync_request, decode_timesync_response,
35};
36use crate::{
37 E2eEncryptionPolicy, MessageElement, RouteSelectionMode, TelemetryError, TelemetryResult,
38 config::{
39 DataEndpoint, DataType, runtime_device_identifier, runtime_max_handler_retries,
40 runtime_reliable_max_end_to_end_pending, runtime_reliable_max_pending,
41 runtime_reliable_max_retries, runtime_reliable_max_return_routes,
42 runtime_reliable_retransmit_ms,
43 },
44 get_needed_message_size, impl_letype_num, is_reliable_type,
45 lock::{ReentryGate, RouterMutex},
46 message_e2e_encryption_policy, message_meta, message_priority,
47 packet::Packet,
48 reliable_mode, wire_format,
49};
50use alloc::string::{String, ToString};
51use alloc::{
52 borrow::ToOwned,
53 boxed::Box,
54 collections::{BTreeMap, BTreeSet, VecDeque},
55 format,
56 sync::Arc,
57 vec,
58 vec::Vec,
59};
60use core::cell::UnsafeCell;
61use core::fmt;
62use core::fmt::{Debug, Formatter};
63use core::mem::size_of;
64use core::ops::{Deref, DerefMut};
65use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
66use crc32fast::Hasher as Crc32Hasher;
67#[cfg(feature = "std")]
68use std::time::Instant;
69
70pub type RouterSideId = usize;
72
73const SIDE_TRANSPORT_MAGIC: &[u8; 3] = b"SDT";
74const SIDE_TRANSPORT_KIND_FULL: u8 = 0x01;
75const SIDE_TRANSPORT_KIND_COMPACT: u8 = 0x02;
76const SIDE_TRANSPORT_KIND_CHUNK: u8 = 0x03;
77const SIDE_TRANSPORT_KIND_COMPACT_DELTA: u8 = 0x04;
78const SIDE_TRANSPORT_KIND_COMPACT_SAME_TIMESTAMP: u8 = 0x05;
79const SIDE_TRANSPORT_FLAG_PAYLOAD_COMPRESSED: u8 = 0x01;
80const SIDE_TRANSPORT_FLAG_WIRE_CONTRACT: u8 = 0x04;
81const SIDE_TRANSPORT_FLAG_PACKET_NONCE: u8 = 0x08;
82const SIDE_TRANSPORT_FLAG_ENDPOINT_BITMAP_PRESENT: u8 = 0x20;
83const SIDE_TRANSPORT_FLAG_COMPACT_RELIABLE_HEADER: u8 = 0x40;
84const CONTROL_SLOW_LINK_CAPACITY_BPS: u64 = 512;
85const SIDE_TRANSPORT_CHUNK_OVERHEAD: usize = 3 + 1 + 4 + 2 + 2 + wire_format::CRC32_BYTES;
86const SIDE_TIMESTAMP_POLICY_WORDS: usize = ((crate::MAX_VALUE_DATA_TYPE as usize) + 1).div_ceil(64);
87const SIDE_TRANSPORT_EP_BITMAP_BITS: usize = (crate::MAX_VALUE_DATA_ENDPOINT as usize) + 1;
88const SIDE_TRANSPORT_EP_BITMAP_BYTES: usize = SIDE_TRANSPORT_EP_BITMAP_BITS.div_ceil(8);
89pub const IPV4_LIKE_COMPACT_HEADER_TARGET_BYTES: usize = 20;
90pub const IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES: usize = 40;
91pub const DEFAULT_SIDE_TRANSPORT_TEMPLATE_LIMIT: usize = 64;
92static ROUTER_INSTANCE_SEQ: AtomicU32 = AtomicU32::new(1);
93
94#[derive(Clone, Copy, Debug, PartialEq, Eq)]
95pub enum SideTransportProfile {
96 Canonical,
97 Template,
98 Ipv6Like,
99 Ipv4Like,
100}
101
102impl SideTransportProfile {
103 #[inline]
104 pub const fn as_str(self) -> &'static str {
105 match self {
106 Self::Canonical => "canonical",
107 Self::Template => "template",
108 Self::Ipv6Like => "ipv6_like",
109 Self::Ipv4Like => "ipv4_like",
110 }
111 }
112
113 #[cfg(feature = "discovery")]
114 #[inline]
115 pub const fn discovery_code(self) -> u8 {
116 match self {
117 Self::Canonical => discovery::LINK_PROFILE_CANONICAL,
118 Self::Template => discovery::LINK_PROFILE_TEMPLATE,
119 Self::Ipv6Like => discovery::LINK_PROFILE_IPV6_LIKE,
120 Self::Ipv4Like => discovery::LINK_PROFILE_IPV4_LIKE,
121 }
122 }
123}
124
125#[derive(Clone, Debug, PartialEq, Eq)]
126struct SideHeaderTemplate {
127 hash: u64,
128 base_flags: u8,
129 prefix: Arc<[u8]>,
130 between: Arc<[u8]>,
131 reliable_flags: Option<u8>,
132 reliable_compact: bool,
133}
134
135#[derive(Clone, Debug, Default, PartialEq, Eq)]
136struct SideChunkAssembly {
137 total: u16,
138 received: BTreeMap<u16, Arc<[u8]>>,
139}
140
141#[derive(Clone, Debug, Default)]
142struct SideTransportState {
143 tx_template_ids: BTreeMap<u64, u32>,
144 tx_templates: BTreeMap<u64, SideHeaderTemplate>,
145 tx_last_timestamps: BTreeMap<u32, u64>,
146 tx_compact_uses: BTreeMap<u32, u8>,
147 rx_templates: BTreeMap<u64, SideHeaderTemplate>,
148 rx_templates_by_id: BTreeMap<u32, SideHeaderTemplate>,
149 rx_last_timestamps: BTreeMap<u32, u64>,
150 rx_chunks: BTreeMap<u32, SideChunkAssembly>,
151 next_chunk_id: u32,
152 next_template_id: u32,
153}
154
155impl SideTransportState {
156 fn tx_template_count(&self) -> usize {
157 self.tx_template_ids.len()
158 }
159
160 fn rx_template_count(&self) -> usize {
161 self.rx_templates_by_id.len()
162 }
163
164 fn insert_tx_template(
165 &mut self,
166 template: SideHeaderTemplate,
167 template_id: u32,
168 max_templates: usize,
169 ) -> bool {
170 if max_templates == 0 {
171 return false;
172 }
173 let mut evicted = false;
174 if self.tx_template_ids.len() >= max_templates
175 && !self.tx_template_ids.contains_key(&template.hash)
176 && let Some(old_hash) = self.tx_template_ids.keys().next().copied()
177 {
178 if let Some(old_id) = self.tx_template_ids.remove(&old_hash) {
179 self.tx_last_timestamps.remove(&old_id);
180 self.tx_compact_uses.remove(&old_id);
181 }
182 self.tx_templates.remove(&old_hash);
183 evicted = true;
184 }
185 self.tx_template_ids.insert(template.hash, template_id);
186 self.tx_templates.insert(template.hash, template);
187 self.tx_compact_uses.insert(template_id, 0);
188 evicted
189 }
190
191 fn insert_rx_template(
192 &mut self,
193 template_id: u32,
194 template: SideHeaderTemplate,
195 max_templates: usize,
196 ) -> bool {
197 if max_templates == 0 {
198 return false;
199 }
200 let mut evicted = false;
201 if self.rx_templates_by_id.len() >= max_templates
202 && !self.rx_templates_by_id.contains_key(&template_id)
203 && let Some(old_hash) = self.rx_templates.keys().next().copied()
208 && let Some(old_id) = self.rx_templates_by_id.iter().find_map(|(id, existing)| {
209 (existing.hash == old_hash).then_some(*id)
210 })
211 && let Some(old_template) = self.rx_templates_by_id.remove(&old_id)
212 {
213 self.rx_templates.remove(&old_template.hash);
214 self.rx_last_timestamps.remove(&old_id);
215 evicted = true;
216 }
217 self.rx_templates_by_id
218 .insert(template_id, template.clone());
219 self.rx_templates.insert(template.hash, template);
220 evicted
221 }
222}
223
224type SideTemplateExtract<'a> = (
225 SideHeaderTemplate,
226 DataType,
227 u8,
228 u64,
229 u64,
230 u16,
231 Option<(u32, u32)>,
232 &'a [u8],
233);
234
235#[derive(Clone, Copy, Debug, PartialEq, Eq)]
236pub struct CompactTimestampOmissionPolicy {
237 all: bool,
238 words: [u64; SIDE_TIMESTAMP_POLICY_WORDS],
239}
240
241impl CompactTimestampOmissionPolicy {
242 #[inline]
243 pub const fn none() -> Self {
244 Self {
245 all: false,
246 words: [0; SIDE_TIMESTAMP_POLICY_WORDS],
247 }
248 }
249
250 #[inline]
251 pub const fn all() -> Self {
252 Self {
253 all: true,
254 words: [0; SIDE_TIMESTAMP_POLICY_WORDS],
255 }
256 }
257
258 #[inline]
259 pub fn with_data_type(mut self, ty: DataType) -> Self {
260 self.insert(ty);
261 self
262 }
263
264 #[inline]
265 pub fn insert(&mut self, ty: DataType) {
266 let id = ty.as_u32() as usize;
267 if id <= crate::MAX_VALUE_DATA_TYPE as usize {
268 self.words[id / 64] |= 1u64 << (id % 64);
269 }
270 }
271
272 #[inline]
273 pub fn contains(self, ty: DataType) -> bool {
274 if self.all {
275 return true;
276 }
277 let id = ty.as_u32() as usize;
278 id <= crate::MAX_VALUE_DATA_TYPE as usize
279 && (self.words[id / 64] & (1u64 << (id % 64))) != 0
280 }
281
282 #[inline]
283 pub fn is_empty(self) -> bool {
284 !self.all && self.words.iter().all(|word| *word == 0)
285 }
286}
287
288impl Default for CompactTimestampOmissionPolicy {
289 #[inline]
290 fn default() -> Self {
291 Self::none()
292 }
293}
294
295#[derive(Clone, Copy, Debug, PartialEq, Eq)]
296enum SideCompactTimestampMode {
297 Absolute,
298 Delta,
299 Omitted,
300}
301
302#[derive(Clone, Debug, PartialEq, Eq)]
303pub enum RouterItem {
304 Packet(Packet),
305 Packed(Arc<[u8]>),
306}
307
308#[derive(Clone, Debug, PartialEq, Eq)]
309struct RouterRxItem {
310 src: Option<RouterSideId>,
311 data: RouterItem,
312 priority: u8,
313}
314
315#[derive(Clone, Debug, PartialEq, Eq)]
316enum RouterTxItem {
317 Broadcast(RouterItem),
318 EndToEndReplay {
319 packet_id: u64,
320 },
321 ToSide {
322 src: Option<RouterSideId>,
323 dst: RouterSideId,
324 data: RouterItem,
325 },
326 ReliableReplay {
327 dst: RouterSideId,
328 bytes: Arc<[u8]>,
329 },
330}
331
332impl ByteCost for RouterRxItem {
333 #[inline]
334 fn byte_cost(&self) -> usize {
335 match &self.data {
336 RouterItem::Packet(pkt) => pkt.byte_cost(),
337 RouterItem::Packed(bytes) => size_of::<Arc<[u8]>>() + bytes.len(),
338 }
339 }
340}
341
342impl ByteCost for RouterTxItem {
343 #[inline]
344 fn byte_cost(&self) -> usize {
345 match self {
346 RouterTxItem::Broadcast(data) => match data {
347 RouterItem::Packet(pkt) => pkt.byte_cost(),
348 RouterItem::Packed(bytes) => size_of::<Arc<[u8]>>() + bytes.len(),
349 },
350 RouterTxItem::EndToEndReplay { .. } => size_of::<u64>(),
351 RouterTxItem::ToSide { data, .. } => match data {
352 RouterItem::Packet(pkt) => pkt.byte_cost(),
353 RouterItem::Packed(bytes) => size_of::<Arc<[u8]>>() + bytes.len(),
354 },
355 RouterTxItem::ReliableReplay { bytes, .. } => size_of::<Arc<[u8]>>() + bytes.len(),
356 }
357 }
358}
359
360#[derive(Clone, Debug, PartialEq, Eq)]
364struct TxQueued {
365 item: RouterTxItem,
366 ignore_local: bool,
367 priority: u8,
368}
369
370const MAX_PRIORITY_BURST: u8 = 8;
375
376impl ByteCost for TxQueued {
378 #[inline]
380 fn byte_cost(&self) -> usize {
381 self.item.byte_cost() + size_of::<bool>() + size_of::<u8>()
382 }
383}
384
385impl ByteCost for u64 {
387 #[inline]
389 fn byte_cost(&self) -> usize {
390 size_of::<u64>()
391 }
392}
393
394#[derive(Debug, Clone)]
397struct ReliableTxState {
398 next_seq: u32,
399 sent_order: VecDeque<u32>,
400 sent: BTreeMap<u32, ReliableSent>,
401}
402
403#[derive(Debug, Clone)]
404struct ReliableSent {
405 bytes: Arc<[u8]>,
406 last_send_ms: u64,
407 retries: u32,
408 queued: bool,
409 partial_acked: bool,
410}
411
412#[derive(Debug, Clone)]
413struct EndToEndReliableSent {
414 data: RouterItem,
415 pending_destinations: BTreeMap<u64, RouterSideId>,
416 tracked_destinations: bool,
417 last_send_ms: u64,
418 retries: u32,
419 queued: bool,
420}
421
422#[derive(Debug, Clone)]
423struct ReliableRxState {
424 expected_seq: u32,
425 buffered: BTreeMap<u32, Arc<[u8]>>,
426}
427
428#[derive(Debug, Clone)]
429struct ReliableReturnRouteState {
430 side: RouterSideId,
431}
432
433#[cfg(feature = "discovery")]
434#[derive(Debug, Clone, Default, PartialEq, Eq)]
435struct DiscoverySenderState {
436 reachable: Vec<DataEndpoint>,
437 reachable_network_variables: Vec<DataType>,
438 reachable_timesync_sources: Vec<String>,
439 topology_boards: Vec<TopologyBoardNode>,
440 last_seen_ms: u64,
441}
442
443#[cfg(feature = "discovery")]
444#[derive(Debug, Clone, Default, PartialEq, Eq)]
445struct DiscoverySideState {
446 reachable: Vec<DataEndpoint>,
447 reachable_network_variables: Vec<DataType>,
448 reachable_timesync_sources: Vec<String>,
449 last_seen_ms: u64,
450 announcers: BTreeMap<String, DiscoverySenderState>,
451}
452
453#[cfg(feature = "discovery")]
454#[derive(Debug, Clone, Default)]
455struct DiscoverySideThrottleState {
456 next_ping_ms: u64,
457 next_full_ms: u64,
458}
459
460#[cfg(all(feature = "discovery", feature = "timesync"))]
461#[derive(Debug, Clone, Default)]
462struct TimeSyncSideThrottleState {
463 next_allowed_ms: u64,
464}
465
466#[cfg(feature = "discovery")]
467#[derive(Debug, Clone, Copy, PartialEq, Eq)]
468enum DiscoveryAdvertiseLevel {
469 MinimalPing,
470 Full,
471}
472
473#[derive(Debug, Clone, Default)]
474struct AdaptiveRouteStats {
475 estimated_bandwidth_bps: u64,
476 peak_bandwidth_bps: u64,
477 last_observed_ms: u64,
478 last_slow_observed_ms: u64,
479 sample_count: u64,
480 window_started_ms: u64,
481 window_bytes: u64,
482 peak_usage_bps: u64,
483}
484
485impl AdaptiveRouteStats {
486 #[inline]
487 fn observe(&mut self, bytes: usize, sample_bps: u64, now_ms: u64) {
488 self.estimated_bandwidth_bps = if self.estimated_bandwidth_bps == 0 {
489 sample_bps
490 } else if sample_bps >= self.estimated_bandwidth_bps {
491 self.estimated_bandwidth_bps
492 .saturating_mul(3)
493 .saturating_add(sample_bps.saturating_mul(5))
494 / 8
495 } else {
496 self.estimated_bandwidth_bps
497 .saturating_mul(7)
498 .saturating_add(sample_bps)
499 / 8
500 };
501 self.peak_bandwidth_bps = self.peak_bandwidth_bps.max(sample_bps);
502 self.last_observed_ms = now_ms;
503 if sample_bps > 0 && sample_bps <= CONTROL_SLOW_LINK_CAPACITY_BPS {
504 self.last_slow_observed_ms = now_ms;
505 }
506 self.sample_count = self.sample_count.saturating_add(1);
507 if self.window_started_ms == 0 || now_ms.saturating_sub(self.window_started_ms) > 1_000 {
508 self.window_started_ms = now_ms;
509 self.window_bytes = 0;
510 }
511 self.window_bytes = self.window_bytes.saturating_add(bytes as u64);
512 self.peak_usage_bps = self.peak_usage_bps.max(self.current_usage_bps(now_ms));
513 }
514
515 #[inline]
516 fn current_usage_bps(&self, now_ms: u64) -> u64 {
517 if self.window_started_ms == 0 {
518 return 0;
519 }
520 let elapsed_ms = now_ms.saturating_sub(self.window_started_ms).max(1);
521 (u128::from(self.window_bytes).saturating_mul(1000) / u128::from(elapsed_ms))
522 .min(u128::from(u64::MAX)) as u64
523 }
524
525 #[inline]
526 fn available_headroom_bps(&self, now_ms: u64) -> u64 {
527 let capacity = self
528 .estimated_bandwidth_bps
529 .max(self.peak_bandwidth_bps)
530 .max(1);
531 capacity.saturating_sub(self.current_usage_bps(now_ms))
532 }
533
534 #[inline]
535 fn weight(&self, now_ms: u64) -> u64 {
536 self.available_headroom_bps(now_ms).max(1)
537 }
538
539 #[inline]
540 fn snapshot(&self, now_ms: u64, auto_balancing_enabled: bool) -> AdaptiveLinkStats {
541 let current_usage_bps = self.current_usage_bps(now_ms);
542 let estimated_capacity_bps = self.estimated_bandwidth_bps.max(1);
543 let peak_capacity_bps = self.peak_bandwidth_bps.max(estimated_capacity_bps);
544 let available_headroom_bps = peak_capacity_bps.saturating_sub(current_usage_bps);
545 AdaptiveLinkStats {
546 auto_balancing_enabled,
547 estimated_capacity_bps,
548 peak_capacity_bps,
549 current_usage_bps,
550 peak_usage_bps: self.peak_usage_bps.max(current_usage_bps),
551 available_headroom_bps,
552 effective_weight: available_headroom_bps.max(1),
553 last_observed_ms: self.last_observed_ms,
554 sample_count: self.sample_count,
555 }
556 }
557}
558
559#[derive(Debug, Clone, Default)]
560struct TypeRuntimeStatsInner {
561 tx_packets: u64,
562 tx_bytes: u64,
563 rx_packets: u64,
564 rx_bytes: u64,
565 relayed_tx_packets: u64,
566 relayed_tx_bytes: u64,
567 relayed_rx_packets: u64,
568 relayed_rx_bytes: u64,
569 tx_retries: u64,
570 handler_failures: u64,
571}
572
573#[derive(Debug, Clone, Default)]
574struct SideRuntimeStatsInner {
575 tx_packets: u64,
576 tx_bytes: u64,
577 rx_packets: u64,
578 rx_bytes: u64,
579 relayed_tx_packets: u64,
580 relayed_tx_bytes: u64,
581 relayed_rx_packets: u64,
582 relayed_rx_bytes: u64,
583 local_delivery_packets: u64,
584 tx_retries: u64,
585 tx_handler_failures: u64,
586 local_handler_failures: u64,
587 total_handler_retries: u64,
588 side_transport_full_frames: u64,
589 side_transport_compact_frames: u64,
590 side_transport_compact_delta_frames: u64,
591 side_transport_compact_omitted_timestamp_frames: u64,
592 side_transport_chunk_frames: u64,
593 side_transport_raw_bytes: u64,
594 side_transport_wire_bytes: u64,
595 side_transport_bytes_saved: u64,
596 side_transport_min_compact_overhead_bytes: Option<usize>,
597 side_transport_max_compact_overhead_bytes: Option<usize>,
598 side_transport_compact_target_misses: u64,
599 side_transport_template_evictions: u64,
600 data_types: BTreeMap<u32, TypeRuntimeStatsInner>,
601}
602
603impl SideRuntimeStatsInner {
604 fn type_stats_mut(&mut self, ty: DataType) -> &mut TypeRuntimeStatsInner {
605 self.data_types.entry(ty.as_u32()).or_default()
606 }
607
608 fn note_tx(&mut self, ty: DataType, bytes: usize, relayed: bool, retries: usize) {
609 self.tx_packets = self.tx_packets.saturating_add(1);
610 self.tx_bytes = self.tx_bytes.saturating_add(bytes as u64);
611 self.tx_retries = self.tx_retries.saturating_add(retries as u64);
612 self.total_handler_retries = self.total_handler_retries.saturating_add(retries as u64);
613 if relayed {
614 self.relayed_tx_packets = self.relayed_tx_packets.saturating_add(1);
615 self.relayed_tx_bytes = self.relayed_tx_bytes.saturating_add(bytes as u64);
616 }
617 let stats = self.type_stats_mut(ty);
618 stats.tx_packets = stats.tx_packets.saturating_add(1);
619 stats.tx_bytes = stats.tx_bytes.saturating_add(bytes as u64);
620 stats.tx_retries = stats.tx_retries.saturating_add(retries as u64);
621 if relayed {
622 stats.relayed_tx_packets = stats.relayed_tx_packets.saturating_add(1);
623 stats.relayed_tx_bytes = stats.relayed_tx_bytes.saturating_add(bytes as u64);
624 }
625 }
626
627 fn note_rx(&mut self, ty: DataType, bytes: usize, relayed: bool) {
628 self.rx_packets = self.rx_packets.saturating_add(1);
629 self.rx_bytes = self.rx_bytes.saturating_add(bytes as u64);
630 if relayed {
631 self.relayed_rx_packets = self.relayed_rx_packets.saturating_add(1);
632 self.relayed_rx_bytes = self.relayed_rx_bytes.saturating_add(bytes as u64);
633 }
634 let stats = self.type_stats_mut(ty);
635 stats.rx_packets = stats.rx_packets.saturating_add(1);
636 stats.rx_bytes = stats.rx_bytes.saturating_add(bytes as u64);
637 if relayed {
638 stats.relayed_rx_packets = stats.relayed_rx_packets.saturating_add(1);
639 stats.relayed_rx_bytes = stats.relayed_rx_bytes.saturating_add(bytes as u64);
640 }
641 }
642
643 fn note_local_delivery(&mut self, ty: DataType) {
644 self.local_delivery_packets = self.local_delivery_packets.saturating_add(1);
645 let stats = self.type_stats_mut(ty);
646 stats.rx_packets = stats.rx_packets.saturating_add(1);
647 }
648
649 fn note_local_handler_failure(&mut self, ty: DataType, retries: usize) {
650 self.local_handler_failures = self.local_handler_failures.saturating_add(1);
651 self.total_handler_retries = self.total_handler_retries.saturating_add(retries as u64);
652 let stats = self.type_stats_mut(ty);
653 stats.handler_failures = stats.handler_failures.saturating_add(1);
654 }
655
656 fn note_tx_failure(&mut self, ty: DataType, retries: usize) {
657 self.tx_handler_failures = self.tx_handler_failures.saturating_add(1);
658 self.total_handler_retries = self.total_handler_retries.saturating_add(retries as u64);
659 self.tx_retries = self.tx_retries.saturating_add(retries as u64);
660 let stats = self.type_stats_mut(ty);
661 stats.handler_failures = stats.handler_failures.saturating_add(1);
662 stats.tx_retries = stats.tx_retries.saturating_add(retries as u64);
663 }
664
665 fn note_side_transport_full(&mut self, raw_bytes: usize, wire_bytes: usize) {
666 self.side_transport_full_frames = self.side_transport_full_frames.saturating_add(1);
667 self.note_side_transport_bytes(raw_bytes, wire_bytes);
668 }
669
670 fn note_side_transport_compact(
671 &mut self,
672 raw_bytes: usize,
673 wire_bytes: usize,
674 compact_overhead_bytes: usize,
675 used_timestamp_delta: bool,
676 omitted_timestamp: bool,
677 ) {
678 self.side_transport_compact_frames = self.side_transport_compact_frames.saturating_add(1);
679 if used_timestamp_delta {
680 self.side_transport_compact_delta_frames =
681 self.side_transport_compact_delta_frames.saturating_add(1);
682 }
683 if omitted_timestamp {
684 self.side_transport_compact_omitted_timestamp_frames = self
685 .side_transport_compact_omitted_timestamp_frames
686 .saturating_add(1);
687 }
688 self.note_side_transport_bytes(raw_bytes, wire_bytes);
689 self.side_transport_min_compact_overhead_bytes = Some(
690 self.side_transport_min_compact_overhead_bytes
691 .map_or(compact_overhead_bytes, |v| v.min(compact_overhead_bytes)),
692 );
693 self.side_transport_max_compact_overhead_bytes = Some(
694 self.side_transport_max_compact_overhead_bytes
695 .map_or(compact_overhead_bytes, |v| v.max(compact_overhead_bytes)),
696 );
697 }
698
699 fn note_side_transport_chunks(&mut self, chunks: usize) {
700 self.side_transport_chunk_frames = self
701 .side_transport_chunk_frames
702 .saturating_add(chunks as u64);
703 }
704
705 fn note_side_transport_bytes(&mut self, raw_bytes: usize, wire_bytes: usize) {
706 self.side_transport_raw_bytes = self
707 .side_transport_raw_bytes
708 .saturating_add(raw_bytes as u64);
709 self.side_transport_wire_bytes = self
710 .side_transport_wire_bytes
711 .saturating_add(wire_bytes as u64);
712 if raw_bytes > wire_bytes {
713 self.side_transport_bytes_saved = self
714 .side_transport_bytes_saved
715 .saturating_add((raw_bytes - wire_bytes) as u64);
716 }
717 }
718
719 fn note_side_transport_compact_target_miss(&mut self) {
720 self.side_transport_compact_target_misses =
721 self.side_transport_compact_target_misses.saturating_add(1);
722 }
723
724 fn note_side_transport_template_eviction(&mut self) {
725 self.side_transport_template_evictions =
726 self.side_transport_template_evictions.saturating_add(1);
727 }
728}
729
730#[derive(Clone, Copy, Debug, PartialEq, Eq)]
731enum RouteSelectionOrigin {
732 Flood,
733 Discovered,
734}
735
736type PacketHandlerFn = dyn Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static;
739
740type PackedHandlerFn = dyn Fn(&[u8]) -> TelemetryResult<()> + Send + Sync + 'static;
742
743#[derive(Clone)]
749pub enum EndpointHandlerFn {
750 Packet(Arc<PacketHandlerFn>),
751 Packed(Arc<PackedHandlerFn>),
752}
753
754pub struct EndpointHandler {
756 endpoint: DataEndpoint,
757 handler: EndpointHandlerFn,
758}
759
760impl Debug for EndpointHandlerFn {
762 #[inline]
763 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
764 match self {
765 EndpointHandlerFn::Packet(_) => f.write_str("EndpointHandlerFn::Packet(<handler>)"),
766 EndpointHandlerFn::Packed(_) => f.write_str("EndpointHandlerFn::Packed(<handler>)"),
767 }
768 }
769}
770
771#[derive(Clone)]
773pub enum RouterTxHandlerFn {
774 Packed(Arc<PackedHandlerFn>),
775 Packet(Arc<PacketHandlerFn>),
776}
777
778impl Debug for RouterTxHandlerFn {
779 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
780 match self {
781 RouterTxHandlerFn::Packed(_) => f.debug_tuple("Packed").field(&"<handler>").finish(),
782 RouterTxHandlerFn::Packet(_) => f.debug_tuple("Packet").field(&"<handler>").finish(),
783 }
784 }
785}
786
787#[derive(Clone, Copy, Debug)]
788pub struct RouterSideOptions {
789 pub reliable_enabled: bool,
800 pub link_local_enabled: bool,
802 pub header_template_enabled: bool,
809 pub max_frame_bytes: usize,
815 pub compact_header_target_bytes: usize,
822 pub max_side_transport_templates: usize,
828 pub omit_unchanged_compact_timestamps: bool,
834 pub compact_timestamp_omission_types: CompactTimestampOmissionPolicy,
839 pub side_transport_profile: SideTransportProfile,
841 pub ingress_enabled: bool,
843 pub egress_enabled: bool,
845}
846
847impl Default for RouterSideOptions {
848 fn default() -> Self {
849 Self {
850 reliable_enabled: false,
851 link_local_enabled: false,
852 header_template_enabled: false,
853 max_frame_bytes: 0,
854 compact_header_target_bytes: 0,
855 max_side_transport_templates: DEFAULT_SIDE_TRANSPORT_TEMPLATE_LIMIT,
856 omit_unchanged_compact_timestamps: false,
857 compact_timestamp_omission_types: CompactTimestampOmissionPolicy::none(),
858 side_transport_profile: SideTransportProfile::Canonical,
859 ingress_enabled: true,
860 egress_enabled: true,
861 }
862 }
863}
864
865impl RouterSideOptions {
866 #[inline]
871 pub fn with_small_packet_transport(mut self, max_frame_bytes: usize) -> Self {
872 self.header_template_enabled = true;
873 self.max_frame_bytes = max_frame_bytes;
874 self.compact_header_target_bytes = IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES;
875 self.side_transport_profile = SideTransportProfile::Ipv6Like;
876 self
877 }
878
879 #[inline]
880 pub fn with_ipv4_like_compact_header_target(mut self) -> Self {
881 self.header_template_enabled = true;
882 self.compact_header_target_bytes = IPV4_LIKE_COMPACT_HEADER_TARGET_BYTES;
883 self.omit_unchanged_compact_timestamps = true;
884 self.side_transport_profile = SideTransportProfile::Ipv4Like;
885 self
886 }
887
888 #[inline]
889 pub fn with_ipv6_like_compact_header_target(mut self) -> Self {
890 self.header_template_enabled = true;
891 self.compact_header_target_bytes = IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES;
892 self.side_transport_profile = SideTransportProfile::Ipv6Like;
893 self
894 }
895
896 #[inline]
897 pub fn with_template_transport(mut self) -> Self {
898 self.header_template_enabled = true;
899 self.side_transport_profile = SideTransportProfile::Template;
900 self
901 }
902
903 #[inline]
904 pub fn with_omitted_unchanged_compact_timestamps(mut self) -> Self {
905 self.header_template_enabled = true;
906 self.omit_unchanged_compact_timestamps = true;
907 self
908 }
909
910 #[inline]
911 pub fn with_omitted_unchanged_compact_timestamps_for_type(mut self, ty: DataType) -> Self {
912 self.header_template_enabled = true;
913 self.compact_timestamp_omission_types.insert(ty);
914 self
915 }
916
917 #[inline]
918 pub fn effective_transport_profile(self) -> SideTransportProfile {
919 if !self.header_template_enabled && self.max_frame_bytes == 0 {
920 SideTransportProfile::Canonical
921 } else if self.side_transport_profile == SideTransportProfile::Canonical {
922 SideTransportProfile::Template
923 } else {
924 self.side_transport_profile
925 }
926 }
927
928 #[cfg(feature = "discovery")]
929 #[inline]
930 pub fn link_capabilities(self) -> discovery::LinkCapabilities {
931 let mut flags = discovery::LINK_CAPABILITY_END_TO_END_RELIABILITY;
932 if self.header_template_enabled {
933 flags |= discovery::LINK_CAPABILITY_HEADER_TEMPLATES;
934 }
935 if self.max_frame_bytes != 0 {
936 flags |= discovery::LINK_CAPABILITY_CHUNKING;
937 }
938 if self.reliable_enabled {
939 flags |= discovery::LINK_CAPABILITY_RELIABILITY;
940 }
941 if self.omit_unchanged_compact_timestamps
942 || !self.compact_timestamp_omission_types.is_empty()
943 {
944 flags |= discovery::LINK_CAPABILITY_OMIT_UNCHANGED_TIMESTAMPS;
945 }
946 #[cfg(feature = "cryptography")]
947 {
948 flags |= discovery::LINK_CAPABILITY_CRYPTO;
949 }
950 discovery::LinkCapabilities {
951 version: 1,
952 flags,
953 profile: self.effective_transport_profile().discovery_code(),
954 max_frame_bytes: self.max_frame_bytes.min(u32::MAX as usize) as u32,
955 compact_header_target_bytes: self.compact_header_target_bytes.min(u32::MAX as usize)
956 as u32,
957 max_side_transport_templates: self.max_side_transport_templates.min(u32::MAX as usize)
958 as u32,
959 }
960 }
961}
962
963#[derive(Clone, Debug)]
965pub struct RouterSide {
966 pub name: Arc<str>,
967 pub tx_handler: RouterTxHandlerFn,
968 pub opts: RouterSideOptions,
969}
970
971impl Debug for EndpointHandler {
973 #[inline]
974 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
975 f.debug_struct("EndpointHandler")
976 .field("endpoint", &self.endpoint)
977 .field("handler", &self.handler)
978 .finish()
979 }
980}
981
982#[inline]
983pub(crate) const fn endpoint_is_router_internal(endpoint: DataEndpoint) -> bool {
984 #[cfg(feature = "timesync")]
985 if matches!(endpoint, DataEndpoint::TimeSync) {
986 return true;
987 }
988 discovery::is_discovery_endpoint(endpoint)
989}
990
991impl EndpointHandler {
992 #[inline]
996 pub fn new_packet_handler<F>(endpoint: DataEndpoint, f: F) -> Self
997 where
998 F: Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static,
999 {
1000 assert!(
1001 !endpoint_is_router_internal(endpoint),
1002 "reserved internal endpoint handlers must not be user-registered"
1003 );
1004 #[cfg(feature = "std")]
1005 crate::config::ensure_endpoint_id(endpoint, false)
1006 .expect("endpoint handler endpoint registration failed");
1007 Self {
1008 endpoint,
1009 handler: EndpointHandlerFn::Packet(Arc::new(f)),
1010 }
1011 }
1012
1013 #[inline]
1015 #[cfg(feature = "std")]
1016 pub fn new_packet_handler_for<F>(endpoint: crate::config::OwnedEndpointDefinition, f: F) -> Self
1017 where
1018 F: Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static,
1019 {
1020 Self::new_packet_handler(endpoint.id, f)
1021 }
1022
1023 #[cfg(not(feature = "std"))]
1025 #[inline]
1026 pub fn new_packet_handler_for<F>(endpoint: crate::config::EndpointDefinition, f: F) -> Self
1027 where
1028 F: Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static,
1029 {
1030 Self::new_packet_handler(endpoint.id, f)
1031 }
1032
1033 #[cfg(feature = "std")]
1035 #[inline]
1036 pub fn new_packet_handler_by_name<F>(endpoint_name: &str, f: F) -> TelemetryResult<Self>
1037 where
1038 F: Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static,
1039 {
1040 let endpoint = crate::config::endpoint_definition_by_name(endpoint_name)
1041 .ok_or(TelemetryError::BadArg)?;
1042 Ok(Self::new_packet_handler(endpoint.id, f))
1043 }
1044
1045 #[inline]
1049 pub fn new_packed_handler<F>(endpoint: DataEndpoint, f: F) -> Self
1050 where
1051 F: Fn(&[u8]) -> TelemetryResult<()> + Send + Sync + 'static,
1052 {
1053 assert!(
1054 !endpoint_is_router_internal(endpoint),
1055 "reserved internal endpoint handlers must not be user-registered"
1056 );
1057 #[cfg(feature = "std")]
1058 crate::config::ensure_endpoint_id(endpoint, false)
1059 .expect("endpoint handler endpoint registration failed");
1060 Self {
1061 endpoint,
1062 handler: EndpointHandlerFn::Packed(Arc::new(f)),
1063 }
1064 }
1065
1066 #[inline]
1068 pub fn new_packed_handler_for<F>(endpoint: crate::config::EndpointDefinition, f: F) -> Self
1069 where
1070 F: Fn(&[u8]) -> TelemetryResult<()> + Send + Sync + 'static,
1071 {
1072 Self::new_packed_handler(endpoint.id, f)
1073 }
1074
1075 #[cfg(feature = "std")]
1077 #[inline]
1078 pub fn new_packed_handler_by_name<F>(endpoint_name: &str, f: F) -> TelemetryResult<Self>
1079 where
1080 F: Fn(&[u8]) -> TelemetryResult<()> + Send + Sync + 'static,
1081 {
1082 let endpoint = crate::config::endpoint_definition_by_name(endpoint_name)
1083 .ok_or(TelemetryError::BadArg)?;
1084 Ok(Self::new_packed_handler(endpoint.id, f))
1085 }
1086
1087 #[inline]
1089 pub fn get_endpoint(&self) -> DataEndpoint {
1090 self.endpoint
1091 }
1092
1093 #[inline]
1095 pub fn get_handler(&self) -> &EndpointHandlerFn {
1096 &self.handler
1097 }
1098}
1099
1100pub trait Clock {
1101 fn now_ms(&self) -> u64;
1103
1104 fn now_ns(&self) -> u64 {
1108 self.now_ms().saturating_mul(1_000_000)
1109 }
1110}
1111
1112impl<T: Fn() -> u64> Clock for T {
1113 #[inline]
1114 fn now_ms(&self) -> u64 {
1115 self()
1116 }
1117}
1118
1119#[cfg(feature = "std")]
1120#[derive(Debug)]
1121struct StdMonotonicClock {
1122 start: Instant,
1123}
1124
1125#[cfg(feature = "std")]
1126impl Default for StdMonotonicClock {
1127 fn default() -> Self {
1128 Self {
1129 start: Instant::now(),
1130 }
1131 }
1132}
1133
1134#[cfg(feature = "std")]
1135impl Clock for StdMonotonicClock {
1136 fn now_ms(&self) -> u64 {
1137 u64::try_from(self.start.elapsed().as_millis()).unwrap_or(u64::MAX)
1138 }
1139
1140 fn now_ns(&self) -> u64 {
1141 u64::try_from(self.start.elapsed().as_nanos()).unwrap_or(u64::MAX)
1142 }
1143}
1144
1145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1147pub enum RouterE2eEncryptionMode {
1148 Disabled,
1150 RequiredOnly,
1152 Preferred,
1154 ForceAll,
1156}
1157
1158pub type NodeAddress = u32;
1159pub type P2pPort = u16;
1160pub type P2pStreamId = u32;
1161
1162const P2P_STREAM_MAGIC: [u8; 4] = *b"SDSP";
1163const P2P_STREAM_VERSION: u8 = 1;
1164const P2P_STREAM_SYN: u8 = 0x01;
1165const P2P_STREAM_ACK: u8 = 0x02;
1166const P2P_STREAM_FIN: u8 = 0x04;
1167const P2P_STREAM_RST: u8 = 0x08;
1168const P2P_STREAM_DATA: u8 = 0x10;
1169
1170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1171pub enum AddressAssignmentMode {
1172 Dynamic,
1173 Requested(NodeAddress),
1174 Static(NodeAddress),
1175}
1176
1177impl AddressAssignmentMode {
1178 #[inline]
1179 fn mode_code(self) -> u8 {
1180 match self {
1181 Self::Dynamic => 0,
1182 Self::Requested(_) => 1,
1183 Self::Static(_) => 2,
1184 }
1185 }
1186
1187 #[inline]
1188 fn requested_address(self) -> NodeAddress {
1189 match self {
1190 Self::Dynamic => 0,
1191 Self::Requested(addr) | Self::Static(addr) => addr,
1192 }
1193 }
1194}
1195
1196#[derive(Debug, Clone, PartialEq, Eq)]
1197pub enum AddressChangeReason {
1198 Configured,
1199 DynamicConflict,
1200 RequestedConflict,
1201 StaticConflict,
1202 HostnameConflict,
1203}
1204
1205#[derive(Debug, Clone, PartialEq, Eq)]
1206pub struct AddressChange {
1207 pub old_hostname: Arc<str>,
1208 pub new_hostname: Arc<str>,
1209 pub old_address: NodeAddress,
1210 pub new_address: NodeAddress,
1211 pub reason: AddressChangeReason,
1212}
1213
1214#[derive(Debug, Clone, PartialEq, Eq)]
1215pub struct AddressBookEntry {
1216 pub hostname: Arc<str>,
1217 pub address: NodeAddress,
1218 pub requested_address: NodeAddress,
1219 pub mode: AddressAssignmentMode,
1220 pub birth_ms: u64,
1221 pub owner_hash: u64,
1222 pub last_seen_ms: u64,
1223}
1224
1225pub struct P2pMessage<'a> {
1226 pub source_hostname: &'a str,
1227 pub source_address: NodeAddress,
1228 pub source_port: P2pPort,
1229 pub destination_port: P2pPort,
1230 pub payload: &'a [u8],
1231}
1232
1233#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1234pub enum P2pStreamEventKind {
1235 Accepted,
1236 Connected,
1237 Data,
1238 Closed,
1239 Reset,
1240}
1241
1242pub struct P2pStreamEvent<'a> {
1243 pub kind: P2pStreamEventKind,
1244 pub stream_id: P2pStreamId,
1245 pub peer_stream_id: P2pStreamId,
1246 pub sequence: u32,
1247 pub peer_hostname: &'a str,
1248 pub peer_address: NodeAddress,
1249 pub local_port: P2pPort,
1250 pub peer_port: P2pPort,
1251 pub payload: &'a [u8],
1252}
1253
1254struct P2pDecoded<'a> {
1255 source_hostname: &'a str,
1256 source_address: NodeAddress,
1257 source_port: P2pPort,
1258 destination_port: P2pPort,
1259 payload: &'a [u8],
1260}
1261
1262#[derive(Debug, Clone)]
1263struct P2pStreamDecoded<'a> {
1264 flags: u8,
1265 source_stream_id: P2pStreamId,
1266 destination_stream_id: P2pStreamId,
1267 sequence: u32,
1268 payload: &'a [u8],
1269}
1270
1271type AddressChangeFn = dyn Fn(AddressChange) -> TelemetryResult<()> + Send + Sync + 'static;
1272
1273#[derive(Clone)]
1274struct AddressChangeHandler {
1275 handler: Arc<AddressChangeFn>,
1276}
1277
1278impl Debug for AddressChangeHandler {
1279 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1280 f.write_str("AddressChangeHandler(<handler>)")
1281 }
1282}
1283
1284type P2pPortHandlerFn = dyn Fn(P2pMessage<'_>) -> TelemetryResult<()> + Send + Sync + 'static;
1285
1286#[derive(Clone)]
1287struct P2pPortHandler {
1288 handler: Arc<P2pPortHandlerFn>,
1289}
1290
1291impl Debug for P2pPortHandler {
1292 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1293 f.write_str("P2pPortHandler(<handler>)")
1294 }
1295}
1296
1297type P2pStreamHandlerFn = dyn Fn(P2pStreamEvent<'_>) -> TelemetryResult<()> + Send + Sync + 'static;
1298
1299#[derive(Clone)]
1300struct P2pStreamHandler {
1301 handler: Arc<P2pStreamHandlerFn>,
1302}
1303
1304impl Debug for P2pStreamHandler {
1305 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1306 f.write_str("P2pStreamHandler(<handler>)")
1307 }
1308}
1309
1310#[derive(Debug, Clone)]
1311struct P2pStreamSession {
1312 peer_hostname: Arc<str>,
1313 peer_address: NodeAddress,
1314 local_port: P2pPort,
1315 peer_port: P2pPort,
1316 peer_stream_id: P2pStreamId,
1317 next_sequence: u32,
1318 connected: bool,
1319}
1320
1321#[derive(Debug, Clone)]
1322struct PendingP2pStreamEvent {
1323 handlers: Vec<P2pStreamHandler>,
1324 kind: P2pStreamEventKind,
1325 stream_id: P2pStreamId,
1326 peer_stream_id: P2pStreamId,
1327 peer_hostname: Arc<str>,
1328 peer_address: NodeAddress,
1329 local_port: P2pPort,
1330 peer_port: P2pPort,
1331}
1332
1333#[derive(Debug, Clone)]
1334pub struct RouterConfig {
1335 handlers: Arc<[EndpointHandler]>,
1337 reliable_enabled: bool,
1339 sender: Option<Arc<str>>,
1341 address_mode: AddressAssignmentMode,
1343 address_change_handlers: Arc<[AddressChangeHandler]>,
1345 e2e_encryption: RouterE2eEncryptionMode,
1347 #[cfg_attr(not(feature = "cryptography"), allow(dead_code))]
1349 e2e_key_id: u32,
1350 memory: RuntimeMemoryConfig,
1351 #[cfg(feature = "timesync")]
1352 timesync: Option<TimeSyncConfig>,
1353}
1354
1355impl RouterConfig {
1356 pub fn default_e2e_encryption_mode() -> RouterE2eEncryptionMode {
1361 #[cfg(feature = "cryptography")]
1362 {
1363 RouterE2eEncryptionMode::Preferred
1364 }
1365 #[cfg(not(feature = "cryptography"))]
1366 {
1367 RouterE2eEncryptionMode::Disabled
1368 }
1369 }
1370
1371 pub fn new<H>(handlers: H) -> Self
1373 where
1374 H: Into<Arc<[EndpointHandler]>>,
1375 {
1376 let handlers: Arc<[EndpointHandler]> = handlers.into();
1377 assert!(
1378 handlers
1379 .iter()
1380 .all(|handler| !endpoint_is_router_internal(handler.endpoint)),
1381 "reserved internal endpoint handlers must not be user-registered"
1382 );
1383 Self {
1384 handlers,
1385 reliable_enabled: true,
1386 sender: None,
1387 address_mode: AddressAssignmentMode::Dynamic,
1388 address_change_handlers: Arc::from([]),
1389 e2e_encryption: Self::default_e2e_encryption_mode(),
1390 e2e_key_id: 0,
1391 memory: RuntimeMemoryConfig::default(),
1392 #[cfg(feature = "timesync")]
1393 timesync: None,
1394 }
1395 }
1396
1397 pub fn with_reliable_enabled(mut self, enabled: bool) -> Self {
1399 self.reliable_enabled = enabled;
1400 self
1401 }
1402
1403 pub fn with_sender<S: AsRef<str>>(mut self, sender: S) -> Self {
1405 self.sender = Some(Arc::from(sender.as_ref()));
1406 self
1407 }
1408
1409 pub fn with_hostname<S: AsRef<str>>(self, hostname: S) -> Self {
1411 self.with_sender(hostname)
1412 }
1413
1414 pub fn with_dynamic_address(mut self) -> Self {
1416 self.address_mode = AddressAssignmentMode::Dynamic;
1417 self
1418 }
1419
1420 pub fn with_requested_address(mut self, address: NodeAddress) -> Self {
1422 self.address_mode = AddressAssignmentMode::Requested(address);
1423 self
1424 }
1425
1426 pub fn with_static_address(mut self, address: NodeAddress) -> Self {
1428 self.address_mode = AddressAssignmentMode::Static(address);
1429 self
1430 }
1431
1432 pub fn on_address_change<F>(mut self, f: F) -> Self
1434 where
1435 F: Fn(AddressChange) -> TelemetryResult<()> + Send + Sync + 'static,
1436 {
1437 let mut handlers = self.address_change_handlers.to_vec();
1438 handlers.push(AddressChangeHandler {
1439 handler: Arc::new(f),
1440 });
1441 self.address_change_handlers = Arc::from(handlers);
1442 self
1443 }
1444
1445 pub fn with_e2e_encryption(mut self, mode: RouterE2eEncryptionMode) -> Self {
1447 self.e2e_encryption = mode;
1448 self
1449 }
1450
1451 pub fn with_e2e_key_id(mut self, key_id: u32) -> Self {
1453 self.e2e_key_id = key_id;
1454 self
1455 }
1456
1457 pub fn with_memory_config(mut self, memory: RuntimeMemoryConfig) -> TelemetryResult<Self> {
1459 memory.validate()?;
1460 self.memory = memory;
1461 Ok(self)
1462 }
1463
1464 #[cfg(feature = "timesync")]
1465 pub fn with_timesync(mut self, cfg: TimeSyncConfig) -> Self {
1467 self.timesync = Some(cfg);
1468 self
1469 }
1470
1471 #[inline]
1472 fn is_local_endpoint(&self, ep: DataEndpoint) -> bool {
1474 if endpoint_is_router_internal(ep) {
1475 return false;
1476 }
1477 self.handlers.iter().any(|h| h.endpoint == ep)
1478 }
1479
1480 #[inline]
1481 fn reliable_enabled(&self) -> bool {
1482 self.reliable_enabled
1483 }
1484
1485 #[inline]
1486 fn sender(&self) -> String {
1487 self.sender
1488 .as_deref()
1489 .map(ToString::to_string)
1490 .unwrap_or_else(runtime_device_identifier)
1491 }
1492
1493 #[inline]
1494 fn address_mode(&self) -> AddressAssignmentMode {
1495 self.address_mode
1496 }
1497
1498 #[inline]
1499 fn e2e_encryption(&self) -> RouterE2eEncryptionMode {
1500 self.e2e_encryption
1501 }
1502
1503 #[cfg(feature = "cryptography")]
1504 #[inline]
1505 fn e2e_key_id(&self) -> u32 {
1506 self.e2e_key_id
1507 }
1508
1509 #[cfg(feature = "timesync")]
1510 #[inline]
1511 fn timesync_config(&self) -> Option<TimeSyncConfig> {
1512 self.timesync
1513 }
1514
1515 #[inline]
1516 fn memory_config(&self) -> RuntimeMemoryConfig {
1517 self.memory
1518 }
1519}
1520
1521impl Default for RouterConfig {
1522 fn default() -> Self {
1523 Self {
1524 handlers: Arc::from([]),
1525 reliable_enabled: true,
1526 sender: None,
1527 address_mode: AddressAssignmentMode::Dynamic,
1528 address_change_handlers: Arc::from([]),
1529 e2e_encryption: Self::default_e2e_encryption_mode(),
1530 e2e_key_id: 0,
1531 memory: RuntimeMemoryConfig::default(),
1532 #[cfg(feature = "timesync")]
1533 timesync: None,
1534 }
1535 }
1536}
1537
1538pub trait LeBytes: Copy + Sized {
1541 const WIDTH: usize;
1542 fn write_le(self, out: &mut [u8]);
1543 fn from_le_slice(bytes: &[u8]) -> Self;
1544}
1545
1546impl_letype_num!(u8, 1);
1547impl_letype_num!(u16, 2);
1548impl_letype_num!(u32, 4);
1549impl_letype_num!(u64, 8);
1550impl_letype_num!(u128, 16);
1551impl_letype_num!(i8, 1);
1552impl_letype_num!(i16, 2);
1553impl_letype_num!(i32, 4);
1554impl_letype_num!(i64, 8);
1555impl_letype_num!(i128, 16);
1556impl_letype_num!(f32, 4);
1557impl_letype_num!(f64, 8);
1558
1559pub(crate) fn encode_slice_le<T: LeBytes>(data: &[T]) -> Arc<[u8]> {
1561 let total = data.len() * T::WIDTH;
1562 let mut buf = vec![0u8; total];
1563
1564 for (i, v) in data.iter().copied().enumerate() {
1565 let start = i * T::WIDTH;
1566 v.write_le(&mut buf[start..start + T::WIDTH]);
1567 }
1568
1569 Arc::from(buf)
1570}
1571
1572fn make_error_payload(msg: &str) -> Arc<[u8]> {
1575 let meta = message_meta(DataType::TelemetryError);
1576 match meta.element {
1577 MessageElement::Static(_, _, _) => {
1578 let max = get_needed_message_size(DataType::TelemetryError);
1579 let bytes = msg.as_bytes();
1580 let n = core::cmp::min(max, bytes.len());
1581 let mut buf = vec![0u8; max];
1582 if n > 0 {
1583 buf[..n].copy_from_slice(&bytes[..n]);
1584 }
1585 Arc::from(buf)
1586 }
1587 MessageElement::Dynamic(_, _) => Arc::from(msg.as_bytes()),
1588 }
1589}
1590
1591fn log_raw<T, F>(
1595 sender: &str,
1596 ty: DataType,
1597 data: &[T],
1598 timestamp: u64,
1599 mut tx_function: F,
1600) -> TelemetryResult<()>
1601where
1602 T: LeBytes,
1603 F: FnMut(Packet) -> TelemetryResult<()>,
1604{
1605 let meta = message_meta(ty);
1606 let got = data.len() * T::WIDTH;
1607
1608 match meta.element {
1609 MessageElement::Static(_, _, _) => {
1610 if got != get_needed_message_size(ty) {
1611 return Err(TelemetryError::SizeMismatch {
1612 expected: get_needed_message_size(ty),
1613 got,
1614 });
1615 }
1616 }
1617 MessageElement::Dynamic(_, _) => {
1618 if !got.is_multiple_of(T::WIDTH) {
1620 return Err(TelemetryError::SizeMismatch {
1621 expected: T::WIDTH,
1622 got,
1623 });
1624 }
1625 }
1626 }
1627
1628 let payload = encode_slice_le(data);
1629 let pkt = Packet::new(ty, meta.endpoints_ref(), sender, timestamp, payload)?;
1630 tx_function(pkt)
1631}
1632
1633fn fallback_stdout(_msg: &str) {
1637 #[cfg(feature = "std")]
1638 {
1639 eprintln!("{}", _msg);
1640 }
1641 #[cfg(all(not(feature = "std"), target_os = "none"))]
1642 {
1643 let message = format!("{}\n", _msg);
1644 unsafe {
1645 seds_error_msg(message.as_ptr(), message.len());
1646 }
1647 }
1648}
1649
1650#[derive(Debug, Clone)]
1655struct RouterInner {
1656 memory: RuntimeMemoryConfig,
1657 sides: Vec<Option<RouterSide>>,
1658 route_overrides: BTreeMap<(Option<RouterSideId>, RouterSideId), bool>,
1659 typed_route_overrides: BTreeMap<(Option<RouterSideId>, u32, RouterSideId), bool>,
1660 route_weights: BTreeMap<(Option<RouterSideId>, RouterSideId), u32>,
1661 route_priorities: BTreeMap<(Option<RouterSideId>, RouterSideId), u32>,
1662 source_route_modes: BTreeMap<Option<RouterSideId>, RouteSelectionMode>,
1663 route_selection_cursors: BTreeMap<Option<RouterSideId>, u64>,
1664 adaptive_route_stats: BTreeMap<RouterSideId, AdaptiveRouteStats>,
1665 side_runtime_stats: BTreeMap<RouterSideId, SideRuntimeStatsInner>,
1666 side_transport: BTreeMap<RouterSideId, SideTransportState>,
1667 managed_variable_types: BTreeSet<u32>,
1668 managed_variable_permissions: BTreeMap<u32, NetworkVariablePermissions>,
1669 managed_variable_latest: BTreeMap<u32, ManagedVariableCacheEntry>,
1670 network_variable_update_handlers: BTreeMap<u32, Vec<NetworkVariableUpdateHandler>>,
1671 local_address: AddressBookEntry,
1672 address_book: BTreeMap<String, AddressBookEntry>,
1673 address_by_value: BTreeMap<NodeAddress, String>,
1674 p2p_port_handlers: BTreeMap<P2pPort, Vec<P2pPortHandler>>,
1675 p2p_stream_handlers: BTreeMap<P2pPort, Vec<P2pStreamHandler>>,
1676 p2p_stream_sessions: BTreeMap<P2pStreamId, P2pStreamSession>,
1677 next_p2p_stream_id: P2pStreamId,
1678 received_queue: BoundedDeque<RouterRxItem>,
1679 transmit_queue: BoundedDeque<TxQueued>,
1680 tx_priority_burst: u8,
1681 recent_rx: BoundedDeque<u64>,
1682 reliable_tx: BTreeMap<(RouterSideId, u32), ReliableTxState>,
1683 reliable_rx: BTreeMap<(RouterSideId, u32), ReliableRxState>,
1684 reliable_return_routes: BTreeMap<u64, ReliableReturnRouteState>,
1685 reliable_return_route_order: VecDeque<u64>,
1686 end_to_end_reliable_tx: BTreeMap<u64, EndToEndReliableSent>,
1687 end_to_end_reliable_tx_order: VecDeque<u64>,
1688 total_handler_failures: u64,
1689 total_handler_retries: u64,
1690 #[cfg(feature = "discovery")]
1691 discovery_routes: BTreeMap<RouterSideId, DiscoverySideState>,
1692 #[cfg(feature = "discovery")]
1693 discovery_cadence: DiscoveryCadenceState,
1694 #[cfg(feature = "discovery")]
1695 discovery_side_throttle: BTreeMap<RouterSideId, DiscoverySideThrottleState>,
1696 #[cfg(all(feature = "discovery", feature = "timesync"))]
1697 timesync_side_throttle: BTreeMap<RouterSideId, TimeSyncSideThrottleState>,
1698}
1699
1700#[derive(Debug, Clone)]
1701struct ManagedVariableCacheEntry {
1702 packet: Packet,
1703 cached_at_ms: u64,
1704}
1705
1706type NetworkVariableUpdateFn = dyn Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static;
1707
1708#[derive(Clone)]
1709struct NetworkVariableUpdateHandler {
1710 handler: Arc<NetworkVariableUpdateFn>,
1711}
1712
1713impl Debug for NetworkVariableUpdateHandler {
1714 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1715 f.write_str("NetworkVariableUpdateHandler(<handler>)")
1716 }
1717}
1718
1719#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1721pub struct NetworkVariablePermissions {
1722 pub read: bool,
1723 pub write: bool,
1724}
1725
1726impl NetworkVariablePermissions {
1727 pub const NONE: Self = Self {
1728 read: false,
1729 write: false,
1730 };
1731 pub const READ_ONLY: Self = Self {
1732 read: true,
1733 write: false,
1734 };
1735 pub const WRITE_ONLY: Self = Self {
1736 read: false,
1737 write: true,
1738 };
1739 pub const READ_WRITE: Self = Self {
1740 read: true,
1741 write: true,
1742 };
1743}
1744
1745#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1746enum RouterQueueKind {
1747 Received,
1748 Transmit,
1749 Recent,
1750 ReliableRxBuffer,
1751 #[cfg(feature = "discovery")]
1752 Discovery,
1753}
1754
1755impl RouterInner {
1756 #[cfg(feature = "discovery")]
1757 fn topology_board_byte_cost(board: &TopologyBoardNode) -> usize {
1758 board
1759 .sender_id
1760 .len()
1761 .saturating_add(board.reachable_endpoints.len() * size_of::<DataEndpoint>())
1762 .saturating_add(
1763 board
1764 .reachable_timesync_sources
1765 .iter()
1766 .map(|s| s.len())
1767 .sum::<usize>(),
1768 )
1769 .saturating_add(board.connections.iter().map(|s| s.len()).sum::<usize>())
1770 }
1771
1772 #[cfg(feature = "discovery")]
1773 fn discovery_sender_byte_cost(sender: &str, state: &DiscoverySenderState) -> usize {
1774 sender
1775 .len()
1776 .saturating_add(state.reachable.len() * size_of::<DataEndpoint>())
1777 .saturating_add(state.reachable_network_variables.len() * size_of::<DataType>())
1778 .saturating_add(
1779 state
1780 .reachable_timesync_sources
1781 .iter()
1782 .map(|s| s.len())
1783 .sum::<usize>(),
1784 )
1785 .saturating_add(
1786 state
1787 .topology_boards
1788 .iter()
1789 .map(Self::topology_board_byte_cost)
1790 .sum::<usize>(),
1791 )
1792 .saturating_add(size_of::<DiscoverySenderState>())
1793 }
1794
1795 #[cfg(feature = "discovery")]
1796 fn discovery_route_byte_cost(side: RouterSideId, route: &DiscoverySideState) -> usize {
1797 size_of::<RouterSideId>()
1798 .saturating_add(size_of::<DiscoverySideState>())
1799 .saturating_add(route.reachable.len() * size_of::<DataEndpoint>())
1800 .saturating_add(route.reachable_network_variables.len() * size_of::<DataType>())
1801 .saturating_add(
1802 route
1803 .reachable_timesync_sources
1804 .iter()
1805 .map(|s| s.len())
1806 .sum::<usize>(),
1807 )
1808 .saturating_add(
1809 route
1810 .announcers
1811 .iter()
1812 .map(|(sender, state)| Self::discovery_sender_byte_cost(sender, state))
1813 .sum::<usize>(),
1814 )
1815 .saturating_add(side.saturating_sub(side))
1816 }
1817
1818 #[cfg(feature = "discovery")]
1819 fn discovery_bytes_used(&self) -> usize {
1820 self.discovery_routes
1821 .iter()
1822 .map(|(side, route)| Self::discovery_route_byte_cost(*side, route))
1823 .sum()
1824 }
1825
1826 #[inline]
1827 fn reliable_rx_buffered_bytes(&self) -> usize {
1828 self.reliable_rx
1829 .values()
1830 .flat_map(|state| state.buffered.values())
1831 .map(|bytes| size_of::<Arc<[u8]>>() + bytes.len())
1832 .sum()
1833 }
1834
1835 #[inline]
1836 fn shared_queue_bytes_used(&self) -> usize {
1837 self.received_queue
1838 .bytes_used()
1839 .saturating_add(self.transmit_queue.bytes_used())
1840 .saturating_add(self.recent_rx.max_bytes())
1841 .saturating_add(self.reliable_rx_buffered_bytes())
1842 .saturating_add(crate::config::schema_bytes_used())
1843 .saturating_add({
1844 #[cfg(feature = "discovery")]
1845 {
1846 self.discovery_bytes_used()
1847 }
1848 #[cfg(not(feature = "discovery"))]
1849 {
1850 0
1851 }
1852 })
1853 }
1854
1855 fn reliable_rx_buffer_len(&self) -> usize {
1856 self.reliable_rx
1857 .values()
1858 .map(|state| state.buffered.len())
1859 .sum()
1860 }
1861
1862 fn pop_reliable_rx_buffered(&mut self) -> Option<Arc<[u8]>> {
1863 let key = self
1864 .reliable_rx
1865 .iter()
1866 .find_map(|(key, state)| (!state.buffered.is_empty()).then_some(*key))?;
1867 self.reliable_rx
1868 .get_mut(&key)?
1869 .buffered
1870 .pop_first()
1871 .map(|(_, v)| v)
1872 }
1873
1874 fn pop_shared_queue_item(&mut self, preferred: RouterQueueKind) -> bool {
1875 match preferred {
1876 RouterQueueKind::Received => self.received_queue.pop_front().is_some(),
1877 RouterQueueKind::Transmit => self.transmit_queue.pop_front().is_some(),
1878 RouterQueueKind::Recent => self.recent_rx.pop_front().is_some(),
1879 RouterQueueKind::ReliableRxBuffer => self.pop_reliable_rx_buffered().is_some(),
1880 #[cfg(feature = "discovery")]
1881 RouterQueueKind::Discovery => self.pop_discovery_route(),
1882 }
1883 }
1884
1885 #[cfg(feature = "discovery")]
1886 fn pop_discovery_route(&mut self) -> bool {
1887 let Some((&side, _)) = self
1888 .discovery_routes
1889 .iter()
1890 .min_by_key(|(_, route)| route.last_seen_ms)
1891 else {
1892 return false;
1893 };
1894 self.discovery_routes.remove(&side);
1895 Self::queue_budget_warning("topology route evicted because shared queue budget is full");
1896 true
1897 }
1898
1899 fn largest_shared_queue(&self) -> Option<RouterQueueKind> {
1900 let candidates = [
1901 (
1902 RouterQueueKind::Received,
1903 self.received_queue.bytes_used(),
1904 self.received_queue.len(),
1905 ),
1906 (
1907 RouterQueueKind::Transmit,
1908 self.transmit_queue.bytes_used(),
1909 self.transmit_queue.len(),
1910 ),
1911 (RouterQueueKind::Recent, 0, 0),
1912 (
1913 RouterQueueKind::ReliableRxBuffer,
1914 self.reliable_rx_buffered_bytes(),
1915 self.reliable_rx_buffer_len(),
1916 ),
1917 #[cfg(feature = "discovery")]
1918 (
1919 RouterQueueKind::Discovery,
1920 self.discovery_bytes_used(),
1921 self.discovery_routes.len(),
1922 ),
1923 ];
1924 candidates
1925 .into_iter()
1926 .filter(|(_, bytes, len)| *bytes > 0 && *len > 0)
1927 .max_by_key(|(kind, bytes, _)| {
1928 (
1929 *bytes,
1930 if *kind == RouterQueueKind::ReliableRxBuffer {
1931 0
1932 } else {
1933 1
1934 },
1935 )
1936 })
1937 .map(|(kind, _, _)| kind)
1938 }
1939
1940 fn make_shared_queue_room(
1941 &mut self,
1942 incoming_cost: usize,
1943 preferred: RouterQueueKind,
1944 ) -> TelemetryResult<()> {
1945 if incoming_cost > self.memory.max_queue_budget {
1946 return Err(TelemetryError::PacketTooLarge(
1947 "Item exceeds maximum shared queue budget",
1948 ));
1949 }
1950
1951 while self.shared_queue_bytes_used().saturating_add(incoming_cost)
1952 > self.memory.max_queue_budget
1953 {
1954 let victim = self.largest_shared_queue().unwrap_or(preferred);
1955 if victim == RouterQueueKind::Discovery {
1956 Self::queue_budget_warning("topology data is using the largest queue budget share");
1957 }
1958 if !self.pop_shared_queue_item(victim) && !self.pop_shared_queue_item(preferred) {
1959 return Err(TelemetryError::PacketTooLarge(
1960 "Item exceeds maximum shared queue budget",
1961 ));
1962 }
1963 }
1964
1965 Ok(())
1966 }
1967
1968 #[inline]
1969 fn queue_budget_warning(msg: &str) {
1970 #[cfg(feature = "std")]
1971 eprintln!("sedsnet queue budget warning: {msg}");
1972 let _ = msg;
1973 }
1974
1975 #[cfg(feature = "discovery")]
1976 fn fit_discovery_budget(&mut self) {
1977 while self.shared_queue_bytes_used() > self.memory.max_queue_budget {
1978 if !self.pop_discovery_route() {
1979 break;
1980 }
1981 }
1982 }
1983
1984 fn push_received(&mut self, item: RouterRxItem) -> TelemetryResult<()> {
1985 self.make_shared_queue_room(item.byte_cost(), RouterQueueKind::Received)?;
1986 self.received_queue
1987 .push_back_prioritized(item, |queued| queued.priority)
1988 }
1989
1990 fn push_transmit(&mut self, item: TxQueued) -> TelemetryResult<()> {
1991 self.make_shared_queue_room(item.byte_cost(), RouterQueueKind::Transmit)?;
1992 self.transmit_queue
1993 .push_back_prioritized(item, |queued| queued.priority)
1994 }
1995
1996 fn push_recent_rx(&mut self, id: u64) -> TelemetryResult<()> {
1997 while self.recent_rx.len() >= self.memory.max_recent_rx_ids {
1998 let _ = self.recent_rx.pop_front();
1999 }
2000 self.make_shared_queue_room(0, RouterQueueKind::Recent)?;
2001 self.recent_rx.push_back(id)
2002 }
2003
2004 fn buffer_reliable_rx(
2005 &mut self,
2006 side: RouterSideId,
2007 ty: DataType,
2008 seq: u32,
2009 bytes: Arc<[u8]>,
2010 ) -> TelemetryResult<()> {
2011 let key = Router::reliable_key(side, ty);
2012 if self
2013 .reliable_rx
2014 .get(&key)
2015 .is_some_and(|state| state.buffered.contains_key(&seq))
2016 {
2017 return Ok(());
2018 }
2019 let cost = size_of::<Arc<[u8]>>() + bytes.len();
2020 self.make_shared_queue_room(cost, RouterQueueKind::ReliableRxBuffer)?;
2021 let rx_state = self
2022 .reliable_rx
2023 .entry(key)
2024 .or_insert_with(|| ReliableRxState {
2025 expected_seq: 1,
2026 buffered: BTreeMap::new(),
2027 });
2028 if rx_state.buffered.len() >= runtime_reliable_max_pending() {
2029 let _ = rx_state.buffered.pop_first();
2030 }
2031 rx_state.buffered.insert(seq, bytes);
2032 Ok(())
2033 }
2034}
2035
2036struct IsrRxQueue {
2041 busy: AtomicBool,
2042 q: UnsafeCell<BoundedDeque<RouterRxItem>>,
2043}
2044
2045unsafe impl Send for IsrRxQueue {}
2046unsafe impl Sync for IsrRxQueue {}
2047
2048struct IsrRxQueueGuard<'a> {
2049 owner: &'a IsrRxQueue,
2050}
2051
2052impl Deref for IsrRxQueueGuard<'_> {
2053 type Target = BoundedDeque<RouterRxItem>;
2054
2055 #[inline]
2056 fn deref(&self) -> &Self::Target {
2057 unsafe { &*self.owner.q.get() }
2058 }
2059}
2060
2061impl DerefMut for IsrRxQueueGuard<'_> {
2062 #[inline]
2063 fn deref_mut(&mut self) -> &mut Self::Target {
2064 unsafe { &mut *self.owner.q.get() }
2065 }
2066}
2067
2068impl Drop for IsrRxQueueGuard<'_> {
2069 #[inline]
2070 fn drop(&mut self) {
2071 self.owner.busy.store(false, Ordering::Release);
2072 }
2073}
2074
2075impl IsrRxQueue {
2076 #[inline]
2077 fn new(max_bytes: usize, starting_bytes: usize, grow_mult: f64) -> Self {
2078 Self {
2079 busy: AtomicBool::new(false),
2080 q: UnsafeCell::new(BoundedDeque::new(max_bytes, starting_bytes, grow_mult)),
2081 }
2082 }
2083
2084 #[inline]
2085 fn try_lock(&self) -> TelemetryResult<IsrRxQueueGuard<'_>> {
2086 match self
2087 .busy
2088 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
2089 {
2090 Ok(_) => Ok(IsrRxQueueGuard { owner: self }),
2091 Err(_) => Err(TelemetryError::Io("rx queue busy")),
2092 }
2093 }
2094
2095 #[allow(dead_code)]
2096 #[inline]
2097 fn push_back(&self, item: RouterRxItem) -> TelemetryResult<()> {
2098 let mut g = self.try_lock()?;
2099 g.push_back(item)
2100 }
2101
2102 #[inline]
2103 fn push_back_prioritized(&self, item: RouterRxItem) -> TelemetryResult<()> {
2104 let mut g = self.try_lock()?;
2105 g.push_back_prioritized(item, |queued| queued.priority)
2106 }
2107
2108 #[inline]
2109 fn pop_front(&self) -> TelemetryResult<Option<RouterRxItem>> {
2110 let mut g = self.try_lock()?;
2111 Ok(g.pop_front())
2112 }
2113
2114 #[inline]
2115 fn clear(&self) -> TelemetryResult<()> {
2116 let mut g = self.try_lock()?;
2117 g.clear();
2118 Ok(())
2119 }
2120
2121 #[inline]
2122 fn snapshot(&self) -> Option<(usize, usize)> {
2123 let g = self.try_lock().ok()?;
2124 Some((g.len(), g.bytes_used()))
2125 }
2126}
2127
2128pub struct Router {
2132 sender: RouterMutex<Arc<str>>,
2133 cfg: RouterConfig,
2134 state: RouterMutex<RouterInner>,
2135 isr_rx_queue: IsrRxQueue,
2136 side_tx_gate: ReentryGate,
2137 clock: Box<dyn Clock + Send + Sync>,
2138 #[cfg(feature = "timesync")]
2139 timesync: RouterMutex<TimeSyncRuntime>,
2140}
2141
2142#[cfg(feature = "timesync")]
2143#[derive(Debug, Clone)]
2144struct PendingTimeSyncRequest {
2145 seq: u64,
2146 t1_mono_ms: u64,
2147 source: String,
2148}
2149
2150#[cfg(feature = "timesync")]
2151#[derive(Debug, Clone)]
2152struct RemoteTimeSyncSource {
2153 priority: u64,
2154 last_sample_mono_ms: u64,
2155 sample_unix_ms: u64,
2156}
2157
2158#[cfg(feature = "timesync")]
2159#[derive(Debug, Clone)]
2160struct TimeSyncRuntime {
2161 cfg: Option<TimeSyncConfig>,
2162 tracker: Option<TimeSyncTracker>,
2163 clock: NetworkClock,
2164 disciplined_clock: SlewedNetworkClock,
2165 remote_sources: BTreeMap<String, RemoteTimeSyncSource>,
2166 next_seq: u64,
2167 next_announce_mono_ms: u64,
2168 next_request_mono_ms: u64,
2169 pending_request: Option<PendingTimeSyncRequest>,
2170}
2171
2172#[cfg(feature = "timesync")]
2173impl TimeSyncRuntime {
2174 fn new(cfg: Option<TimeSyncConfig>) -> Self {
2175 Self {
2176 tracker: cfg.map(TimeSyncTracker::new),
2177 cfg,
2178 clock: NetworkClock::default(),
2179 disciplined_clock: SlewedNetworkClock::new(
2180 cfg.map(|c| c.max_slew_ppm)
2181 .unwrap_or(TimeSyncConfig::default().max_slew_ppm),
2182 ),
2183 remote_sources: BTreeMap::new(),
2184 next_seq: 1,
2185 next_announce_mono_ms: 0,
2186 next_request_mono_ms: 0,
2187 pending_request: None,
2188 }
2189 }
2190}
2191
2192enum RemoteSidePlan {
2193 Target(Vec<RouterSideId>),
2194}
2195
2196#[cfg(feature = "discovery")]
2197#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2198struct DiscoveryCandidateMatch {
2199 side: RouterSideId,
2200 overlap: usize,
2201}
2202
2203#[cfg(feature = "discovery")]
2204#[inline]
2205const fn discovery_is_hop_local_advertisement(ty: DataType) -> bool {
2206 matches!(
2207 ty,
2208 DataType::DiscoveryAnnounce
2209 | DataType::DiscoveryTimeSyncSources
2210 | DataType::DiscoveryTopology
2211 | DataType::DiscoveryAddress
2212 | DataType::DiscoveryLinkCapabilities
2213 )
2214}
2215
2216impl Debug for Router {
2217 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2218 let sender = self.sender();
2219 f.debug_struct("Router")
2220 .field("sender", &sender)
2221 .field("cfg", &self.cfg)
2222 .field("state", &"<mutex>")
2223 .field("clock", &"Clock")
2224 .finish()
2225 }
2226}
2227
2228#[inline]
2231fn has_nonlocal_endpoint(eps: &[DataEndpoint], cfg: &RouterConfig) -> bool {
2232 eps.iter().copied().any(|ep| !cfg.is_local_endpoint(ep))
2233}
2234
2235#[inline]
2236fn force_remote_for_type(ty: DataType) -> bool {
2237 matches!(
2238 ty,
2239 DataType::ReliableAck
2240 | DataType::ReliablePartialAck
2241 | DataType::ReliablePacketRequest
2242 | DataType::P2pMessage
2243 ) || {
2244 #[cfg(feature = "timesync")]
2245 {
2246 matches!(
2247 ty,
2248 DataType::TimeSyncAnnounce | DataType::TimeSyncRequest | DataType::TimeSyncResponse
2249 )
2250 }
2251 #[cfg(not(feature = "timesync"))]
2252 {
2253 false
2254 }
2255 }
2256}
2257
2258#[inline]
2259fn is_internal_control_type(ty: DataType) -> bool {
2260 if matches!(
2261 ty,
2262 DataType::ReliableAck
2263 | DataType::ReliablePartialAck
2264 | DataType::ReliablePacketRequest
2265 | DataType::P2pMessage
2266 ) {
2267 return true;
2268 }
2269
2270 #[cfg(feature = "timesync")]
2271 if matches!(
2272 ty,
2273 DataType::TimeSyncAnnounce | DataType::TimeSyncRequest | DataType::TimeSyncResponse
2274 ) {
2275 return true;
2276 }
2277
2278 #[cfg(feature = "discovery")]
2279 if discovery::is_discovery_type(ty) {
2280 return true;
2281 }
2282
2283 let _ = ty;
2284 false
2285}
2286
2287fn with_retries<F>(
2289 this: &Router,
2290 dest: DataEndpoint,
2291 data: &RouterItem,
2292 pkt_for_ctx: Option<&Packet>,
2293 env_for_ctx: Option<&wire_format::TelemetryEnvelope>,
2294 called_from_queue: bool,
2295 run: F,
2296) -> TelemetryResult<()>
2297where
2298 F: Fn() -> TelemetryResult<()>,
2299{
2300 match this.retry_with_attempts(runtime_max_handler_retries(), run) {
2301 Ok(((), attempts)) => {
2302 if attempts > 1 {
2303 let mut st = this.state.lock();
2304 st.total_handler_retries = st
2305 .total_handler_retries
2306 .saturating_add(attempts.saturating_sub(1) as u64);
2307 }
2308 Ok(())
2309 }
2310 Err((e, attempts)) => {
2311 {
2312 let mut st = this.state.lock();
2313 st.total_handler_failures = st.total_handler_failures.saturating_add(1);
2314 st.total_handler_retries = st.total_handler_retries.saturating_add(attempts as u64);
2315 }
2316
2317 this.remove_pkt_id(data);
2319
2320 if let Some(pkt) = pkt_for_ctx {
2322 let _ = this.handle_callback_error(pkt, Some(dest), e, called_from_queue);
2323 } else if let Some(env) = env_for_ctx {
2324 let _ = this.handle_callback_error_from_env(env, Some(dest), e, called_from_queue);
2325 }
2326
2327 Err(TelemetryError::HandlerError("local handler failed"))
2328 }
2329 }
2330}
2331impl Router {
2333 const END_TO_END_ACK_SENDER: &'static str = "E2EACK";
2334 const END_TO_END_ACK_PREFIX: &'static str = "E2EACK:";
2335
2336 #[inline]
2337 fn side_ref(st: &RouterInner, side: RouterSideId) -> TelemetryResult<&RouterSide> {
2338 st.sides
2339 .get(side)
2340 .and_then(|side| side.as_ref())
2341 .ok_or(TelemetryError::HandlerError("router: invalid side id"))
2342 }
2343
2344 fn note_side_tx_success(
2345 &self,
2346 side: RouterSideId,
2347 ty: DataType,
2348 bytes: usize,
2349 relayed: bool,
2350 attempts: usize,
2351 ) {
2352 let mut st = self.state.lock();
2353 let entry = st.side_runtime_stats.entry(side).or_default();
2354 entry.note_tx(ty, bytes, relayed, attempts.saturating_sub(1));
2355 }
2356
2357 fn note_side_tx_failure(&self, side: RouterSideId, ty: DataType, attempts: usize) {
2358 let mut st = self.state.lock();
2359 st.total_handler_failures = st.total_handler_failures.saturating_add(1);
2360 st.total_handler_retries = st.total_handler_retries.saturating_add(attempts as u64);
2361 let entry = st.side_runtime_stats.entry(side).or_default();
2362 entry.note_tx_failure(ty, attempts);
2363 }
2364
2365 fn note_side_rx(&self, side: RouterSideId, ty: DataType, bytes: usize, relayed: bool) {
2366 let mut st = self.state.lock();
2367 let entry = st.side_runtime_stats.entry(side).or_default();
2368 entry.note_rx(ty, bytes, relayed);
2369 }
2370
2371 fn note_side_local_delivery(&self, side: RouterSideId, ty: DataType) {
2372 let mut st = self.state.lock();
2373 let entry = st.side_runtime_stats.entry(side).or_default();
2374 entry.note_local_delivery(ty);
2375 }
2376
2377 fn note_side_local_handler_failure(&self, side: RouterSideId, ty: DataType, retries: usize) {
2378 let mut st = self.state.lock();
2379 let entry = st.side_runtime_stats.entry(side).or_default();
2380 entry.note_local_handler_failure(ty, retries);
2381 }
2382
2383 fn cache_managed_variable_packet(
2384 &self,
2385 pkt: &Packet,
2386 notify_handlers: bool,
2387 ) -> TelemetryResult<()> {
2388 let handlers = {
2389 let mut st = self.state.lock();
2390 if !st
2391 .managed_variable_types
2392 .contains(&pkt.data_type().as_u32())
2393 {
2394 return Ok(());
2395 }
2396 let changed = st
2397 .managed_variable_latest
2398 .get(&pkt.data_type().as_u32())
2399 .is_none_or(|entry| entry.packet != *pkt);
2400 st.managed_variable_latest.insert(
2401 pkt.data_type().as_u32(),
2402 ManagedVariableCacheEntry {
2403 packet: pkt.clone(),
2404 cached_at_ms: self.clock.now_ms(),
2405 },
2406 );
2407 if notify_handlers && changed {
2408 st.network_variable_update_handlers
2409 .get(&pkt.data_type().as_u32())
2410 .cloned()
2411 .unwrap_or_default()
2412 } else {
2413 Vec::new()
2414 }
2415 };
2416 for handler in handlers {
2417 (handler.handler)(pkt)?;
2418 }
2419 Ok(())
2420 }
2421
2422 fn remember_managed_variable_packet(&self, pkt: &Packet) -> TelemetryResult<()> {
2423 self.cache_managed_variable_packet(pkt, true)
2424 }
2425
2426 fn managed_variable_latest(&self, ty: DataType) -> Option<Packet> {
2427 let st = self.state.lock();
2428 st.managed_variable_latest
2429 .get(&ty.as_u32())
2430 .map(|entry| entry.packet.clone())
2431 }
2432
2433 fn managed_variable_latest_with_age(&self, ty: DataType) -> Option<(Packet, u64)> {
2434 let now_ms = self.clock.now_ms();
2435 let st = self.state.lock();
2436 st.managed_variable_latest.get(&ty.as_u32()).map(|entry| {
2437 (
2438 entry.packet.clone(),
2439 now_ms.saturating_sub(entry.cached_at_ms),
2440 )
2441 })
2442 }
2443
2444 fn is_managed_variable_type(&self, ty: DataType) -> bool {
2445 let st = self.state.lock();
2446 st.managed_variable_types.contains(&ty.as_u32())
2447 }
2448
2449 fn managed_variable_permissions_locked(
2450 st: &RouterInner,
2451 ty: DataType,
2452 ) -> NetworkVariablePermissions {
2453 st.managed_variable_permissions
2454 .get(&ty.as_u32())
2455 .copied()
2456 .unwrap_or(NetworkVariablePermissions::READ_WRITE)
2457 }
2458
2459 fn can_read_managed_variable(&self, ty: DataType) -> bool {
2460 let st = self.state.lock();
2461 Self::managed_variable_permissions_locked(&st, ty).read
2462 }
2463
2464 fn can_write_managed_variable(&self, ty: DataType) -> bool {
2465 let st = self.state.lock();
2466 Self::managed_variable_permissions_locked(&st, ty).write
2467 }
2468
2469 #[inline]
2470 fn ensure_side_ingress_enabled(&self, side: RouterSideId) -> TelemetryResult<()> {
2471 let st = self.state.lock();
2472 let side_ref = Self::side_ref(&st, side)?;
2473 if side_ref.opts.ingress_enabled {
2474 Ok(())
2475 } else {
2476 Err(TelemetryError::HandlerError(
2477 "router: ingress disabled for side id",
2478 ))
2479 }
2480 }
2481
2482 #[inline]
2483 fn default_route_enabled(&self, src: Option<RouterSideId>, dst: RouterSideId) -> bool {
2484 src != Some(dst)
2485 }
2486
2487 #[inline]
2488 fn route_allowed_locked(
2489 &self,
2490 st: &RouterInner,
2491 src: Option<RouterSideId>,
2492 ty: Option<DataType>,
2493 dst: RouterSideId,
2494 ) -> bool {
2495 let Some(dst_side) = st.sides.get(dst).and_then(|side| side.as_ref()) else {
2496 return false;
2497 };
2498 if !dst_side.opts.egress_enabled {
2499 return false;
2500 }
2501 if let Some(src_id) = src {
2502 let Some(src_side) = st.sides.get(src_id).and_then(|side| side.as_ref()) else {
2503 return false;
2504 };
2505 if !src_side.opts.ingress_enabled {
2506 return false;
2507 }
2508 }
2509 let base_allowed = st
2510 .route_overrides
2511 .get(&(src, dst))
2512 .copied()
2513 .unwrap_or_else(|| self.default_route_enabled(src, dst));
2514 if !base_allowed {
2515 return false;
2516 }
2517
2518 let Some(ty) = ty else {
2519 return true;
2520 };
2521 if st
2522 .typed_route_overrides
2523 .keys()
2524 .any(|(typed_src, typed_ty, _)| *typed_src == src && *typed_ty == ty.as_u32())
2525 {
2526 return st
2527 .typed_route_overrides
2528 .get(&(src, ty.as_u32(), dst))
2529 .copied()
2530 .unwrap_or(false);
2531 }
2532 true
2533 }
2534
2535 fn has_typed_route_overrides_locked(
2536 st: &RouterInner,
2537 src: Option<RouterSideId>,
2538 ty: DataType,
2539 ) -> bool {
2540 st.typed_route_overrides
2541 .keys()
2542 .any(|(typed_src, typed_ty, _)| *typed_src == src && *typed_ty == ty.as_u32())
2543 }
2544
2545 #[cfg(feature = "discovery")]
2546 fn endpoint_overlap_count<I>(reachable: I, eps: &[DataEndpoint]) -> usize
2547 where
2548 I: IntoIterator<Item = DataEndpoint>,
2549 {
2550 let mut overlap = 0usize;
2551 for ep in reachable {
2552 if eps.contains(&ep) {
2553 overlap = overlap.saturating_add(1);
2554 }
2555 }
2556 overlap
2557 }
2558
2559 #[inline]
2560 fn preferred_scoring_endpoints(
2561 &self,
2562 eps: &[DataEndpoint],
2563 prefer_nonlocal: bool,
2564 ) -> Vec<DataEndpoint> {
2565 if !prefer_nonlocal {
2566 return eps.to_vec();
2567 }
2568 let nonlocal: Vec<DataEndpoint> = eps
2569 .iter()
2570 .copied()
2571 .filter(|&ep| !self.cfg.is_local_endpoint(ep))
2572 .collect();
2573 if nonlocal.is_empty() {
2574 eps.to_vec()
2575 } else {
2576 nonlocal
2577 }
2578 }
2579
2580 #[cfg(feature = "discovery")]
2581 fn pop_next_queued_discovery_rx_item(&self) -> TelemetryResult<Option<RouterRxItem>> {
2582 {
2583 let mut isr_rx = self.isr_rx_queue.try_lock()?;
2584 let idx = isr_rx.iter().position(Self::queued_rx_item_is_discovery);
2585 if let Some(idx) = idx {
2586 return Ok(isr_rx.remove_pos(idx));
2587 }
2588 }
2589
2590 let mut st = self.state.lock();
2591 let idx = st
2592 .received_queue
2593 .iter()
2594 .position(Self::queued_rx_item_is_discovery);
2595 if let Some(idx) = idx {
2596 return Ok(st.received_queue.remove_pos(idx));
2597 }
2598 Ok(None)
2599 }
2600
2601 #[cfg(feature = "discovery")]
2602 fn queued_rx_item_is_discovery(item: &RouterRxItem) -> bool {
2603 match &item.data {
2604 RouterItem::Packet(pkt) => discovery::is_discovery_type(pkt.data_type()),
2605 RouterItem::Packed(bytes) => wire_format::peek_envelope(bytes.as_ref())
2606 .map(|env| discovery::is_discovery_type(env.ty))
2607 .unwrap_or(false),
2608 }
2609 }
2610
2611 #[cfg(feature = "discovery")]
2612 fn drain_queued_discovery_rx_before_tx(&self) -> TelemetryResult<bool> {
2613 let mut did_any = false;
2614 while let Some(item) = self.pop_next_queued_discovery_rx_item()? {
2615 self.process_rx_queue_item(item)?;
2616 did_any = true;
2617 }
2618 Ok(did_any)
2619 }
2620
2621 fn eligible_side_ids_locked(
2622 &self,
2623 st: &RouterInner,
2624 src: Option<RouterSideId>,
2625 ty: Option<DataType>,
2626 restrict_link_local: bool,
2627 ) -> Vec<RouterSideId> {
2628 st.sides
2629 .iter()
2630 .enumerate()
2631 .filter_map(|(side_id, side)| {
2632 let side = side.as_ref()?;
2633 if restrict_link_local && !side.opts.link_local_enabled {
2634 return None;
2635 }
2636 if self.route_allowed_locked(st, src, ty, side_id) {
2637 Some(side_id)
2638 } else {
2639 None
2640 }
2641 })
2642 .collect()
2643 }
2644
2645 fn apply_route_selection_locked(
2646 &self,
2647 st: &mut RouterInner,
2648 src: Option<RouterSideId>,
2649 mut sides: Vec<RouterSideId>,
2650 origin: RouteSelectionOrigin,
2651 ) -> Vec<RouterSideId> {
2652 if sides.len() <= 1 {
2653 return sides;
2654 }
2655
2656 let selection_mode = st.source_route_modes.get(&src).copied();
2657 if selection_mode.is_none() && origin == RouteSelectionOrigin::Discovered {
2658 return self.apply_adaptive_discovery_selection_locked(st, src, sides);
2659 }
2660
2661 match selection_mode.unwrap_or(RouteSelectionMode::Fanout) {
2662 RouteSelectionMode::Fanout => sides,
2663 RouteSelectionMode::Weighted => {
2664 sides.sort_unstable();
2665 let total_weight = sides.iter().fold(0_u64, |acc, side| {
2666 acc + u64::from(st.route_weights.get(&(src, *side)).copied().unwrap_or(1))
2667 });
2668 if total_weight == 0 {
2669 return Vec::new();
2670 }
2671 let cursor = st.route_selection_cursors.entry(src).or_insert(0);
2672 let pick = *cursor % total_weight;
2673 *cursor = cursor.wrapping_add(1);
2674 let mut remaining = pick;
2675 for side in sides {
2676 let weight =
2677 u64::from(st.route_weights.get(&(src, side)).copied().unwrap_or(1));
2678 if remaining < weight {
2679 return vec![side];
2680 }
2681 remaining -= weight;
2682 }
2683 Vec::new()
2684 }
2685 RouteSelectionMode::Failover => {
2686 sides.sort_by_key(|side| {
2687 (
2688 st.route_priorities.get(&(src, *side)).copied().unwrap_or(0),
2689 *side,
2690 )
2691 });
2692 sides.truncate(1);
2693 sides
2694 }
2695 }
2696 }
2697
2698 fn apply_adaptive_discovery_selection_locked(
2699 &self,
2700 st: &mut RouterInner,
2701 src: Option<RouterSideId>,
2702 mut sides: Vec<RouterSideId>,
2703 ) -> Vec<RouterSideId> {
2704 sides.sort_unstable();
2705 let mut unmeasured: Vec<_> = sides
2706 .iter()
2707 .copied()
2708 .filter(|side| !st.adaptive_route_stats.contains_key(side))
2709 .collect();
2710 if !unmeasured.is_empty() {
2711 let cursor = st.route_selection_cursors.entry(src).or_insert(0);
2712 let pick = (*cursor as usize) % unmeasured.len();
2713 *cursor = cursor.wrapping_add(1);
2714 return vec![unmeasured.swap_remove(pick)];
2715 }
2716
2717 let now_ms = self.clock.now_ms();
2718 let total_weight = sides.iter().fold(0_u64, |acc, side| {
2719 acc + st
2720 .adaptive_route_stats
2721 .get(side)
2722 .map(|stats| stats.weight(now_ms))
2723 .unwrap_or(1)
2724 });
2725 if total_weight == 0 {
2726 sides.truncate(1);
2727 return sides;
2728 }
2729
2730 let cursor = st.route_selection_cursors.entry(src).or_insert(0);
2731 let pick = *cursor % total_weight;
2732 *cursor = cursor.wrapping_add(1);
2733 let mut remaining = pick;
2734 for side in sides {
2735 let weight = st
2736 .adaptive_route_stats
2737 .get(&side)
2738 .map(|stats| stats.weight(now_ms))
2739 .unwrap_or(1);
2740 if remaining < weight {
2741 return vec![side];
2742 }
2743 remaining -= weight;
2744 }
2745 Vec::new()
2746 }
2747
2748 fn record_side_tx_sample(
2749 &self,
2750 side: RouterSideId,
2751 bytes: usize,
2752 started_ms: u64,
2753 ended_ms: u64,
2754 ) {
2755 let sample_ms = ended_ms.saturating_sub(started_ms).max(1);
2756 let sample_bps = ((bytes as u128).saturating_mul(1000) / u128::from(sample_ms))
2757 .min(u128::from(u64::MAX)) as u64;
2758 let mut st = self.state.lock();
2759 st.adaptive_route_stats
2760 .entry(side)
2761 .or_default()
2762 .observe(bytes, sample_bps, ended_ms);
2763 }
2764
2765 pub fn note_side_link_probe_sample(
2770 &self,
2771 side: RouterSideId,
2772 bytes: usize,
2773 duration_ms: u64,
2774 ) -> TelemetryResult<()> {
2775 {
2776 let st = self.state.lock();
2777 let _ = Self::side_ref(&st, side).map_err(|_| TelemetryError::BadArg)?;
2778 }
2779 let ended_ms = self.clock.now_ms();
2780 self.record_side_tx_sample(side, bytes, ended_ms.saturating_sub(duration_ms), ended_ms);
2781 Ok(())
2782 }
2783
2784 fn router_item_wire_len(data: &RouterItem) -> TelemetryResult<usize> {
2785 match data {
2786 RouterItem::Packet(pkt) => Ok(wire_format::pack_packet(pkt).len()),
2787 RouterItem::Packed(bytes) => Ok(bytes.len()),
2788 }
2789 }
2790
2791 #[inline]
2801 fn reliable_control_target_packet_id(data: &RouterItem) -> TelemetryResult<Option<u64>> {
2802 match data {
2803 RouterItem::Packet(pkt) => {
2804 if pkt.data_type() != DataType::ReliableAck
2805 || !Self::is_end_to_end_ack_sender(pkt.sender())
2806 {
2807 return Ok(None);
2808 }
2809 Self::decode_end_to_end_reliable_ack(pkt.payload()).map(Some)
2810 }
2811 RouterItem::Packed(bytes) => {
2812 if wire_format::peek_frame_info(bytes.as_ref())
2813 .ok()
2814 .is_some_and(|frame| frame.ack_only())
2815 {
2816 return Ok(None);
2817 }
2818 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
2819 if pkt.data_type() != DataType::ReliableAck
2820 || !Self::is_end_to_end_ack_sender(pkt.sender())
2821 {
2822 return Ok(None);
2823 }
2824 Self::decode_end_to_end_reliable_ack(pkt.payload()).map(Some)
2825 }
2826 }
2827 }
2828
2829 fn decode_end_to_end_reliable_ack(payload: &[u8]) -> TelemetryResult<u64> {
2830 if payload.len() != 8 {
2831 return Err(TelemetryError::Unpack("bad reliable e2e ack payload"));
2832 }
2833 Ok(u64::from_le_bytes(payload[0..8].try_into().unwrap()))
2834 }
2835
2836 #[inline]
2837 fn sender_hash(sender: &str) -> u64 {
2838 if let Some(address) = sender
2839 .strip_prefix("@addr:")
2840 .and_then(|v| v.parse::<u32>().ok())
2841 {
2842 return u64::from(address);
2843 }
2844 hash_bytes_u64(0x517C_C1B7_2722_0A95, sender.as_bytes())
2845 }
2846
2847 #[inline]
2848 fn fallback_address_for_hostname(hostname: &str) -> NodeAddress {
2849 let hash = Self::sender_hash(hostname);
2850 let mut address = (hash as u32) ^ ((hash >> 32) as u32);
2851 if address == 0 {
2852 address = 1;
2853 }
2854 address
2855 }
2856
2857 fn canonical_sender_locked(st: &RouterInner, sender: &str) -> String {
2862 let Some(address) = sender
2863 .strip_prefix("@addr:")
2864 .and_then(|value| value.parse::<u32>().ok())
2865 else {
2866 return sender.to_string();
2867 };
2868 if let Some(hostname) = st.address_by_value.get(&address) {
2869 return hostname.clone();
2870 }
2871 st.address_book
2872 .values()
2873 .find(|entry| sender_address_u32(entry.hostname.as_ref()) == address)
2874 .map(|entry| entry.hostname.to_string())
2875 .unwrap_or_else(|| sender.to_string())
2876 }
2877
2878 fn address_mode_from_code(mode: u8, requested: NodeAddress) -> AddressAssignmentMode {
2879 match mode {
2880 2 => AddressAssignmentMode::Static(if requested == 0 { 1 } else { requested }),
2881 1 => AddressAssignmentMode::Requested(if requested == 0 { 1 } else { requested }),
2882 _ => AddressAssignmentMode::Dynamic,
2883 }
2884 }
2885
2886 fn address_winner_pref(entry: &AddressBookEntry) -> (u8, core::cmp::Reverse<u64>, u64) {
2887 let rank = match entry.mode {
2888 AddressAssignmentMode::Static(_) => 2,
2889 AddressAssignmentMode::Requested(_) => 1,
2890 AddressAssignmentMode::Dynamic => 0,
2891 };
2892 (
2893 rank,
2894 core::cmp::Reverse(entry.birth_ms),
2895 u64::MAX - entry.owner_hash,
2896 )
2897 }
2898
2899 fn identity_winner_pref(entry: &AddressBookEntry) -> (core::cmp::Reverse<u64>, u64) {
2900 (
2901 core::cmp::Reverse(entry.birth_ms),
2902 u64::MAX - entry.owner_hash,
2903 )
2904 }
2905
2906 fn allocate_free_address_locked(st: &RouterInner, seed: NodeAddress) -> NodeAddress {
2907 let mut candidate = if seed == 0 { 1 } else { seed };
2908 for _ in 0..u32::MAX {
2909 if candidate != 0 && !st.address_by_value.contains_key(&candidate) {
2910 return candidate;
2911 }
2912 candidate = candidate.wrapping_add(1);
2913 if candidate == 0 {
2914 candidate = 1;
2915 }
2916 }
2917 1
2918 }
2919
2920 fn unique_hostname_locked(st: &RouterInner, base: &str, owner_hash: u64) -> String {
2921 if !st.address_book.contains_key(base) {
2922 return base.to_string();
2923 }
2924 let stem = if base.is_empty() { "node" } else { base };
2925 let mut candidate = format!("{stem}-{owner_hash:08x}");
2926 let mut suffix = 1u32;
2927 while st.address_book.contains_key(&candidate) {
2928 candidate = format!("{stem}-{owner_hash:08x}-{suffix}");
2929 suffix = suffix.saturating_add(1);
2930 }
2931 candidate
2932 }
2933
2934 fn update_local_identity_locked(
2935 &self,
2936 st: &mut RouterInner,
2937 mut local: AddressBookEntry,
2938 reason: AddressChangeReason,
2939 ) -> AddressChange {
2940 let old = st.local_address.clone();
2941 st.address_book.remove(old.hostname.as_ref());
2942 st.address_by_value.remove(&old.address);
2943 local.last_seen_ms = self.clock.now_ms();
2944 st.address_by_value
2945 .insert(local.address, local.hostname.to_string());
2946 st.address_book
2947 .insert(local.hostname.to_string(), local.clone());
2948 st.local_address = local.clone();
2949 *self.sender.lock() = local.hostname.clone();
2950 #[cfg(feature = "discovery")]
2951 Self::note_discovery_topology_change_locked(st, self.clock.now_ms());
2952 AddressChange {
2953 old_hostname: old.hostname,
2954 new_hostname: local.hostname,
2955 old_address: old.address,
2956 new_address: local.address,
2957 reason,
2958 }
2959 }
2960
2961 fn notify_address_change(&self, change: AddressChange) -> TelemetryResult<()> {
2962 for handler in self.cfg.address_change_handlers.iter() {
2963 (handler.handler)(change.clone())?;
2964 }
2965 Ok(())
2966 }
2967
2968 #[cfg(feature = "discovery")]
2969 fn local_address_advertisement(
2970 &self,
2971 reachable_endpoints: Vec<DataEndpoint>,
2972 reachable_network_variables: Vec<DataType>,
2973 reachable_timesync_sources: Vec<String>,
2974 link_capabilities: discovery::LinkCapabilities,
2975 state: u8,
2976 ) -> discovery::AddressAdvertisement {
2977 let st = self.state.lock();
2978 discovery::AddressAdvertisement {
2979 hostname: st.local_address.hostname.to_string(),
2980 address: st.local_address.address,
2981 requested_address: st.local_address.requested_address,
2982 mode: st.local_address.mode.mode_code(),
2983 state,
2984 birth_ms: st.local_address.birth_ms,
2985 owner_hash: st.local_address.owner_hash,
2986 reachable_endpoints,
2987 reachable_network_variables,
2988 reachable_timesync_sources,
2989 link_capabilities,
2990 }
2991 }
2992
2993 #[cfg(feature = "discovery")]
2994 fn ingest_address_advertisement(
2995 &self,
2996 ad: discovery::AddressAdvertisement,
2997 ) -> TelemetryResult<bool> {
2998 let now_ms = self.clock.now_ms();
2999 let mut remote = AddressBookEntry {
3000 hostname: Arc::from(ad.hostname.as_str()),
3001 address: ad.address,
3002 requested_address: ad.requested_address,
3003 mode: Self::address_mode_from_code(ad.mode, ad.requested_address),
3004 birth_ms: ad.birth_ms,
3005 owner_hash: ad.owner_hash,
3006 last_seen_ms: now_ms,
3007 };
3008 let mut change = None;
3009 let mut changed = false;
3010 {
3011 let mut st = self.state.lock();
3012 let local = st.local_address.clone();
3013 let hostname_conflict =
3014 remote.hostname == local.hostname && remote.owner_hash != local.owner_hash;
3015 let address_conflict =
3016 remote.address == local.address && remote.owner_hash != local.owner_hash;
3017
3018 if hostname_conflict
3019 && Self::identity_winner_pref(&remote) > Self::identity_winner_pref(&local)
3020 {
3021 let mut next = local.clone();
3022 next.hostname = Arc::from(Self::unique_hostname_locked(
3023 &st,
3024 local.hostname.as_ref(),
3025 local.owner_hash,
3026 ));
3027 change = Some(self.update_local_identity_locked(
3028 &mut st,
3029 next,
3030 AddressChangeReason::HostnameConflict,
3031 ));
3032 changed = true;
3033 } else if address_conflict
3034 && Self::address_winner_pref(&remote) > Self::address_winner_pref(&local)
3035 {
3036 let mut next = local.clone();
3037 let seed = next
3038 .requested_address
3039 .max(Self::fallback_address_for_hostname(next.hostname.as_ref()));
3040 next.address = Self::allocate_free_address_locked(&st, seed);
3041 let reason = match next.mode {
3042 AddressAssignmentMode::Static(_) => AddressChangeReason::StaticConflict,
3043 AddressAssignmentMode::Requested(_) => AddressChangeReason::RequestedConflict,
3044 AddressAssignmentMode::Dynamic => AddressChangeReason::DynamicConflict,
3045 };
3046 change = Some(self.update_local_identity_locked(&mut st, next, reason));
3047 changed = true;
3048 } else if hostname_conflict {
3049 remote.hostname = Arc::from(Self::unique_hostname_locked(
3050 &st,
3051 remote.hostname.as_ref(),
3052 remote.owner_hash,
3053 ));
3054 changed = true;
3055 } else if address_conflict {
3056 let seed = remote
3057 .requested_address
3058 .max(Self::fallback_address_for_hostname(
3059 remote.hostname.as_ref(),
3060 ));
3061 remote.address = Self::allocate_free_address_locked(&st, seed);
3062 changed = true;
3063 }
3064
3065 st.address_book.remove(remote.hostname.as_ref());
3066 st.address_by_value.remove(&remote.address);
3067 st.address_by_value
3068 .insert(remote.address, remote.hostname.to_string());
3069 st.address_book
3070 .insert(remote.hostname.to_string(), remote.clone());
3071 }
3072 if let Some(change) = change {
3073 self.notify_address_change(change)?;
3074 }
3075 Ok(changed)
3076 }
3077
3078 #[inline]
3079 fn is_end_to_end_ack_sender(sender: &str) -> bool {
3080 sender == Self::END_TO_END_ACK_SENDER || sender.starts_with(Self::END_TO_END_ACK_PREFIX)
3081 }
3082
3083 fn decode_end_to_end_ack_sender_hash(sender: &str) -> Option<u64> {
3084 if let Some(ack_sender) = sender.strip_prefix(Self::END_TO_END_ACK_PREFIX)
3085 && !ack_sender.is_empty()
3086 {
3087 return Some(Self::sender_hash(ack_sender));
3088 }
3089 None
3090 }
3091
3092 fn encode_end_to_end_ack_sender(&self) -> String {
3093 let sender = self.sender_arc();
3094 format!("{}{}", Self::END_TO_END_ACK_PREFIX, sender)
3095 }
3096
3097 #[cfg(feature = "discovery")]
3098 fn is_end_to_end_destination_sender(sender: &str) -> bool {
3099 sender != "RELAY" && !Self::is_end_to_end_ack_sender(sender)
3100 }
3101
3102 fn encode_end_to_end_reliable_ack(packet_id: u64) -> Arc<[u8]> {
3103 let mut payload = Vec::with_capacity(8);
3104 payload.extend_from_slice(&packet_id.to_le_bytes());
3105 Arc::from(payload)
3106 }
3107
3108 fn encode_p2p_payload(
3109 src_hostname: &str,
3110 src_address: NodeAddress,
3111 src_port: P2pPort,
3112 dst_port: P2pPort,
3113 payload: &[u8],
3114 ) -> TelemetryResult<Arc<[u8]>> {
3115 let host_len = u16::try_from(src_hostname.len())
3116 .map_err(|_| TelemetryError::Pack("p2p hostname too long"))?;
3117 let payload_len = u32::try_from(payload.len())
3118 .map_err(|_| TelemetryError::Pack("p2p payload too long"))?;
3119 let mut out = Vec::with_capacity(
3120 15usize
3121 .saturating_add(src_hostname.len())
3122 .saturating_add(payload.len()),
3123 );
3124 out.push(1);
3125 out.extend_from_slice(&dst_port.to_le_bytes());
3126 out.extend_from_slice(&src_port.to_le_bytes());
3127 out.extend_from_slice(&src_address.to_le_bytes());
3128 out.extend_from_slice(&host_len.to_le_bytes());
3129 out.extend_from_slice(&payload_len.to_le_bytes());
3130 out.extend_from_slice(src_hostname.as_bytes());
3131 out.extend_from_slice(payload);
3132 Ok(out.into())
3133 }
3134
3135 fn decode_p2p_payload(payload: &[u8]) -> TelemetryResult<P2pDecoded<'_>> {
3136 if payload.len() < 15 {
3137 return Err(TelemetryError::Unpack("p2p frame short"));
3138 }
3139 if payload[0] != 1 {
3140 return Err(TelemetryError::Unpack("p2p frame version"));
3141 }
3142 let destination_port =
3143 u16::from_le_bytes(payload[1..3].try_into().expect("2-byte dst port"));
3144 let source_port = u16::from_le_bytes(payload[3..5].try_into().expect("2-byte src port"));
3145 let source_address = u32::from_le_bytes(payload[5..9].try_into().expect("4-byte address"));
3146 let host_len =
3147 u16::from_le_bytes(payload[9..11].try_into().expect("2-byte host len")) as usize;
3148 let body_len =
3149 u32::from_le_bytes(payload[11..15].try_into().expect("4-byte body len")) as usize;
3150 let host_start = 15usize;
3151 let host_end = host_start.saturating_add(host_len);
3152 let body_end = host_end.saturating_add(body_len);
3153 if host_end > payload.len() || body_end != payload.len() {
3154 return Err(TelemetryError::Unpack("p2p frame length"));
3155 }
3156 let source_hostname = core::str::from_utf8(&payload[host_start..host_end])
3157 .map_err(|_| TelemetryError::Unpack("p2p hostname utf8"))?;
3158 Ok(P2pDecoded {
3159 source_hostname,
3160 source_address,
3161 source_port,
3162 destination_port,
3163 payload: &payload[host_end..body_end],
3164 })
3165 }
3166
3167 fn encode_p2p_stream_payload(
3168 flags: u8,
3169 source_stream_id: P2pStreamId,
3170 destination_stream_id: P2pStreamId,
3171 sequence: u32,
3172 payload: &[u8],
3173 ) -> TelemetryResult<Arc<[u8]>> {
3174 let payload_len = u32::try_from(payload.len())
3175 .map_err(|_| TelemetryError::Pack("p2p stream payload too long"))?;
3176 let mut out = Vec::with_capacity(22usize.saturating_add(payload.len()));
3177 out.extend_from_slice(&P2P_STREAM_MAGIC);
3178 out.push(P2P_STREAM_VERSION);
3179 out.push(flags);
3180 out.extend_from_slice(&source_stream_id.to_le_bytes());
3181 out.extend_from_slice(&destination_stream_id.to_le_bytes());
3182 out.extend_from_slice(&sequence.to_le_bytes());
3183 out.extend_from_slice(&payload_len.to_le_bytes());
3184 out.extend_from_slice(payload);
3185 Ok(out.into())
3186 }
3187
3188 fn decode_p2p_stream_payload(payload: &[u8]) -> TelemetryResult<Option<P2pStreamDecoded<'_>>> {
3189 if !payload.starts_with(&P2P_STREAM_MAGIC) {
3190 return Ok(None);
3191 }
3192 if payload.len() < 22 {
3193 return Err(TelemetryError::Unpack("p2p stream frame short"));
3194 }
3195 if payload[4] != P2P_STREAM_VERSION {
3196 return Err(TelemetryError::Unpack("p2p stream frame version"));
3197 }
3198 let flags = payload[5];
3199 let source_stream_id =
3200 u32::from_le_bytes(payload[6..10].try_into().expect("stream source id"));
3201 let destination_stream_id =
3202 u32::from_le_bytes(payload[10..14].try_into().expect("stream destination id"));
3203 let sequence = u32::from_le_bytes(payload[14..18].try_into().expect("stream sequence"));
3204 let body_len =
3205 u32::from_le_bytes(payload[18..22].try_into().expect("stream body len")) as usize;
3206 let body_end = 22usize.saturating_add(body_len);
3207 if body_end != payload.len() {
3208 return Err(TelemetryError::Unpack("p2p stream frame length"));
3209 }
3210 Ok(Some(P2pStreamDecoded {
3211 flags,
3212 source_stream_id,
3213 destination_stream_id,
3214 sequence,
3215 payload: &payload[22..],
3216 }))
3217 }
3218
3219 fn allocate_p2p_stream_id_locked(st: &mut RouterInner) -> P2pStreamId {
3220 for _ in 0..u32::MAX {
3221 let id = st.next_p2p_stream_id.max(1);
3222 st.next_p2p_stream_id = st.next_p2p_stream_id.wrapping_add(1).max(1);
3223 if !st.p2p_stream_sessions.contains_key(&id) {
3224 return id;
3225 }
3226 }
3227 0
3228 }
3229
3230 fn dispatch_p2p_packet(&self, pkt: &Packet) -> TelemetryResult<()> {
3231 if pkt.data_type() != DataType::P2pMessage {
3232 return Ok(());
3233 }
3234 let decoded = Self::decode_p2p_payload(pkt.payload())?;
3235 if let Some(stream) = Self::decode_p2p_stream_payload(decoded.payload)? {
3236 return self.dispatch_p2p_stream_frame(&decoded, &stream);
3237 }
3238 let handlers = {
3239 let st = self.state.lock();
3240 st.p2p_port_handlers
3241 .get(&decoded.destination_port)
3242 .cloned()
3243 .unwrap_or_default()
3244 };
3245 for handler in handlers {
3246 (handler.handler)(P2pMessage {
3247 source_hostname: decoded.source_hostname,
3248 source_address: decoded.source_address,
3249 source_port: decoded.source_port,
3250 destination_port: decoded.destination_port,
3251 payload: decoded.payload,
3252 })?;
3253 }
3254 Ok(())
3255 }
3256
3257 fn dispatch_p2p_stream_frame(
3258 &self,
3259 msg: &P2pDecoded<'_>,
3260 frame: &P2pStreamDecoded<'_>,
3261 ) -> TelemetryResult<()> {
3262 let mut events: Vec<PendingP2pStreamEvent> = Vec::new();
3263 let mut reply: Option<(AddressBookEntry, P2pPort, P2pPort, Arc<[u8]>)> = None;
3264 {
3265 let mut st = self.state.lock();
3266 if frame.flags & P2P_STREAM_SYN != 0 && frame.flags & P2P_STREAM_ACK == 0 {
3267 let peer_hostname: Arc<str> = Arc::from(msg.source_hostname);
3268 let existing_id = st.p2p_stream_sessions.iter().find_map(|(id, session)| {
3269 (session.peer_stream_id == frame.source_stream_id
3270 && session.local_port == msg.destination_port
3271 && session.peer_port == msg.source_port
3272 && session.peer_address == msg.source_address
3273 && session.peer_hostname.as_ref() == msg.source_hostname)
3274 .then_some(*id)
3275 });
3276 let local_id = if let Some(local_id) = existing_id {
3277 local_id
3278 } else {
3279 let local_id = Self::allocate_p2p_stream_id_locked(&mut st);
3280 if local_id == 0 {
3281 return Err(TelemetryError::Io("p2p stream id exhausted"));
3282 }
3283 st.p2p_stream_sessions.insert(
3284 local_id,
3285 P2pStreamSession {
3286 peer_hostname: peer_hostname.clone(),
3287 peer_address: msg.source_address,
3288 local_port: msg.destination_port,
3289 peer_port: msg.source_port,
3290 peer_stream_id: frame.source_stream_id,
3291 next_sequence: 1,
3292 connected: true,
3293 },
3294 );
3295 let handlers = st
3296 .p2p_stream_handlers
3297 .get(&msg.destination_port)
3298 .cloned()
3299 .unwrap_or_default();
3300 events.push(PendingP2pStreamEvent {
3301 handlers,
3302 kind: P2pStreamEventKind::Accepted,
3303 stream_id: local_id,
3304 peer_stream_id: frame.source_stream_id,
3305 peer_hostname: peer_hostname.clone(),
3306 peer_address: msg.source_address,
3307 local_port: msg.destination_port,
3308 peer_port: msg.source_port,
3309 });
3310 local_id
3311 };
3312 let dst =
3313 st.address_book
3314 .get(msg.source_hostname)
3315 .cloned()
3316 .unwrap_or(AddressBookEntry {
3317 hostname: peer_hostname,
3318 address: msg.source_address,
3319 requested_address: msg.source_address,
3320 mode: AddressAssignmentMode::Dynamic,
3321 birth_ms: self.clock.now_ms(),
3322 owner_hash: Self::sender_hash(msg.source_hostname),
3323 last_seen_ms: self.clock.now_ms(),
3324 });
3325 let payload = Self::encode_p2p_stream_payload(
3326 P2P_STREAM_SYN | P2P_STREAM_ACK,
3327 local_id,
3328 frame.source_stream_id,
3329 0,
3330 &[],
3331 )?;
3332 reply = Some((dst, msg.source_port, msg.destination_port, payload));
3333 } else if frame.flags & P2P_STREAM_SYN != 0 && frame.flags & P2P_STREAM_ACK != 0 {
3334 if let Some(session) = st.p2p_stream_sessions.get_mut(&frame.destination_stream_id)
3335 {
3336 session.peer_stream_id = frame.source_stream_id;
3337 session.connected = true;
3338 let peer_hostname = session.peer_hostname.clone();
3339 let peer_address = session.peer_address;
3340 let local_port = session.local_port;
3341 let peer_port = session.peer_port;
3342 let handlers = st
3343 .p2p_stream_handlers
3344 .get(&local_port)
3345 .cloned()
3346 .unwrap_or_default();
3347 events.push(PendingP2pStreamEvent {
3348 handlers,
3349 kind: P2pStreamEventKind::Connected,
3350 stream_id: frame.destination_stream_id,
3351 peer_stream_id: frame.source_stream_id,
3352 peer_hostname,
3353 peer_address,
3354 local_port,
3355 peer_port,
3356 });
3357 }
3358 } else if frame.flags & (P2P_STREAM_FIN | P2P_STREAM_RST | P2P_STREAM_DATA) != 0 {
3359 let kind = if frame.flags & P2P_STREAM_RST != 0 {
3360 P2pStreamEventKind::Reset
3361 } else if frame.flags & P2P_STREAM_FIN != 0 {
3362 P2pStreamEventKind::Closed
3363 } else {
3364 P2pStreamEventKind::Data
3365 };
3366 let session_id = if frame.destination_stream_id != 0 {
3367 Some(frame.destination_stream_id)
3368 } else {
3369 st.p2p_stream_sessions.iter().find_map(|(id, session)| {
3370 (session.peer_stream_id == frame.source_stream_id
3371 && session.local_port == msg.destination_port
3372 && session.peer_port == msg.source_port
3373 && session.peer_address == msg.source_address
3374 && session.peer_hostname.as_ref() == msg.source_hostname)
3375 .then_some(*id)
3376 })
3377 };
3378 if let Some(session_id) = session_id
3379 && let Some(session) = st.p2p_stream_sessions.get(&session_id)
3380 {
3381 let handlers = st
3382 .p2p_stream_handlers
3383 .get(&session.local_port)
3384 .cloned()
3385 .unwrap_or_default();
3386 events.push(PendingP2pStreamEvent {
3387 handlers,
3388 kind,
3389 stream_id: session_id,
3390 peer_stream_id: frame.source_stream_id,
3391 peer_hostname: session.peer_hostname.clone(),
3392 peer_address: session.peer_address,
3393 local_port: session.local_port,
3394 peer_port: session.peer_port,
3395 });
3396 if matches!(kind, P2pStreamEventKind::Closed | P2pStreamEventKind::Reset) {
3397 st.p2p_stream_sessions.remove(&session_id);
3398 }
3399 }
3400 }
3401 }
3402 if let Some((dst, dst_port, src_port, payload)) = reply {
3403 self.send_p2p_to_entry(dst, dst_port, src_port, &payload)?;
3404 }
3405 for pending in events {
3406 for handler in pending.handlers {
3407 (handler.handler)(P2pStreamEvent {
3408 kind: pending.kind,
3409 stream_id: pending.stream_id,
3410 peer_stream_id: pending.peer_stream_id,
3411 sequence: frame.sequence,
3412 peer_hostname: pending.peer_hostname.as_ref(),
3413 peer_address: pending.peer_address,
3414 local_port: pending.local_port,
3415 peer_port: pending.peer_port,
3416 payload: frame.payload,
3417 })?;
3418 }
3419 }
3420 Ok(())
3421 }
3422
3423 fn note_reliable_return_route(&self, side: RouterSideId, packet_id: u64) {
3429 let mut st = self.state.lock();
3430 Self::remember_reliable_return_route_locked(&mut st, packet_id);
3431 st.reliable_return_routes
3432 .insert(packet_id, ReliableReturnRouteState { side });
3433 }
3434
3435 fn remember_reliable_return_route_locked(st: &mut RouterInner, packet_id: u64) {
3441 let cap = runtime_reliable_max_return_routes().max(1);
3442 st.reliable_return_route_order
3443 .retain(|id| st.reliable_return_routes.contains_key(id) && *id != packet_id);
3444 while st.reliable_return_route_order.len() >= cap {
3445 if let Some(oldest) = st.reliable_return_route_order.pop_front() {
3446 st.reliable_return_routes.remove(&oldest);
3447 } else {
3448 break;
3449 }
3450 }
3451 st.reliable_return_route_order.push_back(packet_id);
3452 }
3453
3454 fn remember_end_to_end_reliable_tx_locked(st: &mut RouterInner, packet_id: u64) {
3455 let cap = runtime_reliable_max_end_to_end_pending().max(1);
3456 st.end_to_end_reliable_tx_order
3457 .retain(|id| st.end_to_end_reliable_tx.contains_key(id) && *id != packet_id);
3458 while st.end_to_end_reliable_tx_order.len() >= cap {
3459 if let Some(oldest) = st.end_to_end_reliable_tx_order.pop_front() {
3460 st.end_to_end_reliable_tx.remove(&oldest);
3461 } else {
3462 break;
3463 }
3464 }
3465 st.end_to_end_reliable_tx_order.push_back(packet_id);
3466 }
3467
3468 #[cfg(feature = "discovery")]
3469 fn expected_end_to_end_destinations_locked(
3470 &self,
3471 st: &RouterInner,
3472 data: &RouterItem,
3473 ) -> TelemetryResult<BTreeMap<u64, RouterSideId>> {
3474 let (eps, ty) = self.item_route_info(data)?;
3475 let now_ms = self.clock.now_ms();
3476 let restrict_link_local = Self::endpoints_are_link_local_only(&eps);
3477 let prefer_best_overlap =
3478 is_reliable_type(ty) && Self::reliable_control_target_packet_id(data)?.is_none();
3479 let scoring_eps = self.preferred_scoring_endpoints(&eps, prefer_best_overlap);
3480 let mut candidates: Vec<(u64, RouterSideId, usize)> = Vec::new();
3481 let mut best_overlap = 0usize;
3482 let mut out = BTreeMap::new();
3483 for (&side, route) in st.discovery_routes.iter() {
3484 if now_ms.saturating_sub(route.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
3485 continue;
3486 }
3487 let Some(side_ref) = st.sides.get(side).and_then(Option::as_ref) else {
3488 continue;
3489 };
3490 if restrict_link_local && !side_ref.opts.link_local_enabled {
3491 continue;
3492 }
3493 if !self.route_allowed_locked(st, None, Some(ty), side) {
3494 continue;
3495 }
3496 for sender_state in route.announcers.values() {
3497 if now_ms.saturating_sub(sender_state.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
3498 continue;
3499 }
3500 for board in sender_state.topology_boards.iter() {
3501 if !Self::is_end_to_end_destination_sender(&board.sender_id) {
3502 continue;
3503 }
3504 let overlap = Self::endpoint_overlap_count(
3505 board.reachable_endpoints.iter().copied(),
3506 &scoring_eps,
3507 );
3508 if overlap > 0 {
3509 if prefer_best_overlap {
3510 best_overlap = best_overlap.max(overlap);
3511 candidates.push((Self::sender_hash(&board.sender_id), side, overlap));
3512 } else {
3513 out.insert(Self::sender_hash(&board.sender_id), side);
3514 if out.len() >= runtime_reliable_max_end_to_end_pending().max(1) {
3515 return Ok(out);
3516 }
3517 }
3518 }
3519 }
3520 }
3521 }
3522
3523 if prefer_best_overlap {
3524 for (sender_hash, side, overlap) in candidates {
3525 if overlap == best_overlap {
3526 out.insert(sender_hash, side);
3527 if out.len() >= runtime_reliable_max_end_to_end_pending().max(1) {
3528 return Ok(out);
3529 }
3530 }
3531 }
3532 }
3533 Ok(out)
3534 }
3535
3536 #[cfg(feature = "discovery")]
3537 #[allow(clippy::too_many_arguments)]
3538 fn discovered_route_candidates_locked(
3539 &self,
3540 st: &RouterInner,
3541 exclude: Option<RouterSideId>,
3542 ty: DataType,
3543 eps: &[DataEndpoint],
3544 target_senders: &[u64],
3545 prefer_nonlocal: bool,
3546 preferred_timesync_source: Option<&str>,
3547 ) -> Vec<DiscoveryCandidateMatch> {
3548 let restrict_link_local = Self::endpoints_are_link_local_only(eps);
3549 let now_ms = self.clock.now_ms();
3550 let scoring_eps = self.preferred_scoring_endpoints(eps, prefer_nonlocal);
3551 let has_variable_owner = st.discovery_routes.iter().any(|(&side, route)| {
3552 exclude != Some(side)
3553 && now_ms.saturating_sub(route.last_seen_ms) <= DISCOVERY_ROUTE_TTL_MS
3554 && route.reachable_network_variables.contains(&ty)
3555 });
3556 let mut out = Vec::new();
3557
3558 for (&side, route) in st.discovery_routes.iter() {
3559 if exclude == Some(side)
3560 || now_ms.saturating_sub(route.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS
3561 {
3562 continue;
3563 }
3564 if restrict_link_local
3565 && st
3566 .sides
3567 .get(side)
3568 .and_then(|s| s.as_ref())
3569 .map(|s| !s.opts.link_local_enabled)
3570 .unwrap_or(true)
3571 {
3572 continue;
3573 }
3574 if !self.route_allowed_locked(st, exclude, Some(ty), side) {
3575 continue;
3576 }
3577 if !target_senders.is_empty()
3578 && !Self::side_matches_target_senders_locked(st, side, target_senders, now_ms)
3579 {
3580 continue;
3581 }
3582 if !target_senders.is_empty() {
3583 out.push(DiscoveryCandidateMatch {
3584 side,
3585 overlap: usize::MAX,
3586 });
3587 continue;
3588 }
3589 if has_variable_owner {
3590 if route.reachable_network_variables.contains(&ty) {
3591 out.push(DiscoveryCandidateMatch {
3592 side,
3593 overlap: usize::MAX,
3594 });
3595 }
3596 continue;
3597 }
3598 if preferred_timesync_source
3599 .is_some_and(|source| route.reachable_timesync_sources.iter().any(|s| s == source))
3600 {
3601 out.push(DiscoveryCandidateMatch {
3602 side,
3603 overlap: usize::MAX,
3604 });
3605 continue;
3606 }
3607 let overlap =
3608 Self::endpoint_overlap_count(route.reachable.iter().copied(), &scoring_eps);
3609 if overlap > 0 {
3610 out.push(DiscoveryCandidateMatch { side, overlap });
3611 }
3612 }
3613 out
3614 }
3615
3616 #[cfg(feature = "discovery")]
3622 fn retain_shortest_discovery_candidates_locked(
3623 st: &RouterInner,
3624 matches: &mut Vec<DiscoveryCandidateMatch>,
3625 endpoints: &[DataEndpoint],
3626 target_senders: &[u64],
3627 now_ms: u64,
3628 ) {
3629 if matches.len() <= 1 || endpoints.is_empty() {
3630 return;
3631 }
3632
3633 let route_distance = |side: RouterSideId, target_sender: Option<u64>| -> Option<usize> {
3634 let route = st.discovery_routes.get(&side)?;
3635 route
3636 .announcers
3637 .iter()
3638 .filter(|(_, state)| {
3639 now_ms.saturating_sub(state.last_seen_ms) <= DISCOVERY_ROUTE_TTL_MS
3640 })
3641 .filter_map(|(announcer, state)| {
3642 let targets: BTreeSet<&str> = state
3643 .topology_boards
3644 .iter()
3645 .filter(|board| {
3646 target_sender
3647 .map(|target| Self::sender_hash(&board.sender_id) == target)
3648 .unwrap_or_else(|| {
3649 endpoints.iter().any(|endpoint| {
3650 board.reachable_endpoints.contains(endpoint)
3651 })
3652 })
3653 })
3654 .map(|board| board.sender_id.as_str())
3655 .collect();
3656 if targets.is_empty() {
3657 return if let Some(target) = target_sender {
3658 state
3659 .topology_boards
3660 .iter()
3661 .any(|board| Self::sender_hash(&board.sender_id) == target)
3662 .then_some(usize::MAX / 2)
3663 } else {
3664 state
3665 .reachable
3666 .iter()
3667 .any(|endpoint| endpoints.contains(endpoint))
3668 .then_some(usize::MAX / 2)
3669 };
3670 }
3671
3672 let mut distances: BTreeMap<&str, usize> = BTreeMap::new();
3673 let mut pending = VecDeque::from([(announcer.as_str(), 0usize)]);
3674 while let Some((sender, distance)) = pending.pop_front() {
3675 if distances.contains_key(sender) {
3676 continue;
3677 }
3678 distances.insert(sender, distance);
3679 if targets.contains(sender) {
3680 return Some(distance);
3681 }
3682 for board in &state.topology_boards {
3683 if board.sender_id == sender {
3684 for peer in &board.connections {
3685 if !distances.contains_key(peer.as_str()) {
3686 pending.push_back((peer.as_str(), distance + 1));
3687 }
3688 }
3689 } else if board.connections.iter().any(|peer| peer == sender)
3690 && !distances.contains_key(board.sender_id.as_str())
3691 {
3692 pending.push_back((board.sender_id.as_str(), distance + 1));
3693 }
3694 }
3695 }
3696 None
3697 })
3698 .min()
3699 };
3700
3701 let route_targets: Vec<Option<u64>> = if target_senders.is_empty() {
3702 vec![None]
3703 } else {
3704 target_senders.iter().copied().map(Some).collect()
3705 };
3706 let mut selected = BTreeSet::new();
3707 for target in route_targets {
3708 let distances: Vec<(RouterSideId, usize)> = matches
3709 .iter()
3710 .filter_map(|candidate| {
3711 route_distance(candidate.side, target)
3712 .map(|distance| (candidate.side, distance))
3713 })
3714 .collect();
3715 let Some(best) = distances.iter().map(|(_, distance)| *distance).min() else {
3716 continue;
3717 };
3718 selected.extend(
3719 distances
3720 .into_iter()
3721 .filter(|(_, distance)| *distance == best)
3722 .map(|(side, _)| side),
3723 );
3724 }
3725 if !selected.is_empty() {
3726 matches.retain(|candidate| selected.contains(&candidate.side));
3727 }
3728 }
3729
3730 #[cfg(feature = "discovery")]
3731 fn select_discovered_candidate_sides_locked(
3732 &self,
3733 st: &mut RouterInner,
3734 exclude: Option<RouterSideId>,
3735 ty: DataType,
3736 target_senders: &[u64],
3737 prefer_best_overlap: bool,
3738 matches: Vec<DiscoveryCandidateMatch>,
3739 ) -> Vec<RouterSideId> {
3740 let discovered_origin = if Self::has_typed_route_overrides_locked(st, exclude, ty)
3741 || !target_senders.is_empty()
3742 {
3743 RouteSelectionOrigin::Flood
3744 } else {
3745 RouteSelectionOrigin::Discovered
3746 };
3747
3748 let mut matches = matches;
3749 if matches.iter().any(|m| m.overlap == usize::MAX) {
3750 matches.retain(|m| m.overlap == usize::MAX);
3751 }
3752
3753 let selected: Vec<RouterSideId> = if prefer_best_overlap {
3754 let best_overlap = matches.iter().map(|m| m.overlap).max().unwrap_or(0);
3755 matches
3756 .into_iter()
3757 .filter(|m| m.overlap == best_overlap)
3758 .map(|m| m.side)
3759 .collect()
3760 } else {
3761 matches.into_iter().map(|m| m.side).collect()
3762 };
3763
3764 let has_distributed_variable_owners = discovered_origin == RouteSelectionOrigin::Discovered
3771 && selected.iter().any(|side| {
3772 st.discovery_routes
3773 .get(side)
3774 .is_some_and(|route| route.reachable_network_variables.contains(&ty))
3775 });
3776 if discovered_origin == RouteSelectionOrigin::Discovered
3777 && (DataType::try_named("HEARTBEAT") == Some(ty) || has_distributed_variable_owners)
3778 {
3779 selected
3780 } else {
3781 self.apply_route_selection_locked(st, exclude, selected, discovered_origin)
3782 }
3783 }
3784
3785 fn register_end_to_end_reliable_tx(&self, data: &RouterItem) -> TelemetryResult<()> {
3786 let packet_id = Self::get_hash(data);
3787 let now_ms = self.clock.now_ms();
3788 let ty = match data {
3789 RouterItem::Packet(pkt) => pkt.data_type(),
3790 RouterItem::Packed(bytes) => wire_format::peek_envelope(bytes.as_ref())?.ty,
3791 };
3792 let mut st = self.state.lock();
3793 #[cfg(feature = "discovery")]
3794 let mut pending_destinations = self.expected_end_to_end_destinations_locked(&st, data)?;
3795 #[cfg(not(feature = "discovery"))]
3796 let mut pending_destinations = BTreeMap::new();
3797 self.filter_trackable_end_to_end_destinations_locked(&st, ty, &mut pending_destinations);
3798 let tracked_destinations = !pending_destinations.is_empty();
3799 Self::remember_end_to_end_reliable_tx_locked(&mut st, packet_id);
3800 st.end_to_end_reliable_tx.insert(
3801 packet_id,
3802 EndToEndReliableSent {
3803 data: data.clone(),
3804 pending_destinations,
3805 tracked_destinations,
3806 last_send_ms: now_ms,
3807 retries: 0,
3808 queued: false,
3809 },
3810 );
3811 Ok(())
3812 }
3813
3814 #[cfg(feature = "discovery")]
3815 fn reconcile_end_to_end_reliable_destinations_locked(
3816 &self,
3817 st: &mut RouterInner,
3818 ) -> TelemetryResult<()> {
3819 let active_destinations = self.active_end_to_end_destinations_locked(st);
3820 let packet_ids: Vec<u64> = st.end_to_end_reliable_tx.keys().copied().collect();
3821 let mut completed = Vec::new();
3822
3823 for packet_id in packet_ids {
3824 let Some(data) = st
3825 .end_to_end_reliable_tx
3826 .get(&packet_id)
3827 .map(|sent| sent.data.clone())
3828 else {
3829 continue;
3830 };
3831 let expected = self.expected_end_to_end_destinations_locked(st, &data)?;
3832 let Some(sent) = st.end_to_end_reliable_tx.get_mut(&packet_id) else {
3833 continue;
3834 };
3835 if !sent.tracked_destinations {
3836 continue;
3837 }
3838 sent.pending_destinations.retain(|sender_hash, side| {
3839 match (
3840 expected.get(sender_hash),
3841 active_destinations.get(sender_hash),
3842 ) {
3843 (Some(next_side), _) | (None, Some(next_side)) => {
3844 *side = *next_side;
3845 true
3846 }
3847 (None, None) => false,
3848 }
3849 });
3850 if sent.pending_destinations.is_empty() {
3851 completed.push(packet_id);
3852 }
3853 }
3854
3855 for packet_id in completed {
3856 st.end_to_end_reliable_tx.remove(&packet_id);
3857 }
3858
3859 Ok(())
3860 }
3861
3862 #[cfg(feature = "discovery")]
3863 fn active_end_to_end_destinations_locked(
3864 &self,
3865 st: &RouterInner,
3866 ) -> BTreeMap<u64, RouterSideId> {
3867 let now_ms = self.clock.now_ms();
3868 let mut out = BTreeMap::new();
3869 for (&side, route) in st.discovery_routes.iter() {
3870 if now_ms.saturating_sub(route.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
3871 continue;
3872 }
3873 for sender_state in route.announcers.values() {
3874 if now_ms.saturating_sub(sender_state.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
3875 continue;
3876 }
3877 for board in sender_state.topology_boards.iter() {
3878 if !Self::is_end_to_end_destination_sender(&board.sender_id) {
3879 continue;
3880 }
3881 out.insert(Self::sender_hash(&board.sender_id), side);
3882 if out.len() >= runtime_reliable_max_end_to_end_pending().max(1) {
3883 return out;
3884 }
3885 }
3886 }
3887 }
3888 out
3889 }
3890
3891 fn side_supports_end_to_end_tracking_locked(st: &RouterInner, side: RouterSideId) -> bool {
3892 matches!(
3893 st.sides
3894 .get(side)
3895 .and_then(Option::as_ref)
3896 .map(|side| &side.tx_handler),
3897 Some(RouterTxHandlerFn::Packed(_))
3898 )
3899 }
3900
3901 fn filter_trackable_end_to_end_destinations_locked(
3902 &self,
3903 st: &RouterInner,
3904 ty: DataType,
3905 pending: &mut BTreeMap<u64, RouterSideId>,
3906 ) {
3907 let now_ms = self.clock.now_ms();
3908 pending.retain(|_, side| {
3909 Self::side_supports_end_to_end_tracking_locked(st, *side)
3910 && (is_reliable_type(ty)
3911 || !self.side_has_multiple_announcers_locked(st, *side, now_ms))
3912 });
3913 }
3914
3915 #[cfg(feature = "discovery")]
3916 fn side_has_multiple_announcers_locked(
3917 &self,
3918 st: &RouterInner,
3919 side: RouterSideId,
3920 now_ms: u64,
3921 ) -> bool {
3922 st.discovery_routes
3923 .get(&side)
3924 .map(|route| {
3925 route
3926 .announcers
3927 .values()
3928 .filter(|sender| {
3929 now_ms.saturating_sub(sender.last_seen_ms) <= DISCOVERY_ROUTE_TTL_MS
3930 })
3931 .take(2)
3932 .count()
3933 > 1
3934 })
3935 .unwrap_or(false)
3936 }
3937
3938 #[cfg(not(feature = "discovery"))]
3939 fn side_has_multiple_announcers_locked(
3940 &self,
3941 _st: &RouterInner,
3942 _side: RouterSideId,
3943 _now_ms: u64,
3944 ) -> bool {
3945 false
3946 }
3947
3948 fn queue_end_to_end_reliable_ack(
3949 &self,
3950 pkt: &Packet,
3951 called_from_queue: bool,
3952 ) -> TelemetryResult<()> {
3953 self.queue_end_to_end_reliable_ack_for_packet_id(pkt.packet_id(), called_from_queue)
3954 }
3955
3956 fn queue_end_to_end_reliable_ack_for_packet_id(
3957 &self,
3958 packet_id: u64,
3959 called_from_queue: bool,
3960 ) -> TelemetryResult<()> {
3961 let ack_sender = self.encode_end_to_end_ack_sender();
3962 let ack = Packet::new(
3963 DataType::ReliableAck,
3964 message_meta(DataType::ReliableAck).endpoints_ref(),
3965 ack_sender.as_str(),
3966 self.packet_timestamp_ms(),
3967 Self::encode_end_to_end_reliable_ack(packet_id),
3968 )?;
3969 self.emit_internal_tx(
3970 RouterTxItem::Broadcast(RouterItem::Packet(ack)),
3971 true,
3972 called_from_queue,
3973 )
3974 }
3975
3976 fn emit_internal_tx(
3977 &self,
3978 item: RouterTxItem,
3979 ignore_local: bool,
3980 called_from_queue: bool,
3981 ) -> TelemetryResult<()> {
3982 if called_from_queue {
3983 self.tx_queue_item_with_flags(item, ignore_local)
3984 } else {
3985 self.tx_item_impl(item, ignore_local, false)
3986 }
3987 }
3988
3989 fn emit_internal_tx_with_priority(
3990 &self,
3991 item: RouterTxItem,
3992 ignore_local: bool,
3993 priority: u8,
3994 called_from_queue: bool,
3995 ) -> TelemetryResult<()> {
3996 if called_from_queue {
3997 self.tx_queue_item_with_priority(item, ignore_local, priority)
3998 } else {
3999 self.tx_item_impl(item, ignore_local, false)
4000 }
4001 }
4002
4003 fn queue_end_to_end_reliable_retransmit(&self, packet_id: u64) -> TelemetryResult<()> {
4004 {
4005 let mut st = self.state.lock();
4006 let Some(sent) = st.end_to_end_reliable_tx.get_mut(&packet_id) else {
4007 return Ok(());
4008 };
4009 if sent.queued {
4010 return Ok(());
4011 }
4012 sent.queued = true;
4013 }
4014 self.tx_queue_item_with_priority(
4015 RouterTxItem::EndToEndReplay { packet_id },
4016 true,
4017 Self::router_item_priority_bumped(DataType::ReliableAck),
4018 )
4019 }
4020
4021 fn end_to_end_retransmit_sides(
4022 &self,
4023 packet_id: u64,
4024 ) -> Option<(RouterItem, Vec<RouterSideId>)> {
4025 let mut st = self.state.lock();
4026 let (data, tracked_destinations, mut sides) = {
4027 let sent = st.end_to_end_reliable_tx.get_mut(&packet_id)?;
4028 sent.queued = false;
4029 sent.last_send_ms = self.clock.now_ms();
4030 let data = sent.data.clone();
4031 let tracked_destinations = sent.tracked_destinations;
4032 let sides: Vec<RouterSideId> = sent.pending_destinations.values().copied().collect();
4033 (data, tracked_destinations, sides)
4034 };
4035 if tracked_destinations && sides.is_empty() {
4036 st.end_to_end_reliable_tx.remove(&packet_id);
4037 return None;
4038 }
4039 sides.sort_unstable();
4040 sides.dedup();
4041 Some((data, sides))
4042 }
4043
4044 fn router_item_priority(data: &RouterItem) -> TelemetryResult<u8> {
4045 let ty = match data {
4046 RouterItem::Packet(pkt) => pkt.data_type(),
4047 RouterItem::Packed(bytes) => wire_format::peek_envelope(bytes.as_ref())?.ty,
4048 };
4049 Ok(crate::scheduler_priority(ty))
4050 }
4051
4052 #[inline]
4053 fn router_item_priority_bumped(ty: DataType) -> u8 {
4054 crate::scheduler_priority(ty).saturating_add(16)
4055 }
4056
4057 #[inline]
4058 fn is_side_tx_busy(err: &TelemetryError) -> bool {
4059 matches!(err, TelemetryError::Io("side tx busy"))
4060 }
4061
4062 #[cfg(feature = "timesync")]
4063 fn timesync_has_usable_time_locked(st: &TimeSyncRuntime, now_mono_ns: u64) -> bool {
4064 st.disciplined_clock.read_unix_ms(now_mono_ns).is_some()
4065 || st
4066 .clock
4067 .current_time(now_mono_ns)
4068 .and_then(|reading| reading.unix_time_ms)
4069 .is_some()
4070 }
4071
4072 #[cfg(feature = "timesync")]
4073 fn reconcile_pending_timesync_request_locked(
4074 st: &mut TimeSyncRuntime,
4075 leader: &Option<TimeSyncLeader>,
4076 now_ms: u64,
4077 ) {
4078 let active_remote = match leader {
4079 Some(TimeSyncLeader::Remote(remote)) => Some(remote.sender.as_str()),
4080 _ => None,
4081 };
4082 let should_clear = st
4083 .pending_request
4084 .as_ref()
4085 .is_some_and(|pending| Some(pending.source.as_str()) != active_remote);
4086 if should_clear {
4087 st.pending_request = None;
4088 st.next_request_mono_ms = now_ms;
4089 }
4090 }
4091
4092 #[inline]
4094 fn enqueue_to_sides(
4095 &self,
4096 data: RouterItem,
4097 exclude: Option<RouterSideId>,
4098 ignore_local: bool,
4099 ) -> TelemetryResult<()> {
4100 let data = self.clear_intermediate_hop_targets(data)?;
4101 let plan = self.remote_side_plan(&data, exclude)?;
4102 let mut st = self.state.lock();
4103 let ty = Self::item_data_type(&data)?;
4104 let priority = if st.managed_variable_types.contains(&ty.as_u32()) {
4105 crate::transport_priority(DataType::ManagedVariableValue)
4106 } else {
4107 Self::router_item_priority(&data)?
4108 };
4109
4110 let RemoteSidePlan::Target(sides) = plan;
4111 for idx in sides {
4112 st.push_transmit(TxQueued {
4113 item: RouterTxItem::ToSide {
4114 src: exclude,
4115 dst: idx,
4116 data: data.clone(),
4117 },
4118 ignore_local,
4119 priority,
4120 })?;
4121 }
4122
4123 Ok(())
4124 }
4125
4126 fn relay_send(
4127 &self,
4128 data: RouterItem,
4129 src: Option<RouterSideId>,
4130 called_from_queue: bool,
4131 ) -> TelemetryResult<()> {
4132 if called_from_queue {
4133 return self.enqueue_to_sides(data, src, true);
4134 }
4135
4136 let data = self.clear_intermediate_hop_targets(data)?;
4137 let RemoteSidePlan::Target(sides) = self.remote_side_plan(&data, src)?;
4138 for side in sides {
4139 self.tx_item_impl(
4140 RouterTxItem::ToSide {
4141 src,
4142 dst: side,
4143 data: data.clone(),
4144 },
4145 true,
4146 false,
4147 )?;
4148 }
4149
4150 Ok(())
4151 }
4152
4153 fn item_route_info(&self, data: &RouterItem) -> TelemetryResult<(Vec<DataEndpoint>, DataType)> {
4154 match data {
4155 RouterItem::Packet(pkt) => {
4156 pkt.validate()?;
4157 let mut eps = pkt.endpoints().to_vec();
4158 eps.sort_unstable();
4159 eps.dedup();
4160 Ok((eps, pkt.data_type()))
4161 }
4162 RouterItem::Packed(bytes) => {
4163 let env = wire_format::peek_envelope(bytes.as_ref())?;
4164 let mut eps: Vec<DataEndpoint> = env.endpoints.iter().copied().collect();
4165 eps.sort_unstable();
4166 eps.dedup();
4167 Ok((eps, env.ty))
4168 }
4169 }
4170 }
4171
4172 fn item_data_type(data: &RouterItem) -> TelemetryResult<DataType> {
4173 match data {
4174 RouterItem::Packet(pkt) => Ok(pkt.data_type()),
4175 RouterItem::Packed(bytes) => Ok(wire_format::peek_envelope(bytes.as_ref())?.ty),
4176 }
4177 }
4178
4179 fn e2e_crypto_supported(&self) -> bool {
4180 #[cfg(feature = "cryptography")]
4181 {
4182 self.cfg.e2e_encryption() != RouterE2eEncryptionMode::Disabled
4183 && crate::crypto::registered_crypto_available()
4184 }
4185 #[cfg(not(feature = "cryptography"))]
4186 {
4187 false
4188 }
4189 }
4190
4191 fn should_require_e2e_for_type(&self, ty: DataType) -> bool {
4192 if is_internal_control_type(ty) {
4193 return false;
4194 }
4195 match self.cfg.e2e_encryption() {
4196 RouterE2eEncryptionMode::Disabled => {
4197 message_e2e_encryption_policy(ty) == E2eEncryptionPolicy::RequireOn
4198 }
4199 RouterE2eEncryptionMode::RequiredOnly => {
4200 message_e2e_encryption_policy(ty) == E2eEncryptionPolicy::RequireOn
4201 }
4202 RouterE2eEncryptionMode::Preferred => matches!(
4203 message_e2e_encryption_policy(ty),
4204 E2eEncryptionPolicy::PreferOn | E2eEncryptionPolicy::RequireOn
4205 ),
4206 RouterE2eEncryptionMode::ForceAll => true,
4207 }
4208 }
4209
4210 fn ensure_e2e_policy_supported_for_type(&self, ty: DataType) -> TelemetryResult<()> {
4211 if self.should_require_e2e_for_type(ty) && !self.e2e_crypto_supported() {
4212 return Err(TelemetryError::BadArg);
4213 }
4214 Ok(())
4215 }
4216
4217 #[cfg(feature = "cryptography")]
4218 fn e2e_seal_config_for_type(&self, ty: DataType) -> Option<wire_format::E2eSealConfig> {
4219 if self.should_require_e2e_for_type(ty) && self.e2e_crypto_supported() {
4220 Some(wire_format::E2eSealConfig {
4221 key_id: self.cfg.e2e_key_id(),
4222 })
4223 } else {
4224 None
4225 }
4226 }
4227
4228 #[inline]
4229 fn pack_packet_for_router(
4230 &self,
4231 pkt: &Packet,
4232 reliable: Option<wire_format::ReliableHeader>,
4233 ) -> TelemetryResult<Arc<[u8]>> {
4234 #[cfg(feature = "cryptography")]
4235 if let Some(e2e) = self.e2e_seal_config_for_type(pkt.data_type()) {
4236 return wire_format::pack_packet_with_wire_contract_e2e(
4237 pkt,
4238 reliable,
4239 pkt.wire_shape(),
4240 pkt.wire_target_senders(),
4241 e2e,
4242 );
4243 }
4244 Ok(match reliable {
4245 Some(hdr) => wire_format::pack_packet_with_reliable(pkt, hdr),
4246 None => wire_format::pack_packet(pkt),
4247 })
4248 }
4249
4250 #[inline]
4251 fn pack_packet_for_contract(
4252 &self,
4253 pkt: &Packet,
4254 reliable: Option<wire_format::ReliableHeader>,
4255 shape: Option<MessageElement>,
4256 target_senders: &[u64],
4257 ) -> TelemetryResult<Arc<[u8]>> {
4258 #[cfg(feature = "cryptography")]
4259 if let Some(e2e) = self.e2e_seal_config_for_type(pkt.data_type()) {
4260 return wire_format::pack_packet_with_wire_contract_e2e(
4261 pkt,
4262 reliable,
4263 shape,
4264 target_senders,
4265 e2e,
4266 );
4267 }
4268 wire_format::pack_packet_with_wire_contract(pkt, reliable, shape, target_senders)
4269 }
4270
4271 #[cfg(feature = "cryptography")]
4272 #[inline]
4273 fn prepare_packed_for_remote(
4274 &self,
4275 bytes: Arc<[u8]>,
4276 reliable_override: Option<Option<wire_format::ReliableHeader>>,
4277 ) -> TelemetryResult<Arc<[u8]>> {
4278 let frame = wire_format::peek_frame_info(bytes.as_ref())?;
4279 if frame.ack_only() || self.e2e_seal_config_for_type(frame.envelope.ty).is_none() {
4280 return Ok(bytes);
4281 }
4282 let reliable = reliable_override.unwrap_or(frame.reliable);
4283 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
4284 self.pack_packet_for_contract(
4285 &pkt,
4286 reliable,
4287 frame.envelope.wire_shape,
4288 &frame.envelope.target_senders,
4289 )
4290 }
4291
4292 fn item_target_senders(&self, data: &RouterItem) -> TelemetryResult<Arc<[u64]>> {
4293 match data {
4294 RouterItem::Packet(pkt) => Ok(Arc::from(pkt.wire_target_senders())),
4295 RouterItem::Packed(bytes) => {
4296 Ok(wire_format::peek_envelope(bytes.as_ref())?.target_senders)
4297 }
4298 }
4299 }
4300
4301 fn item_targets_local_sender(&self, data: &RouterItem) -> TelemetryResult<bool> {
4302 let targets = self.item_target_senders(data)?;
4303 if targets.is_empty() {
4304 return Ok(true);
4305 }
4306 let local_sender = self.sender_arc();
4307 let local_hash = Self::sender_hash(local_sender.as_ref());
4308 Ok(targets.contains(&local_hash))
4309 }
4310
4311 fn item_targets_router_as_intermediate_hop(
4312 &self,
4313 data: &RouterItem,
4314 endpoints: &[DataEndpoint],
4315 ) -> TelemetryResult<bool> {
4316 let targets = self.item_target_senders(data)?;
4317 if targets.is_empty()
4318 || endpoints.iter().copied().any(|endpoint| {
4319 self.endpoint_has_packet_handler(endpoint)
4320 || self.endpoint_has_packed_handler(endpoint)
4321 })
4322 {
4323 return Ok(false);
4324 }
4325 let local_sender = self.sender_arc();
4326 Ok(targets.contains(&Self::sender_hash(local_sender.as_ref())))
4327 }
4328
4329 fn clear_intermediate_hop_targets(&self, data: RouterItem) -> TelemetryResult<RouterItem> {
4330 let (endpoints, _) = self.item_route_info(&data)?;
4331 if !self.item_targets_router_as_intermediate_hop(&data, &endpoints)? {
4332 return Ok(data);
4333 }
4334 let pkt = match &data {
4335 RouterItem::Packet(pkt) => pkt.clone(),
4336 RouterItem::Packed(bytes) => wire_format::unpack_packet(bytes.as_ref())?,
4337 };
4338 let reliable = match &data {
4339 RouterItem::Packet(_) => None,
4340 RouterItem::Packed(bytes) => wire_format::peek_frame_info(bytes.as_ref())?.reliable,
4341 };
4342 let shape = match &data {
4343 RouterItem::Packet(pkt) => pkt.wire_shape(),
4344 RouterItem::Packed(bytes) => wire_format::peek_envelope(bytes.as_ref())?.wire_shape,
4345 };
4346 Ok(RouterItem::Packed(self.pack_packet_for_contract(
4347 &pkt,
4348 reliable,
4349 shape,
4350 &[],
4351 )?))
4352 }
4353
4354 #[cfg(feature = "discovery")]
4355 fn side_matches_target_senders_locked(
4356 st: &RouterInner,
4357 side: RouterSideId,
4358 target_senders: &[u64],
4359 now_ms: u64,
4360 ) -> bool {
4361 st.discovery_routes
4362 .get(&side)
4363 .map(|route| {
4364 if now_ms.saturating_sub(route.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
4365 return false;
4366 }
4367 route.announcers.values().any(|sender_state| {
4368 if now_ms.saturating_sub(sender_state.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
4369 return false;
4370 }
4371 sender_state
4372 .topology_boards
4373 .iter()
4374 .any(|board| target_senders.contains(&Self::sender_hash(&board.sender_id)))
4375 })
4376 })
4377 .unwrap_or(false)
4378 }
4379
4380 fn attach_wire_contract_to_item(
4381 &self,
4382 data: RouterItem,
4383 target_senders: &[u64],
4384 ) -> TelemetryResult<RouterItem> {
4385 match data {
4386 RouterItem::Packet(pkt) => {
4387 let reliable = if is_reliable_type(pkt.data_type()) {
4388 Some(wire_format::ReliableHeader {
4389 flags: wire_format::RELIABLE_FLAG_UNSEQUENCED,
4390 seq: 0,
4391 ack: 0,
4392 })
4393 } else {
4394 None
4395 };
4396 let bytes = self.pack_packet_for_contract(
4397 &pkt,
4398 reliable,
4399 Some(message_meta(pkt.data_type()).element),
4400 target_senders,
4401 )?;
4402 Ok(RouterItem::Packed(bytes))
4403 }
4404 RouterItem::Packed(bytes) => Ok(RouterItem::Packed(bytes)),
4405 }
4406 }
4407
4408 fn endpoints_are_link_local_only(eps: &[DataEndpoint]) -> bool {
4409 !eps.is_empty() && eps.iter().all(|ep| ep.is_link_local_only())
4410 }
4411
4412 fn should_route_remote(
4413 &self,
4414 data: &RouterItem,
4415 exclude: Option<RouterSideId>,
4416 ) -> TelemetryResult<bool> {
4417 #[cfg(feature = "discovery")]
4418 {
4419 let RemoteSidePlan::Target(sides) = self.remote_side_plan(data, exclude)?;
4420 Ok(!sides.is_empty())
4421 }
4422
4423 #[cfg(not(feature = "discovery"))]
4424 {
4425 let (eps, ty) = self.item_route_info(data)?;
4426 if !(has_nonlocal_endpoint(&eps, &self.cfg) || force_remote_for_type(ty)) {
4427 return Ok(false);
4428 }
4429 let st = self.state.lock();
4430 Ok(!self
4431 .eligible_side_ids_locked(
4432 &st,
4433 exclude,
4434 Some(ty),
4435 Self::endpoints_are_link_local_only(&eps),
4436 )
4437 .is_empty())
4438 }
4439 }
4440
4441 #[cfg(feature = "discovery")]
4442 fn has_explicit_route_policy_locked(
4443 st: &RouterInner,
4444 src: Option<RouterSideId>,
4445 ty: DataType,
4446 ) -> bool {
4447 st.route_overrides
4448 .keys()
4449 .any(|(route_src, _)| *route_src == src)
4450 || Self::has_typed_route_overrides_locked(st, src, ty)
4451 }
4452
4453 fn remote_side_plan(
4454 &self,
4455 data: &RouterItem,
4456 exclude: Option<RouterSideId>,
4457 ) -> TelemetryResult<RemoteSidePlan> {
4458 #[cfg(feature = "discovery")]
4459 {
4460 let (eps, ty) = self.item_route_info(data)?;
4461 let target_senders = self.item_target_senders(data)?;
4462 let resolve_beyond_local_hop =
4463 self.item_targets_router_as_intermediate_hop(data, &eps)?;
4464 let routing_target_senders: &[u64] = if resolve_beyond_local_hop {
4465 &[]
4466 } else {
4467 target_senders.as_ref()
4468 };
4469 let preferred_packet_id = Self::reliable_control_target_packet_id(data)?;
4470 if discovery::is_discovery_type(ty) {
4471 let mut st = self.state.lock();
4472 let sides = self.eligible_side_ids_locked(&st, exclude, Some(ty), false);
4473 return Ok(RemoteSidePlan::Target(self.apply_route_selection_locked(
4474 &mut st,
4475 exclude,
4476 sides,
4477 RouteSelectionOrigin::Flood,
4478 )));
4479 }
4480 if !(has_nonlocal_endpoint(&eps, &self.cfg) || force_remote_for_type(ty)) {
4481 return Ok(RemoteSidePlan::Target(Vec::new()));
4482 }
4483
4484 #[cfg(feature = "timesync")]
4485 let preferred_timesync_source = self.preferred_timesync_route_source(data, ty)?;
4486 #[cfg(not(feature = "timesync"))]
4487 let preferred_timesync_source: Option<String> = None;
4488
4489 let mut st = self.state.lock();
4490 if let Some(packet_id) = preferred_packet_id {
4491 let target_side = st
4492 .reliable_return_routes
4493 .get(&packet_id)
4494 .map(|route| route.side);
4495 if let Some(side) = target_side
4496 .filter(|side| self.route_allowed_locked(&st, exclude, Some(ty), *side))
4497 {
4498 #[cfg(feature = "timesync")]
4499 if !Self::timesync_allowed_for_side_locked(
4500 &mut st,
4501 side,
4502 ty,
4503 self.clock.now_ms(),
4504 ) {
4505 return Ok(RemoteSidePlan::Target(Vec::new()));
4506 }
4507 return Ok(RemoteSidePlan::Target(vec![side]));
4508 }
4509 return Ok(RemoteSidePlan::Target(Vec::new()));
4510 }
4511 let restrict_link_local = Self::endpoints_are_link_local_only(&eps);
4512 let prefer_best_overlap = is_reliable_type(ty)
4513 && routing_target_senders.is_empty()
4514 && preferred_packet_id.is_none();
4515 if st.discovery_routes.is_empty() {
4516 let mut fallback =
4517 self.eligible_side_ids_locked(&st, exclude, Some(ty), restrict_link_local);
4518 #[cfg(feature = "timesync")]
4519 {
4520 fallback = Self::filter_timesync_sides_locked(
4521 &mut st,
4522 ty,
4523 self.clock.now_ms(),
4524 fallback,
4525 );
4526 }
4527 return Ok(RemoteSidePlan::Target(if fallback.len() == 1 {
4528 fallback
4529 } else {
4530 Vec::new()
4531 }));
4532 }
4533 let mut matches = self.discovered_route_candidates_locked(
4534 &st,
4535 exclude,
4536 ty,
4537 &eps,
4538 routing_target_senders,
4539 prefer_best_overlap,
4540 preferred_timesync_source.as_deref(),
4541 );
4542 #[cfg(feature = "timesync")]
4543 {
4544 matches =
4545 Self::filter_timesync_matches_locked(&mut st, ty, self.clock.now_ms(), matches);
4546 }
4547 let has_distributed_variable_owners = matches.iter().any(|candidate| {
4553 st.discovery_routes
4554 .get(&candidate.side)
4555 .is_some_and(|route| route.reachable_network_variables.contains(&ty))
4556 });
4557 if DataType::try_named("HEARTBEAT") != Some(ty) && !has_distributed_variable_owners {
4558 Self::retain_shortest_discovery_candidates_locked(
4559 &st,
4560 &mut matches,
4561 &eps,
4562 routing_target_senders,
4563 self.clock.now_ms(),
4564 );
4565 }
4566
4567 if !matches.is_empty() {
4568 Ok(RemoteSidePlan::Target(
4569 self.select_discovered_candidate_sides_locked(
4570 &mut st,
4571 exclude,
4572 ty,
4573 routing_target_senders,
4574 prefer_best_overlap,
4575 matches,
4576 ),
4577 ))
4578 } else if prefer_best_overlap {
4579 Ok(RemoteSidePlan::Target(Vec::new()))
4580 } else {
4581 if Self::has_explicit_route_policy_locked(&st, exclude, ty) {
4582 let mut sides =
4583 self.eligible_side_ids_locked(&st, exclude, Some(ty), restrict_link_local);
4584 #[cfg(feature = "timesync")]
4585 {
4586 sides = Self::filter_timesync_sides_locked(
4587 &mut st,
4588 ty,
4589 self.clock.now_ms(),
4590 sides,
4591 );
4592 }
4593 Ok(RemoteSidePlan::Target(self.apply_route_selection_locked(
4594 &mut st,
4595 exclude,
4596 sides,
4597 RouteSelectionOrigin::Flood,
4598 )))
4599 } else {
4600 Ok(RemoteSidePlan::Target(Vec::new()))
4601 }
4602 }
4603 }
4604 #[cfg(not(feature = "discovery"))]
4605 {
4606 let (_, ty) = self.item_route_info(data)?;
4607 let mut st = self.state.lock();
4608 if let Some(packet_id) = Self::reliable_control_target_packet_id(data)? {
4609 let target_side = st
4610 .reliable_return_routes
4611 .get(&packet_id)
4612 .map(|route| route.side);
4613 if let Some(side) = target_side
4614 .filter(|side| self.route_allowed_locked(&st, exclude, Some(ty), *side))
4615 {
4616 return Ok(RemoteSidePlan::Target(vec![side]));
4617 }
4618 return Ok(RemoteSidePlan::Target(Vec::new()));
4619 }
4620 let sides = self.eligible_side_ids_locked(&st, exclude, Some(ty), false);
4621 Ok(RemoteSidePlan::Target(self.apply_route_selection_locked(
4622 &mut st,
4623 exclude,
4624 sides,
4625 RouteSelectionOrigin::Flood,
4626 )))
4627 }
4628 }
4629
4630 #[cfg(feature = "discovery")]
4631 fn local_discovery_endpoints(&self) -> Vec<DataEndpoint> {
4632 let mut eps: Vec<DataEndpoint> = self.cfg.handlers.iter().map(|h| h.endpoint).collect();
4633 #[cfg(feature = "timesync")]
4634 if self.cfg.timesync_config().is_some() {
4635 eps.push(DataEndpoint::TimeSync);
4636 }
4637 eps.retain(|ep| !discovery::is_discovery_endpoint(*ep));
4638 eps.sort_unstable();
4639 eps.dedup();
4640 eps
4641 }
4642
4643 #[cfg(feature = "discovery")]
4644 fn local_discovery_timesync_sources(&self, now_ms: u64) -> Vec<String> {
4645 #[cfg(feature = "timesync")]
4646 {
4647 let st = self.timesync.lock();
4648 if let Some(tracker) = st.tracker.as_ref()
4649 && tracker.should_serve(
4650 now_ms,
4651 Self::timesync_has_usable_time_locked(&st, self.monotonic_now_ns()),
4652 )
4653 {
4654 return vec![self.sender_arc().to_string()];
4655 }
4656 }
4657 Vec::new()
4658 }
4659
4660 #[cfg(all(feature = "discovery", feature = "timesync"))]
4661 fn preferred_timesync_route_source(
4662 &self,
4663 data: &RouterItem,
4664 ty: DataType,
4665 ) -> TelemetryResult<Option<String>> {
4666 if !matches!(
4667 ty,
4668 DataType::TimeSyncAnnounce | DataType::TimeSyncRequest | DataType::TimeSyncResponse
4669 ) {
4670 return Ok(None);
4671 }
4672
4673 match data {
4674 RouterItem::Packet(pkt) => match ty {
4675 DataType::TimeSyncRequest => {
4676 let local_sender = self.sender_arc();
4677 if pkt.sender() == local_sender.as_ref() {
4678 Ok(self.timesync.lock().tracker.as_ref().and_then(|tracker| {
4679 tracker.current_source().map(|src| src.sender.clone())
4680 }))
4681 } else {
4682 Ok(None)
4683 }
4684 }
4685 DataType::TimeSyncAnnounce | DataType::TimeSyncResponse => {
4686 Ok(Some(pkt.sender().to_owned()))
4687 }
4688 _ => Ok(None),
4689 },
4690 RouterItem::Packed(bytes) => {
4691 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
4692 self.preferred_timesync_route_source(&RouterItem::Packet(pkt), ty)
4693 }
4694 }
4695 }
4696
4697 #[cfg(feature = "discovery")]
4698 fn note_discovery_topology_change_locked(st: &mut RouterInner, now_ms: u64) {
4699 st.discovery_cadence.on_topology_change(now_ms);
4700 }
4701
4702 #[cfg(feature = "discovery")]
4703 fn sender_topology_board_mut<'a>(
4704 sender_state: &'a mut DiscoverySenderState,
4705 sender_id: &str,
4706 ) -> &'a mut TopologyBoardNode {
4707 if let Some(idx) = sender_state
4708 .topology_boards
4709 .iter()
4710 .position(|board| board.sender_id == sender_id)
4711 {
4712 return &mut sender_state.topology_boards[idx];
4713 }
4714 sender_state.topology_boards.push(TopologyBoardNode {
4715 sender_id: sender_id.to_string(),
4716 reachable_endpoints: Vec::new(),
4717 reachable_timesync_sources: Vec::new(),
4718 connections: Vec::new(),
4719 });
4720 sender_state
4721 .topology_boards
4722 .last_mut()
4723 .expect("board inserted above")
4724 }
4725
4726 #[cfg(feature = "discovery")]
4727 fn refresh_sender_topology_state(sender_state: &mut DiscoverySenderState) {
4728 discovery::normalize_topology_boards(&mut sender_state.topology_boards);
4729 let (reachable, reachable_timesync_sources) =
4730 discovery::summarize_topology_boards(&sender_state.topology_boards);
4731 sender_state.reachable = reachable;
4732 sender_state.reachable_timesync_sources = reachable_timesync_sources;
4733 }
4734
4735 #[cfg(feature = "discovery")]
4736 fn recompute_discovery_side_state(route: &mut DiscoverySideState) {
4737 let mut reachable = Vec::new();
4738 let mut reachable_network_variables = Vec::new();
4739 let mut reachable_timesync_sources = Vec::new();
4740 let mut last_seen_ms = 0u64;
4741 for sender in route.announcers.values() {
4742 reachable.extend(sender.reachable.iter().copied());
4743 reachable_network_variables.extend(sender.reachable_network_variables.iter().copied());
4744 reachable_timesync_sources.extend(sender.reachable_timesync_sources.iter().cloned());
4745 last_seen_ms = last_seen_ms.max(sender.last_seen_ms);
4746 }
4747 reachable.sort_unstable();
4748 reachable.dedup();
4749 reachable_network_variables.sort_unstable();
4750 reachable_network_variables.dedup();
4751 reachable_timesync_sources.sort_unstable();
4752 reachable_timesync_sources.dedup();
4753 route.reachable = reachable;
4754 route.reachable_network_variables = reachable_network_variables;
4755 route.reachable_timesync_sources = reachable_timesync_sources;
4756 route.last_seen_ms = last_seen_ms;
4757 }
4758
4759 #[cfg(feature = "discovery")]
4760 fn local_discovery_topology_board(
4761 &self,
4762 st: &RouterInner,
4763 now_ms: u64,
4764 link_local_enabled: bool,
4765 ) -> TopologyBoardNode {
4766 let mut reachable_endpoints = self.local_discovery_endpoints();
4767 if !link_local_enabled {
4768 reachable_endpoints.retain(|ep| !ep.is_link_local_only());
4769 }
4770 let mut connections = Vec::new();
4771 for route in st.discovery_routes.values() {
4772 if now_ms.saturating_sub(route.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
4773 continue;
4774 }
4775 for (sender, sender_state) in route.announcers.iter() {
4776 if now_ms.saturating_sub(sender_state.last_seen_ms) <= DISCOVERY_ROUTE_TTL_MS {
4777 connections.push(sender.clone());
4778 }
4779 }
4780 }
4781 connections.sort_unstable();
4782 connections.dedup();
4783 let sender = self.sender_arc();
4784 TopologyBoardNode {
4785 sender_id: sender.to_string(),
4786 reachable_endpoints,
4787 reachable_timesync_sources: self.local_discovery_timesync_sources(now_ms),
4788 connections,
4789 }
4790 }
4791
4792 #[cfg(feature = "discovery")]
4793 fn advertised_discovery_topology_for_link_locked(
4794 &self,
4795 st: &RouterInner,
4796 now_ms: u64,
4797 link_local_enabled: bool,
4798 exclude_side: Option<RouterSideId>,
4799 ) -> Vec<TopologyBoardNode> {
4800 let mut boards = vec![self.local_discovery_topology_board(st, now_ms, link_local_enabled)];
4801 for (&route_side, route) in st.discovery_routes.iter() {
4802 if exclude_side == Some(route_side) {
4803 continue;
4804 }
4805 if now_ms.saturating_sub(route.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
4806 continue;
4807 }
4808 for (announcer, sender_state) in route.announcers.iter() {
4809 if now_ms.saturating_sub(sender_state.last_seen_ms) > DISCOVERY_ROUTE_TTL_MS {
4810 continue;
4811 }
4812 let mut sender_boards = sender_state.topology_boards.clone();
4813 if sender_boards.is_empty() {
4814 let sender = self.sender_arc();
4815 sender_boards.push(TopologyBoardNode {
4816 sender_id: announcer.clone(),
4817 reachable_endpoints: sender_state.reachable.clone(),
4818 reachable_timesync_sources: sender_state.reachable_timesync_sources.clone(),
4819 connections: vec![sender.to_string()],
4820 });
4821 } else if let Some(board) = sender_boards
4822 .iter_mut()
4823 .find(|board| board.sender_id == *announcer)
4824 {
4825 board.connections.push(self.sender_arc().to_string());
4826 }
4827 if !link_local_enabled {
4828 for board in sender_boards.iter_mut() {
4829 board
4830 .reachable_endpoints
4831 .retain(|ep| !ep.is_link_local_only());
4832 }
4833 }
4834 discovery::merge_topology_boards(&mut boards, &sender_boards);
4835 }
4836 }
4837 discovery::normalize_topology_boards(&mut boards);
4838 boards
4839 }
4840
4841 #[cfg(feature = "discovery")]
4842 fn prune_discovery_routes_locked(st: &mut RouterInner, now_ms: u64) -> bool {
4843 let before = st.discovery_routes.clone();
4844 st.discovery_routes.retain(|_, route| {
4845 route.announcers.retain(|_, sender| {
4846 now_ms.saturating_sub(sender.last_seen_ms) <= DISCOVERY_ROUTE_TTL_MS
4847 });
4848 Self::recompute_discovery_side_state(route);
4849 !route.announcers.is_empty()
4850 });
4851 st.discovery_routes != before
4852 }
4853
4854 #[cfg(feature = "discovery")]
4855 fn advertised_discovery_endpoints_for_link_locked(
4856 &self,
4857 st: &RouterInner,
4858 now_ms: u64,
4859 link_local_enabled: bool,
4860 exclude_side: Option<RouterSideId>,
4861 ) -> Vec<DataEndpoint> {
4862 let (reachable_endpoints, _) = discovery::summarize_topology_boards(
4863 &self.advertised_discovery_topology_for_link_locked(
4864 st,
4865 now_ms,
4866 link_local_enabled,
4867 exclude_side,
4868 ),
4869 );
4870 reachable_endpoints
4871 .into_iter()
4872 .filter(|ep| {
4873 !discovery::is_discovery_endpoint(*ep)
4874 && (link_local_enabled || !ep.is_link_local_only())
4875 })
4876 .collect()
4877 }
4878
4879 #[cfg(feature = "discovery")]
4880 fn advertised_discovery_timesync_sources_for_link_locked(
4881 &self,
4882 st: &RouterInner,
4883 now_ms: u64,
4884 exclude_side: Option<RouterSideId>,
4885 ) -> Vec<String> {
4886 let (_, sources) = discovery::summarize_topology_boards(
4887 &self.advertised_discovery_topology_for_link_locked(st, now_ms, true, exclude_side),
4888 );
4889 sources
4890 }
4891
4892 #[cfg(feature = "discovery")]
4893 fn advertised_network_variables_for_link_locked(
4894 &self,
4895 st: &RouterInner,
4896 now_ms: u64,
4897 exclude_side: Option<RouterSideId>,
4898 ) -> Vec<DataType> {
4899 let mut types: Vec<DataType> = st
4900 .managed_variable_types
4901 .iter()
4902 .copied()
4903 .map(DataType)
4904 .collect();
4905 for (&route_side, route) in st.discovery_routes.iter() {
4906 if exclude_side == Some(route_side) {
4907 continue;
4908 }
4909 if now_ms.saturating_sub(route.last_seen_ms) <= DISCOVERY_ROUTE_TTL_MS {
4910 types.extend(route.reachable_network_variables.iter().copied());
4911 }
4912 }
4913 types.sort_unstable();
4914 types.dedup();
4915 types
4916 }
4917
4918 #[cfg(feature = "discovery")]
4919 fn discovery_master_sender_locked(&self, st: &RouterInner, now_ms: u64) -> String {
4920 let boards = self.advertised_discovery_topology_for_link_locked(st, now_ms, true, None);
4921 discovery::elect_discovery_master(self.sender_arc().as_ref(), &boards)
4922 }
4923
4924 #[cfg(feature = "discovery")]
4925 fn should_answer_discovery_request_locked(
4926 &self,
4927 st: &RouterInner,
4928 requester: &str,
4929 now_ms: u64,
4930 ) -> bool {
4931 if requester == self.sender_arc().as_ref() {
4932 return false;
4933 }
4934 self.discovery_master_sender_locked(st, now_ms) == self.sender_arc().as_ref()
4935 }
4936
4937 #[cfg(feature = "discovery")]
4938 #[inline]
4939 fn side_is_slow_control_link_locked(
4940 st: &RouterInner,
4941 side_id: RouterSideId,
4942 now_ms: u64,
4943 ) -> bool {
4944 st.adaptive_route_stats.get(&side_id).is_some_and(|stats| {
4945 let recent_slow = stats.last_slow_observed_ms > 0
4946 && now_ms.saturating_sub(stats.last_slow_observed_ms)
4947 <= DISCOVERY_SLOW_LINK_FULL_INTERVAL_MS;
4948 stats.sample_count > 0
4949 && ((stats.estimated_bandwidth_bps > 0
4950 && stats.estimated_bandwidth_bps <= CONTROL_SLOW_LINK_CAPACITY_BPS)
4951 || recent_slow)
4952 })
4953 }
4954
4955 #[cfg(feature = "discovery")]
4956 fn discovery_level_for_side_locked(
4957 st: &mut RouterInner,
4958 side_id: RouterSideId,
4959 now_ms: u64,
4960 ) -> Option<DiscoveryAdvertiseLevel> {
4961 if !Self::side_is_slow_control_link_locked(st, side_id, now_ms) {
4962 st.discovery_side_throttle.remove(&side_id);
4963 return Some(DiscoveryAdvertiseLevel::Full);
4964 }
4965
4966 let throttle = st.discovery_side_throttle.entry(side_id).or_default();
4967 if now_ms >= throttle.next_full_ms {
4968 throttle.next_full_ms = now_ms.saturating_add(DISCOVERY_SLOW_LINK_FULL_INTERVAL_MS);
4969 throttle.next_ping_ms = now_ms.saturating_add(DISCOVERY_SLOW_LINK_PING_INTERVAL_MS);
4970 return Some(DiscoveryAdvertiseLevel::Full);
4971 }
4972 if now_ms >= throttle.next_ping_ms {
4973 throttle.next_ping_ms = now_ms.saturating_add(DISCOVERY_SLOW_LINK_PING_INTERVAL_MS);
4974 return Some(DiscoveryAdvertiseLevel::MinimalPing);
4975 }
4976 None
4977 }
4978
4979 #[cfg(all(feature = "discovery", feature = "timesync"))]
4980 #[inline]
4981 fn is_timesync_type(ty: DataType) -> bool {
4982 matches!(
4983 ty,
4984 DataType::TimeSyncAnnounce | DataType::TimeSyncRequest | DataType::TimeSyncResponse
4985 )
4986 }
4987
4988 #[cfg(all(feature = "discovery", feature = "timesync"))]
4989 fn timesync_allowed_for_side_locked(
4990 st: &mut RouterInner,
4991 side_id: RouterSideId,
4992 ty: DataType,
4993 now_ms: u64,
4994 ) -> bool {
4995 if !Self::is_timesync_type(ty) {
4996 return true;
4997 }
4998 if !Self::side_is_slow_control_link_locked(st, side_id, now_ms) {
4999 st.timesync_side_throttle.remove(&side_id);
5000 return true;
5001 }
5002
5003 let throttle = st.timesync_side_throttle.entry(side_id).or_default();
5004 if now_ms >= throttle.next_allowed_ms {
5005 throttle.next_allowed_ms = now_ms.saturating_add(TIMESYNC_SLOW_LINK_MIN_INTERVAL_MS);
5006 return true;
5007 }
5008 false
5009 }
5010
5011 #[cfg(all(feature = "discovery", feature = "timesync"))]
5012 fn filter_timesync_sides_locked(
5013 st: &mut RouterInner,
5014 ty: DataType,
5015 now_ms: u64,
5016 sides: Vec<RouterSideId>,
5017 ) -> Vec<RouterSideId> {
5018 sides
5019 .into_iter()
5020 .filter(|side| Self::timesync_allowed_for_side_locked(st, *side, ty, now_ms))
5021 .collect()
5022 }
5023
5024 #[cfg(all(feature = "discovery", feature = "timesync"))]
5025 fn filter_timesync_matches_locked(
5026 st: &mut RouterInner,
5027 ty: DataType,
5028 now_ms: u64,
5029 matches: Vec<DiscoveryCandidateMatch>,
5030 ) -> Vec<DiscoveryCandidateMatch> {
5031 matches
5032 .into_iter()
5033 .filter(|m| Self::timesync_allowed_for_side_locked(st, m.side, ty, now_ms))
5034 .collect()
5035 }
5036
5037 #[cfg(feature = "discovery")]
5038 fn emit_discovery_snapshot(
5039 &self,
5040 called_from_queue: bool,
5041 include_schema: bool,
5042 include_topology: bool,
5043 ) -> TelemetryResult<()> {
5044 let now_ms = self.clock.now_ms();
5045 let per_side = {
5046 let mut st = self.state.lock();
5047 if Self::prune_discovery_routes_locked(&mut st, now_ms) {
5048 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
5049 Self::note_discovery_topology_change_locked(&mut st, now_ms);
5050 }
5051 st.fit_discovery_budget();
5052 let side_entries = st
5053 .sides
5054 .iter()
5055 .enumerate()
5056 .filter_map(|(side_id, side)| {
5057 side.as_ref()
5058 .map(|side| (side_id, side.opts.link_local_enabled, side.opts))
5059 })
5060 .collect::<Vec<_>>();
5061 let local_is_master =
5062 self.discovery_master_sender_locked(&st, now_ms) == self.sender_arc().as_ref();
5063 let mut per_side = Vec::new();
5064 for (side_id, link_local_enabled, opts) in side_entries {
5065 if !self.route_allowed_locked(&st, None, Some(DataType::DiscoveryAnnounce), side_id)
5066 {
5067 continue;
5068 }
5069 let Some(level) = Self::discovery_level_for_side_locked(&mut st, side_id, now_ms)
5070 else {
5071 continue;
5072 };
5073 let include_side_topology = include_topology
5074 && self.route_allowed_locked(
5075 &st,
5076 None,
5077 Some(DataType::DiscoveryTopology),
5078 side_id,
5079 );
5080 let capabilities = opts.link_capabilities();
5081 if level == DiscoveryAdvertiseLevel::MinimalPing {
5082 per_side.push((
5083 side_id,
5084 level,
5085 Vec::new(),
5086 Vec::new(),
5087 Vec::new(),
5088 Vec::new(),
5089 capabilities,
5090 local_is_master,
5091 ));
5092 continue;
5093 }
5094 per_side.push((
5095 side_id,
5096 level,
5097 self.advertised_discovery_endpoints_for_link_locked(
5098 &st,
5099 now_ms,
5100 link_local_enabled,
5101 Some(side_id),
5102 ),
5103 self.advertised_network_variables_for_link_locked(&st, now_ms, Some(side_id)),
5104 self.advertised_discovery_timesync_sources_for_link_locked(
5105 &st,
5106 now_ms,
5107 Some(side_id),
5108 ),
5109 if include_side_topology {
5110 self.advertised_discovery_topology_for_link_locked(
5111 &st,
5112 now_ms,
5113 link_local_enabled,
5114 Some(side_id),
5115 )
5116 } else {
5117 Vec::new()
5118 },
5119 capabilities,
5120 local_is_master,
5121 ));
5122 }
5123 per_side
5124 };
5125 for (
5126 side_id,
5127 level,
5128 endpoints,
5129 network_variables,
5130 timesync_sources,
5131 topology,
5132 capabilities,
5133 local_is_master,
5134 ) in per_side
5135 {
5136 let sender = self.sender_arc();
5137 #[cfg(feature = "std")]
5142 if include_schema && level == DiscoveryAdvertiseLevel::Full {
5143 let pkt = discovery::build_discovery_schema(sender.as_ref(), now_ms)?;
5144 self.emit_internal_tx(
5145 RouterTxItem::ToSide {
5146 src: None,
5147 dst: side_id,
5148 data: RouterItem::Packet(pkt),
5149 },
5150 true,
5151 called_from_queue,
5152 )?;
5153 }
5154 #[cfg(not(feature = "std"))]
5155 let _ = include_schema;
5156 if level == DiscoveryAdvertiseLevel::Full {
5157 let address = self.local_address_advertisement(
5158 endpoints.clone(),
5159 network_variables.clone(),
5160 timesync_sources.clone(),
5161 capabilities,
5162 if local_is_master {
5163 discovery::ADDRESS_STATE_APPROVED
5164 } else {
5165 discovery::ADDRESS_STATE_REQUEST
5166 },
5167 );
5168 let pkt = discovery::build_discovery_address(sender.as_ref(), now_ms, &address)?;
5169 self.emit_internal_tx(
5170 RouterTxItem::ToSide {
5171 src: None,
5172 dst: side_id,
5173 data: RouterItem::Packet(pkt),
5174 },
5175 true,
5176 called_from_queue,
5177 )?;
5178 }
5179 if level == DiscoveryAdvertiseLevel::MinimalPing {
5180 let pkt = discovery::build_discovery_announce(
5181 sender.as_ref(),
5182 now_ms,
5183 endpoints.as_slice(),
5184 )?;
5185 self.emit_internal_tx(
5186 RouterTxItem::ToSide {
5187 src: None,
5188 dst: side_id,
5189 data: RouterItem::Packet(pkt),
5190 },
5191 true,
5192 called_from_queue,
5193 )?;
5194 }
5195 if include_topology && level == DiscoveryAdvertiseLevel::Full && !topology.is_empty() {
5196 let pkt = discovery::build_discovery_topology(sender.as_ref(), now_ms, &topology)?;
5197 self.emit_internal_tx(
5198 RouterTxItem::ToSide {
5199 src: None,
5200 dst: side_id,
5201 data: RouterItem::Packet(pkt),
5202 },
5203 true,
5204 called_from_queue,
5205 )?;
5206 }
5207 }
5208 Ok(())
5209 }
5210
5211 #[cfg(feature = "discovery")]
5212 fn queue_discovery_announce(&self, include_schema: bool) -> TelemetryResult<()> {
5213 let now_ms = self.clock.now_ms();
5214 {
5215 let mut st = self.state.lock();
5216 if Self::prune_discovery_routes_locked(&mut st, now_ms) {
5217 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
5218 Self::note_discovery_topology_change_locked(&mut st, now_ms);
5219 }
5220 st.fit_discovery_budget();
5221 if st.sides.iter().all(|side| side.is_none()) {
5222 return Ok(());
5223 }
5224 st.discovery_cadence.on_announce_sent(now_ms);
5225 }
5226 self.emit_discovery_snapshot(true, include_schema, true)
5227 }
5228
5229 #[cfg(feature = "discovery")]
5230 fn poll_discovery_announce(&self) -> TelemetryResult<bool> {
5231 let now_ms = self.clock.now_ms();
5232 let due = {
5233 let mut st = self.state.lock();
5234 let removed = Self::prune_discovery_routes_locked(&mut st, now_ms);
5235 if removed {
5236 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
5237 Self::note_discovery_topology_change_locked(&mut st, now_ms);
5238 }
5239 st.fit_discovery_budget();
5240 let has_any = st.sides.iter().enumerate().any(|(side_id, side)| {
5241 let Some(side) = side.as_ref() else {
5242 return false;
5243 };
5244 if !self.route_allowed_locked(&st, None, Some(DataType::DiscoveryAnnounce), side_id)
5245 {
5246 return false;
5247 }
5248 let _ = side;
5249 true
5250 });
5251 if st.sides.is_empty() || !has_any {
5252 return Ok(false);
5253 }
5254 st.discovery_cadence.due(now_ms)
5255 };
5256 if !due {
5257 return Ok(false);
5258 }
5259 self.queue_discovery_announce(false)?;
5264 Ok(true)
5265 }
5266
5267 #[cfg(feature = "discovery")]
5268 fn learn_discovery_packet(
5269 &self,
5270 pkt: &Packet,
5271 src: Option<RouterSideId>,
5272 called_from_queue: bool,
5273 ) -> TelemetryResult<bool> {
5274 if !discovery::is_discovery_type(pkt.data_type()) {
5275 return Ok(false);
5276 }
5277 let Some(side) = src else {
5278 return Ok(true);
5279 };
5280 if pkt.data_type() == DataType::DiscoveryAddress {
5281 let mut ad = discovery::decode_discovery_address(pkt)?;
5282 let mut changed = self.ingest_address_advertisement(ad.clone())?;
5283 let sender_id = if ad.hostname.is_empty() {
5289 pkt.sender()
5290 } else {
5291 ad.hostname.as_str()
5292 };
5293 let now_ms = self.clock.now_ms();
5294 let mut st = self.state.lock();
5295 let side_link_local_enabled = st
5296 .sides
5297 .get(side)
5298 .and_then(|entry| entry.as_ref())
5299 .map(|side_ref| side_ref.opts.link_local_enabled)
5300 .unwrap_or(false);
5301 if !side_link_local_enabled {
5302 ad.reachable_endpoints.retain(|ep| !ep.is_link_local_only());
5303 }
5304 let mut route = st.discovery_routes.get(&side).cloned().unwrap_or_default();
5305 if pkt.sender() != sender_id {
5306 route.announcers.remove(pkt.sender());
5307 }
5308 let mut sender_state = route.announcers.get(sender_id).cloned().unwrap_or_default();
5309 let board = Self::sender_topology_board_mut(&mut sender_state, sender_id);
5310 if board.reachable_endpoints != ad.reachable_endpoints {
5311 board.reachable_endpoints = ad.reachable_endpoints;
5312 changed = true;
5313 }
5314 if board.reachable_timesync_sources != ad.reachable_timesync_sources {
5315 board.reachable_timesync_sources = ad.reachable_timesync_sources;
5316 changed = true;
5317 }
5318 if sender_state.reachable_network_variables != ad.reachable_network_variables {
5319 sender_state.reachable_network_variables = ad.reachable_network_variables;
5320 changed = true;
5321 }
5322 Self::refresh_sender_topology_state(&mut sender_state);
5323 sender_state.last_seen_ms = now_ms;
5324 route.announcers.insert(sender_id.to_string(), sender_state);
5325 Self::recompute_discovery_side_state(&mut route);
5326 st.discovery_routes.insert(side, route);
5327 st.fit_discovery_budget();
5328 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
5329 if changed {
5330 Self::note_discovery_topology_change_locked(&mut st, self.clock.now_ms());
5331 }
5332 return Ok(true);
5333 }
5334 let mut decoded_topology = if pkt.data_type() == DataType::DiscoveryTopology {
5335 Some(discovery::decode_discovery_topology(pkt)?)
5336 } else {
5337 None
5338 };
5339 let packet_sender = {
5340 let st = self.state.lock();
5341 let canonical = Self::canonical_sender_locked(&st, pkt.sender());
5342 if canonical != pkt.sender() {
5343 canonical
5344 } else if let Some(address) = pkt
5345 .sender()
5346 .strip_prefix("@addr:")
5347 .and_then(|value| value.parse::<u32>().ok())
5348 {
5349 decoded_topology
5355 .as_ref()
5356 .and_then(|boards| {
5357 boards
5358 .iter()
5359 .find(|board| sender_address_u32(&board.sender_id) == address)
5360 })
5361 .map(|board| board.sender_id.clone())
5362 .unwrap_or(canonical)
5363 } else {
5364 canonical
5365 }
5366 };
5367 let local_sender = self.sender_arc();
5368 if packet_sender == local_sender.as_ref() {
5369 return Ok(true);
5370 }
5371 if pkt.data_type() == DataType::DiscoveryTopologyRequest {
5372 let now_ms = self.clock.now_ms();
5373 let should_answer = {
5374 let mut st = self.state.lock();
5375 if Self::prune_discovery_routes_locked(&mut st, now_ms) {
5376 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
5377 Self::note_discovery_topology_change_locked(&mut st, now_ms);
5378 }
5379 self.should_answer_discovery_request_locked(&st, &packet_sender, now_ms)
5380 };
5381 if should_answer {
5382 self.emit_discovery_snapshot(called_from_queue, false, true)?;
5383 }
5384 return Ok(true);
5385 }
5386 if pkt.data_type() == DataType::DiscoverySchemaRequest {
5387 let now_ms = self.clock.now_ms();
5388 let should_answer = {
5389 let mut st = self.state.lock();
5390 if Self::prune_discovery_routes_locked(&mut st, now_ms) {
5391 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
5392 Self::note_discovery_topology_change_locked(&mut st, now_ms);
5393 }
5394 self.should_answer_discovery_request_locked(&st, &packet_sender, now_ms)
5395 };
5396 if should_answer {
5397 self.emit_discovery_snapshot(called_from_queue, true, true)?;
5398 }
5399 return Ok(true);
5400 }
5401 if pkt.data_type() == DataType::ManagedVariableRequest {
5402 let ty = discovery::decode_managed_variable_request(pkt)?;
5403 if !self.can_write_managed_variable(ty) {
5404 return Ok(false);
5409 }
5410 if let Some(value) = self.managed_variable_latest(ty) {
5411 self.emit_internal_tx(
5412 RouterTxItem::ToSide {
5413 src: None,
5414 dst: side,
5415 data: RouterItem::Packet(value),
5416 },
5417 true,
5418 called_from_queue,
5419 )?;
5420 return Ok(true);
5421 }
5422 return Ok(false);
5425 }
5426 if pkt.data_type() == DataType::DiscoverySchema {
5427 #[cfg(not(feature = "std"))]
5433 return Ok(true);
5434
5435 #[cfg(feature = "std")]
5436 {
5437 let snapshot = discovery::decode_discovery_schema(pkt)?;
5438 let incoming_cost = crate::config::owned_schema_byte_cost(&snapshot);
5439 let mut st = self.state.lock();
5440 st.make_shared_queue_room(incoming_cost, RouterQueueKind::Discovery)?;
5441 let budget = st.memory.max_queue_budget;
5442 drop(st);
5443 let report =
5444 crate::config::merge_owned_schema_snapshot_with_budget(snapshot, budget)?;
5445 if report.changed() {
5446 let mut st = self.state.lock();
5447 st.fit_discovery_budget();
5448 Self::note_discovery_topology_change_locked(&mut st, self.clock.now_ms());
5449 }
5450 return Ok(true);
5451 }
5452 }
5453 if pkt.data_type() == DataType::DiscoveryLinkCapabilities {
5454 let _ = discovery::decode_discovery_link_capabilities(pkt)?;
5455 return Ok(true);
5456 }
5457 let mut st = self.state.lock();
5458 let now_ms = self.clock.now_ms();
5459 if pkt.data_type() == DataType::DiscoveryLeave {
5460 let leaving = packet_sender.as_str();
5461 let before = st.discovery_routes.clone();
5462 for route in st.discovery_routes.values_mut() {
5463 route.announcers.remove(leaving);
5464 for sender_state in route.announcers.values_mut() {
5465 sender_state
5466 .topology_boards
5467 .retain(|board| board.sender_id != leaving);
5468 for board in sender_state.topology_boards.iter_mut() {
5469 board.connections.retain(|peer| peer != leaving);
5470 }
5471 Self::refresh_sender_topology_state(sender_state);
5472 }
5473 Self::recompute_discovery_side_state(route);
5474 }
5475 st.discovery_routes
5476 .retain(|_, route| !route.announcers.is_empty());
5477 if st.discovery_routes != before {
5478 Self::note_discovery_topology_change_locked(&mut st, now_ms);
5479 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
5480 }
5481 return Ok(true);
5482 }
5483 let mut route = st.discovery_routes.get(&side).cloned().unwrap_or_default();
5484 let side_link_local_enabled = st
5485 .sides
5486 .get(side)
5487 .and_then(|entry| entry.as_ref())
5488 .map(|side_ref| side_ref.opts.link_local_enabled)
5489 .unwrap_or(false);
5490 let mut sender_state = route
5491 .announcers
5492 .get(&packet_sender)
5493 .cloned()
5494 .unwrap_or_default();
5495 let changed = match pkt.data_type() {
5496 DataType::DiscoveryAnnounce => {
5497 let mut reachable = discovery::decode_discovery_announce(pkt)?;
5498 if !side_link_local_enabled {
5499 reachable.retain(|ep| !ep.is_link_local_only());
5500 }
5501 let board = Self::sender_topology_board_mut(&mut sender_state, &packet_sender);
5502 let changed = board.reachable_endpoints != reachable;
5503 board.reachable_endpoints = reachable;
5504 Self::refresh_sender_topology_state(&mut sender_state);
5505 changed
5506 }
5507 DataType::DiscoveryTimeSyncSources => {
5508 let sources = discovery::decode_discovery_timesync_sources(pkt)?;
5509 let board = Self::sender_topology_board_mut(&mut sender_state, &packet_sender);
5510 let changed = board.reachable_timesync_sources != sources;
5511 board.reachable_timesync_sources = sources;
5512 Self::refresh_sender_topology_state(&mut sender_state);
5513 changed
5514 }
5515 DataType::DiscoveryTopology => {
5516 let mut boards = decoded_topology
5517 .take()
5518 .expect("topology packet was decoded before route selection");
5519 for board in boards.iter_mut() {
5520 board.sender_id = Self::canonical_sender_locked(&st, &board.sender_id);
5521 for peer in board.connections.iter_mut() {
5522 *peer = Self::canonical_sender_locked(&st, peer);
5523 }
5524 }
5525 if !side_link_local_enabled {
5526 for board in boards.iter_mut() {
5527 board
5528 .reachable_endpoints
5529 .retain(|ep| !ep.is_link_local_only());
5530 }
5531 }
5532 let changed = sender_state.topology_boards != boards;
5533 sender_state.topology_boards = boards;
5534 Self::refresh_sender_topology_state(&mut sender_state);
5535 changed
5536 }
5537 DataType::DiscoverySchema => false,
5538 _ => false,
5539 };
5540 sender_state.last_seen_ms = now_ms;
5541 route.announcers.insert(packet_sender, sender_state);
5542 Self::recompute_discovery_side_state(&mut route);
5543 st.discovery_routes.insert(side, route);
5544 st.fit_discovery_budget();
5545 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
5546 if changed {
5547 Self::note_discovery_topology_change_locked(&mut st, now_ms);
5548 }
5549 Ok(true)
5550 }
5551
5552 #[cfg(not(feature = "discovery"))]
5553 fn queue_discovery_announce(&self) -> TelemetryResult<()> {
5554 Ok(())
5555 }
5556
5557 #[cfg(not(feature = "discovery"))]
5558 fn poll_discovery_announce(&self) -> TelemetryResult<bool> {
5559 Ok(false)
5560 }
5561
5562 #[cfg(not(feature = "discovery"))]
5563 fn learn_discovery_packet(
5564 &self,
5565 _pkt: &Packet,
5566 _src: Option<RouterSideId>,
5567 _called_from_queue: bool,
5568 ) -> TelemetryResult<bool> {
5569 Ok(false)
5570 }
5571
5572 #[inline]
5573 fn reliable_key(side: RouterSideId, ty: DataType) -> (RouterSideId, u32) {
5574 (side, ty.as_u32())
5575 }
5576
5577 fn reliable_tx_state_mut<'a>(
5578 &'a self,
5579 st: &'a mut RouterInner,
5580 side: RouterSideId,
5581 ty: DataType,
5582 ) -> &'a mut ReliableTxState {
5583 let key = Self::reliable_key(side, ty);
5584 st.reliable_tx
5585 .entry(key)
5586 .or_insert_with(|| ReliableTxState {
5587 next_seq: 1,
5588 sent_order: VecDeque::new(),
5589 sent: BTreeMap::new(),
5590 })
5591 }
5592
5593 fn reliable_rx_state_mut<'a>(
5594 &'a self,
5595 st: &'a mut RouterInner,
5596 side: RouterSideId,
5597 ty: DataType,
5598 ) -> &'a mut ReliableRxState {
5599 let key = Self::reliable_key(side, ty);
5600 st.reliable_rx
5601 .entry(key)
5602 .or_insert_with(|| ReliableRxState {
5603 expected_seq: 1,
5604 buffered: BTreeMap::new(),
5605 })
5606 }
5607
5608 fn reliable_control_packet(
5609 &self,
5610 control_ty: DataType,
5611 ty: DataType,
5612 seq: u32,
5613 ) -> TelemetryResult<Packet> {
5614 let sender = self.sender_arc();
5615 Packet::new(
5616 control_ty,
5617 message_meta(control_ty).endpoints_ref(),
5618 sender.as_ref(),
5619 self.packet_timestamp_ms(),
5620 encode_slice_le(&[ty.as_u32(), seq]),
5621 )
5622 }
5623
5624 fn queue_reliable_ack(
5625 &self,
5626 side: RouterSideId,
5627 ty: DataType,
5628 seq: u32,
5629 called_from_queue: bool,
5630 ) -> TelemetryResult<()> {
5631 let pkt = self.reliable_control_packet(DataType::ReliableAck, ty, seq)?;
5632 self.emit_internal_tx_with_priority(
5633 RouterTxItem::ToSide {
5634 src: None,
5635 dst: side,
5636 data: RouterItem::Packet(pkt),
5637 },
5638 true,
5639 message_priority(DataType::ReliableAck),
5640 called_from_queue,
5641 )
5642 }
5643
5644 fn queue_reliable_packet_request(
5645 &self,
5646 side: RouterSideId,
5647 ty: DataType,
5648 seq: u32,
5649 called_from_queue: bool,
5650 ) -> TelemetryResult<()> {
5651 let pkt = self.reliable_control_packet(DataType::ReliablePacketRequest, ty, seq)?;
5652 self.emit_internal_tx_with_priority(
5653 RouterTxItem::ToSide {
5654 src: None,
5655 dst: side,
5656 data: RouterItem::Packet(pkt),
5657 },
5658 true,
5659 message_priority(DataType::ReliablePacketRequest),
5660 called_from_queue,
5661 )
5662 }
5663
5664 fn queue_reliable_partial_ack(
5665 &self,
5666 side: RouterSideId,
5667 ty: DataType,
5668 seq: u32,
5669 called_from_queue: bool,
5670 ) -> TelemetryResult<()> {
5671 let pkt = self.reliable_control_packet(DataType::ReliablePartialAck, ty, seq)?;
5672 self.emit_internal_tx_with_priority(
5673 RouterTxItem::ToSide {
5674 src: None,
5675 dst: side,
5676 data: RouterItem::Packet(pkt),
5677 },
5678 true,
5679 message_priority(DataType::ReliablePartialAck),
5680 called_from_queue,
5681 )
5682 }
5683
5684 fn handle_reliable_ack(&self, side: RouterSideId, ty: DataType, ack: u32) {
5685 let mut st = self.state.lock();
5686 let tx_state = self.reliable_tx_state_mut(&mut st, side, ty);
5687 if matches!(reliable_mode(ty), crate::ReliableMode::Unordered) {
5688 tx_state.sent.remove(&ack);
5689 tx_state.sent_order.retain(|seq| *seq != ack);
5690 return;
5691 }
5692
5693 while let Some(seq) = tx_state.sent_order.front().copied() {
5694 if seq > ack {
5695 break;
5696 }
5697 tx_state.sent_order.pop_front();
5698 tx_state.sent.remove(&seq);
5699 }
5700 }
5701
5702 fn handle_reliable_partial_ack(&self, side: RouterSideId, ty: DataType, seq: u32) {
5703 let mut st = self.state.lock();
5704 let tx_state = self.reliable_tx_state_mut(&mut st, side, ty);
5705 if let Some(sent) = tx_state.sent.get_mut(&seq) {
5706 sent.partial_acked = true;
5707 }
5708 }
5709
5710 fn queue_reliable_retransmit(
5711 &self,
5712 side: RouterSideId,
5713 ty: DataType,
5714 seq: u32,
5715 called_from_queue: bool,
5716 ) -> TelemetryResult<()> {
5717 let mut queued = None;
5718 {
5719 let mut st = self.state.lock();
5720 let tx_state = self.reliable_tx_state_mut(&mut st, side, ty);
5721 if let Some(sent) = tx_state.sent.get_mut(&seq)
5722 && !sent.queued
5723 {
5724 sent.queued = true;
5725 sent.partial_acked = false;
5726 queued = Some(sent.bytes.clone());
5727 }
5728 }
5729
5730 if let Some(bytes) = queued {
5731 if called_from_queue {
5732 self.tx_queue_item_with_priority(
5733 RouterTxItem::ReliableReplay { dst: side, bytes },
5734 true,
5735 Self::router_item_priority_bumped(ty),
5736 )?;
5737 } else {
5738 self.tx_item_impl(
5739 RouterTxItem::ReliableReplay { dst: side, bytes },
5740 true,
5741 false,
5742 )?;
5743 }
5744 }
5745
5746 Ok(())
5747 }
5748
5749 fn send_reliable_raw_to_side(
5750 &self,
5751 side: RouterSideId,
5752 bytes: Arc<[u8]>,
5753 relayed: bool,
5754 ) -> TelemetryResult<()> {
5755 let handler = {
5756 let st = self.state.lock();
5757 let side_ref = Self::side_ref(&st, side)?;
5758 if !side_ref.opts.egress_enabled {
5759 return Ok(());
5760 }
5761 (side_ref.tx_handler.clone(), side_ref.opts)
5762 };
5763
5764 let (handler, opts) = handler;
5765
5766 let Some(_side_tx_guard) = self.try_enter_side_tx() else {
5767 return Err(TelemetryError::Io("side tx busy"));
5768 };
5769 let started_ms = self.clock.now_ms();
5770 let ty = wire_format::peek_envelope(bytes.as_ref())
5771 .map(|env| env.ty)
5772 .unwrap_or(DataType::ReliableAck);
5773 let result = match handler {
5774 RouterTxHandlerFn::Packed(f) => {
5775 let frames = self.encode_side_transport_frames(side, opts, bytes.clone())?;
5776 let mut attempts_total = 0usize;
5777 let mut sent_bytes = 0usize;
5778 for frame in frames {
5779 match self
5780 .retry_with_attempts(runtime_max_handler_retries(), || f(frame.as_ref()))
5781 {
5782 Ok((_, attempts)) => {
5783 attempts_total = attempts_total.saturating_add(attempts);
5784 sent_bytes = sent_bytes.saturating_add(frame.len());
5785 }
5786 Err((err, attempts)) => {
5787 self.note_side_tx_failure(
5788 side,
5789 ty,
5790 attempts_total.saturating_add(attempts),
5791 );
5792 return Err(err);
5793 }
5794 }
5795 }
5796 self.record_side_tx_sample(side, sent_bytes, started_ms, self.clock.now_ms());
5797 self.note_side_tx_success(side, ty, sent_bytes, relayed, attempts_total);
5798 return Ok(());
5799 }
5800 RouterTxHandlerFn::Packet(f) => {
5801 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
5802 self.retry_with_attempts(runtime_max_handler_retries(), || f(&pkt))
5803 }
5804 };
5805 match result {
5806 Ok((_, attempts)) => {
5807 self.record_side_tx_sample(side, bytes.len(), started_ms, self.clock.now_ms());
5808 self.note_side_tx_success(side, ty, bytes.len(), relayed, attempts);
5809 Ok(())
5810 }
5811 Err((err, attempts)) => {
5812 self.note_side_tx_failure(side, ty, attempts);
5813 Err(err)
5814 }
5815 }
5816 }
5817
5818 fn send_reliable_to_side(
5819 &self,
5820 side: RouterSideId,
5821 data: RouterItem,
5822 relayed: bool,
5823 ) -> TelemetryResult<()> {
5824 let (handler, opts, hop_reliable_enabled) = {
5825 let st = self.state.lock();
5826 let side_ref = Self::side_ref(&st, side)?;
5827 let opts = side_ref.opts;
5828 let hop_reliable_enabled = opts.reliable_enabled
5829 && self.cfg.reliable_enabled()
5830 && !self.side_has_multiple_announcers_locked(&st, side, self.clock.now_ms());
5831 (side_ref.tx_handler.clone(), opts, hop_reliable_enabled)
5832 };
5833
5834 let RouterTxHandlerFn::Packed(f) = &handler else {
5835 return self.call_side_tx_handler(side, &handler, &data, relayed);
5836 };
5837
5838 if !hop_reliable_enabled {
5839 let mut adjusted_opts = opts;
5840 adjusted_opts.reliable_enabled = false;
5841 let preserve_end_to_end_ack = opts.reliable_enabled && self.cfg.reliable_enabled();
5842 if let Some(adjusted) =
5843 self.adjust_reliable_for_side(adjusted_opts, data, preserve_end_to_end_ack)?
5844 {
5845 return self.call_side_tx_handler(side, &handler, &adjusted, relayed);
5846 }
5847 return Ok(());
5848 }
5849
5850 let ty = match &data {
5851 RouterItem::Packet(pkt) => pkt.data_type(),
5852 RouterItem::Packed(bytes) => wire_format::peek_frame_info(bytes.as_ref())?.envelope.ty,
5853 };
5854
5855 if !is_reliable_type(ty) {
5856 if let Some(adjusted) = self.adjust_reliable_for_side(opts, data, true)? {
5857 self.call_side_tx_handler(side, &handler, &adjusted, relayed)?;
5858 }
5859 return Ok(());
5860 }
5861
5862 let (seq, flags) = {
5863 let mut st = self.state.lock();
5864 let tx_state = self.reliable_tx_state_mut(&mut st, side, ty);
5865 if tx_state.sent.len() >= runtime_reliable_max_pending() {
5866 return Err(TelemetryError::PacketTooLarge(
5867 "router reliable history full",
5868 ));
5869 }
5870 let seq = tx_state.next_seq;
5871 let next = tx_state.next_seq.wrapping_add(1);
5872 tx_state.next_seq = if next == 0 { 1 } else { next };
5873 let flags = match reliable_mode(ty) {
5874 crate::ReliableMode::Unordered => wire_format::RELIABLE_FLAG_UNORDERED,
5875 _ => 0,
5876 };
5877 (seq, flags)
5878 };
5879
5880 let bytes: Arc<[u8]> = match data {
5881 RouterItem::Packet(pkt) => self.pack_packet_for_router(
5882 &pkt,
5883 Some(wire_format::ReliableHeader { flags, seq, ack: 0 }),
5884 )?,
5885 RouterItem::Packed(bytes) => {
5886 #[cfg(feature = "cryptography")]
5887 if self.e2e_seal_config_for_type(ty).is_some() {
5888 self.prepare_packed_for_remote(
5889 bytes,
5890 Some(Some(wire_format::ReliableHeader { flags, seq, ack: 0 })),
5891 )?
5892 } else {
5893 let Some(rewritten) =
5894 wire_format::rewrite_reliable_header_owned(bytes.as_ref(), flags, seq, 0)?
5895 else {
5896 let Some(_side_tx_guard) = self.try_enter_side_tx() else {
5897 return Err(TelemetryError::Io("side tx busy"));
5898 };
5899 let started_ms = self.clock.now_ms();
5900 let frames =
5901 self.encode_side_transport_frames(side, opts, bytes.clone())?;
5902 let mut attempts_total = 0usize;
5903 let mut sent_bytes = 0usize;
5904 for frame in frames {
5905 match self.retry_with_attempts(runtime_max_handler_retries(), || {
5906 f(frame.as_ref())
5907 }) {
5908 Ok((_, attempts)) => {
5909 attempts_total = attempts_total.saturating_add(attempts);
5910 sent_bytes = sent_bytes.saturating_add(frame.len());
5911 }
5912 Err((err, attempts)) => {
5913 self.note_side_tx_failure(
5914 side,
5915 ty,
5916 attempts_total.saturating_add(attempts),
5917 );
5918 return Err(err);
5919 }
5920 }
5921 }
5922 self.record_side_tx_sample(
5923 side,
5924 sent_bytes,
5925 started_ms,
5926 self.clock.now_ms(),
5927 );
5928 self.note_side_tx_success(side, ty, sent_bytes, relayed, attempts_total);
5929 return Ok(());
5930 };
5931 rewritten
5932 }
5933 #[cfg(not(feature = "cryptography"))]
5934 {
5935 let Some(rewritten) =
5936 wire_format::rewrite_reliable_header_owned(bytes.as_ref(), flags, seq, 0)?
5937 else {
5938 let Some(_side_tx_guard) = self.try_enter_side_tx() else {
5939 return Err(TelemetryError::Io("side tx busy"));
5940 };
5941 let started_ms = self.clock.now_ms();
5942 let frames =
5943 self.encode_side_transport_frames(side, opts, bytes.clone())?;
5944 let mut attempts_total = 0usize;
5945 let mut sent_bytes = 0usize;
5946 for frame in frames {
5947 match self.retry_with_attempts(runtime_max_handler_retries(), || {
5948 f(frame.as_ref())
5949 }) {
5950 Ok((_, attempts)) => {
5951 attempts_total = attempts_total.saturating_add(attempts);
5952 sent_bytes = sent_bytes.saturating_add(frame.len());
5953 }
5954 Err((err, attempts)) => {
5955 self.note_side_tx_failure(
5956 side,
5957 ty,
5958 attempts_total.saturating_add(attempts),
5959 );
5960 return Err(err);
5961 }
5962 }
5963 }
5964 self.record_side_tx_sample(
5965 side,
5966 sent_bytes,
5967 started_ms,
5968 self.clock.now_ms(),
5969 );
5970 self.note_side_tx_success(side, ty, sent_bytes, relayed, attempts_total);
5971 return Ok(());
5972 };
5973 rewritten
5974 }
5975 }
5976 };
5977
5978 let Some(_side_tx_guard) = self.try_enter_side_tx() else {
5979 return Err(TelemetryError::Io("side tx busy"));
5980 };
5981 let started_ms = self.clock.now_ms();
5982 let frames = self.encode_side_transport_frames(side, opts, bytes.clone())?;
5983 let mut attempts_total = 0usize;
5984 let mut sent_bytes = 0usize;
5985 for frame in frames {
5986 match self.retry_with_attempts(runtime_max_handler_retries(), || f(frame.as_ref())) {
5987 Ok((_, attempts)) => {
5988 attempts_total = attempts_total.saturating_add(attempts);
5989 sent_bytes = sent_bytes.saturating_add(frame.len());
5990 }
5991 Err((err, attempts)) => {
5992 self.note_side_tx_failure(side, ty, attempts_total.saturating_add(attempts));
5993 return Err(err);
5994 }
5995 }
5996 }
5997 self.record_side_tx_sample(side, sent_bytes, started_ms, self.clock.now_ms());
5998 self.note_side_tx_success(side, ty, sent_bytes, relayed, attempts_total);
5999
6000 {
6001 let mut st = self.state.lock();
6002 let tx_state = self.reliable_tx_state_mut(&mut st, side, ty);
6003 tx_state.sent_order.push_back(seq);
6004 tx_state.sent.insert(
6005 seq,
6006 ReliableSent {
6007 bytes: bytes.clone(),
6008 last_send_ms: self.clock.now_ms(),
6009 retries: 0,
6010 queued: false,
6011 partial_acked: false,
6012 },
6013 );
6014 }
6015
6016 Ok(())
6017 }
6018
6019 #[inline]
6020 fn crc32_bytes(data: &[u8]) -> u32 {
6021 let mut hasher = Crc32Hasher::new();
6022 hasher.update(data);
6023 hasher.finalize()
6024 }
6025
6026 fn read_uleb128_local(buf: &[u8], off: &mut usize) -> TelemetryResult<u64> {
6027 let mut result = 0u64;
6028 let mut shift = 0u32;
6029 for _ in 0..10 {
6030 let byte = *buf.get(*off).ok_or(TelemetryError::Unpack("short read"))?;
6031 *off += 1;
6032 result |= u64::from(byte & 0x7F) << shift;
6033 if (byte & 0x80) == 0 {
6034 return Ok(result);
6035 }
6036 shift += 7;
6037 }
6038 Err(TelemetryError::Unpack("uleb128 too long"))
6039 }
6040
6041 fn write_uleb128_local(mut value: u64, out: &mut Vec<u8>) {
6042 loop {
6043 let mut byte = (value & 0x7F) as u8;
6044 value >>= 7;
6045 if value != 0 {
6046 byte |= 0x80;
6047 }
6048 out.push(byte);
6049 if value == 0 {
6050 break;
6051 }
6052 }
6053 }
6054
6055 fn uleb128_len_local(mut value: u64) -> usize {
6056 let mut len = 1;
6057 while value >= 0x80 {
6058 value >>= 7;
6059 len += 1;
6060 }
6061 len
6062 }
6063
6064 fn wrap_side_transport_frame(kind: u8, body: &[u8]) -> Arc<[u8]> {
6065 let mut out = Vec::with_capacity(
6066 SIDE_TRANSPORT_MAGIC.len() + 1 + body.len() + wire_format::CRC32_BYTES,
6067 );
6068 out.extend_from_slice(SIDE_TRANSPORT_MAGIC);
6069 out.push(kind);
6070 out.extend_from_slice(body);
6071 let crc = Self::crc32_bytes(&out);
6072 out.extend_from_slice(&crc.to_le_bytes());
6073 Arc::from(out)
6074 }
6075
6076 fn parse_side_transport_wrapper(bytes: &[u8]) -> TelemetryResult<Option<(u8, &[u8])>> {
6077 if bytes.len() < SIDE_TRANSPORT_MAGIC.len() + 1 + wire_format::CRC32_BYTES {
6078 return Ok(None);
6079 }
6080 if &bytes[..SIDE_TRANSPORT_MAGIC.len()] != SIDE_TRANSPORT_MAGIC {
6081 return Ok(None);
6082 }
6083 let data_len = bytes.len() - wire_format::CRC32_BYTES;
6084 let expected = u32::from_le_bytes([
6085 bytes[data_len],
6086 bytes[data_len + 1],
6087 bytes[data_len + 2],
6088 bytes[data_len + 3],
6089 ]);
6090 let data = &bytes[..data_len];
6091 if Self::crc32_bytes(data) != expected {
6092 return Err(TelemetryError::Unpack("side transport crc32 mismatch"));
6093 }
6094 let kind = data[SIDE_TRANSPORT_MAGIC.len()];
6095 Ok(Some((kind, &data[SIDE_TRANSPORT_MAGIC.len() + 1..])))
6096 }
6097
6098 fn extract_side_header_template(bytes: &[u8]) -> TelemetryResult<SideTemplateExtract<'_>> {
6099 if bytes.len() < wire_format::CRC32_BYTES + 4 {
6100 return Err(TelemetryError::Unpack("short buffer"));
6101 }
6102 let data_len = bytes.len() - wire_format::CRC32_BYTES;
6103 let data = &bytes[..data_len];
6104 let mut off = 0usize;
6105 let flags = *data
6106 .get(off)
6107 .ok_or(TelemetryError::Unpack("short prelude"))?;
6108 off += 1;
6109 off += 1; let ty_end_start = off;
6111 let ty_u64 = Self::read_uleb128_local(data, &mut off)?;
6112 let ty_u32 = u32::try_from(ty_u64).map_err(|_| TelemetryError::Unpack("bad data type"))?;
6113 if ty_u32 > crate::MAX_VALUE_DATA_TYPE {
6114 return Err(TelemetryError::Unpack("bad data type"));
6115 }
6116 let ty = DataType(ty_u32);
6117 let data_size_off = off;
6118 let data_size = Self::read_uleb128_local(data, &mut off)?;
6119 let _timestamp_off = off;
6120 let timestamp = Self::read_uleb128_local(data, &mut off)?;
6121 let nonce = if (flags & SIDE_TRANSPORT_FLAG_PACKET_NONCE) != 0 {
6122 u16::try_from(Self::read_uleb128_local(data, &mut off)?)
6123 .map_err(|_| TelemetryError::Unpack("packet nonce too large"))?
6124 } else {
6125 0
6126 };
6127 let between_start = off;
6128 let _source_address = u32::try_from(Self::read_uleb128_local(data, &mut off)?)
6129 .map_err(|_| TelemetryError::Unpack("source address too large"))?;
6130 let endpoint_bitmap_bytes = if (flags & SIDE_TRANSPORT_FLAG_ENDPOINT_BITMAP_PRESENT) != 0 {
6131 SIDE_TRANSPORT_EP_BITMAP_BYTES
6132 } else {
6133 0
6134 };
6135 if data.len() < off + endpoint_bitmap_bytes {
6136 return Err(TelemetryError::Unpack("short buffer"));
6137 }
6138 off += endpoint_bitmap_bytes;
6139 if (flags & SIDE_TRANSPORT_FLAG_WIRE_CONTRACT) != 0 {
6140 let contract_len = usize::try_from(Self::read_uleb128_local(data, &mut off)?)
6141 .map_err(|_| TelemetryError::Unpack("wire contract length"))?;
6142 if data.len() < off + contract_len {
6143 return Err(TelemetryError::Unpack("short buffer"));
6144 }
6145 off += contract_len;
6146 }
6147 let reliable_span = wire_format::reliable_header_span(bytes)?;
6148 let (reliable_flags, reliable_seq_ack, reliable_compact, payload_off) =
6149 if let Some((rel_off, rel_len, hdr)) = reliable_span {
6150 if data.len() < rel_off + rel_len {
6151 return Err(TelemetryError::Unpack("short buffer"));
6152 }
6153 (
6154 Some(hdr.flags),
6155 Some((hdr.seq, hdr.ack)),
6156 (flags & SIDE_TRANSPORT_FLAG_COMPACT_RELIABLE_HEADER) != 0,
6157 rel_off + rel_len,
6158 )
6159 } else {
6160 (None, None, false, off)
6161 };
6162 if payload_off > data.len() {
6163 return Err(TelemetryError::Unpack("short buffer"));
6164 }
6165 let payload = &data[payload_off..];
6166 let prefix = Arc::<[u8]>::from(&data[1..data_size_off]);
6167 let between_end = reliable_span
6168 .map(|(rel_off, _, _)| rel_off)
6169 .unwrap_or(payload_off);
6170 let between = Arc::<[u8]>::from(&data[between_start..between_end]);
6171 let base_flags =
6172 flags & !(SIDE_TRANSPORT_FLAG_PAYLOAD_COMPRESSED | SIDE_TRANSPORT_FLAG_PACKET_NONCE);
6173 let mut hash = 0xD1B5_4A32_9C7E_01F3u64;
6174 hash = hash_bytes_u64(hash, &[base_flags]);
6175 hash = hash_bytes_u64(hash, &prefix);
6176 hash = hash_bytes_u64(hash, &between);
6177 if let Some(rel_flags) = reliable_flags {
6178 hash = hash_bytes_u64(hash, &[rel_flags]);
6179 }
6180 let template = SideHeaderTemplate {
6181 hash,
6182 base_flags,
6183 prefix,
6184 between,
6185 reliable_flags,
6186 reliable_compact,
6187 };
6188 let _ = ty_end_start;
6189 Ok((
6190 template,
6191 ty,
6192 flags,
6193 data_size,
6194 timestamp,
6195 nonce,
6196 reliable_seq_ack,
6197 payload,
6198 ))
6199 }
6200
6201 fn reconstruct_side_compact_frame(
6202 template: &SideHeaderTemplate,
6203 body: &[u8],
6204 timestamp_mode: SideCompactTimestampMode,
6205 timestamp_base: Option<u64>,
6206 ) -> TelemetryResult<(Arc<[u8]>, u64)> {
6207 if body.is_empty() {
6208 return Err(TelemetryError::Unpack("short side compact frame"));
6209 }
6210 let mut off = 0usize;
6211 let flags = body[off];
6212 off += 1;
6213 if (flags & !(SIDE_TRANSPORT_FLAG_PAYLOAD_COMPRESSED | SIDE_TRANSPORT_FLAG_PACKET_NONCE))
6214 != template.base_flags
6215 {
6216 return Err(TelemetryError::Unpack("side compact flags mismatch"));
6217 }
6218 let data_size = Self::read_uleb128_local(body, &mut off)?;
6219 let timestamp = match timestamp_mode {
6220 SideCompactTimestampMode::Absolute => Self::read_uleb128_local(body, &mut off)?,
6221 SideCompactTimestampMode::Delta => {
6222 let timestamp_field = Self::read_uleb128_local(body, &mut off)?;
6223 let base = timestamp_base.ok_or(TelemetryError::Unpack(
6224 "missing side compact timestamp context",
6225 ))?;
6226 base.checked_add(timestamp_field)
6227 .ok_or(TelemetryError::Unpack(
6228 "side compact timestamp delta overflow",
6229 ))?
6230 }
6231 SideCompactTimestampMode::Omitted => timestamp_base.ok_or(TelemetryError::Unpack(
6232 "missing side compact timestamp context",
6233 ))?,
6234 };
6235 let nonce = if (flags & SIDE_TRANSPORT_FLAG_PACKET_NONCE) != 0 {
6236 Some(Self::read_uleb128_local(body, &mut off)?)
6237 } else {
6238 None
6239 };
6240 let reliable_seq_ack = if template.reliable_flags.is_some() {
6241 let seq = u32::try_from(Self::read_uleb128_local(body, &mut off)?)
6242 .map_err(|_| TelemetryError::Unpack("side compact reliable seq too large"))?;
6243 let ack = u32::try_from(Self::read_uleb128_local(body, &mut off)?)
6244 .map_err(|_| TelemetryError::Unpack("side compact reliable ack too large"))?;
6245 Some((seq, ack))
6246 } else {
6247 None
6248 };
6249 let payload = &body[off..];
6250 let mut raw = Vec::with_capacity(
6251 1 + template.prefix.len() + template.between.len() + payload.len() + 32,
6252 );
6253 raw.push(flags);
6254 raw.extend_from_slice(&template.prefix);
6255 Self::write_uleb128_local(data_size, &mut raw);
6256 Self::write_uleb128_local(timestamp, &mut raw);
6257 if let Some(nonce) = nonce {
6258 Self::write_uleb128_local(nonce, &mut raw);
6259 }
6260 raw.extend_from_slice(&template.between);
6261 if let Some(rel_flags) = template.reliable_flags {
6262 let (seq, ack) =
6263 reliable_seq_ack.ok_or(TelemetryError::Unpack("missing side compact reliable"))?;
6264 wire_format::write_reliable_header_encoded(
6265 wire_format::ReliableHeader {
6266 flags: rel_flags,
6267 seq,
6268 ack,
6269 },
6270 template.reliable_compact,
6271 &mut raw,
6272 );
6273 }
6274 raw.extend_from_slice(payload);
6275 let crc = Self::crc32_bytes(&raw);
6276 raw.extend_from_slice(&crc.to_le_bytes());
6277 Ok((Arc::from(raw), timestamp))
6278 }
6279 fn split_side_transport_frame(
6280 &self,
6281 side: RouterSideId,
6282 frame: Arc<[u8]>,
6283 max_frame_bytes: usize,
6284 ) -> TelemetryResult<Vec<Arc<[u8]>>> {
6285 if max_frame_bytes <= SIDE_TRANSPORT_CHUNK_OVERHEAD {
6286 return Err(TelemetryError::BadArg);
6287 }
6288 let payload_budget = max_frame_bytes - SIDE_TRANSPORT_CHUNK_OVERHEAD;
6289 let mut st = self.state.lock();
6290 let side_state = st
6291 .side_transport
6292 .get_mut(&side)
6293 .ok_or(TelemetryError::BadArg)?;
6294 let transfer_id = side_state.next_chunk_id.wrapping_add(1).max(1);
6295 side_state.next_chunk_id = transfer_id;
6296 drop(st);
6297
6298 let total = frame.len().div_ceil(payload_budget);
6299 let total_u16 =
6300 u16::try_from(total).map_err(|_| TelemetryError::PacketTooLarge("too many chunks"))?;
6301 let mut frames = Vec::with_capacity(total);
6302 for (idx, chunk) in frame.chunks(payload_budget).enumerate() {
6303 let mut body = Vec::with_capacity(8 + chunk.len());
6304 body.extend_from_slice(&transfer_id.to_le_bytes());
6305 body.extend_from_slice(&(idx as u16).to_le_bytes());
6306 body.extend_from_slice(&total_u16.to_le_bytes());
6307 body.extend_from_slice(chunk);
6308 frames.push(Self::wrap_side_transport_frame(
6309 SIDE_TRANSPORT_KIND_CHUNK,
6310 &body,
6311 ));
6312 }
6313 Ok(frames)
6314 }
6315
6316 fn encode_side_transport_frames(
6317 &self,
6318 side: RouterSideId,
6319 opts: RouterSideOptions,
6320 raw: Arc<[u8]>,
6321 ) -> TelemetryResult<Vec<Arc<[u8]>>> {
6322 if !opts.header_template_enabled && opts.max_frame_bytes == 0 {
6323 return Ok(vec![raw]);
6324 }
6325
6326 let raw_len = raw.len();
6327 let mut compact_payload_len = None;
6328 let mut used_compact = false;
6329 let mut used_timestamp_delta = false;
6330 let mut omitted_timestamp = false;
6331 let wrapped = if opts.header_template_enabled {
6332 let (template, ty, flags, data_size, timestamp, nonce, reliable_seq_ack, payload) =
6333 Self::extract_side_header_template(raw.as_ref())?;
6334 let (template_id, use_compact, previous_timestamp) = {
6335 let mut st = self.state.lock();
6336 let side_state = st
6337 .side_transport
6338 .get_mut(&side)
6339 .ok_or(TelemetryError::BadArg)?;
6340 if let Some(id) = side_state.tx_template_ids.get(&template.hash).copied() {
6341 let previous = side_state.tx_last_timestamps.get(&id).copied();
6342 const FULL_REFRESH_AFTER_COMPACT_FRAMES: u8 = 8;
6345 let compact_uses = side_state.tx_compact_uses.entry(id).or_default();
6346 let use_compact = *compact_uses < FULL_REFRESH_AFTER_COMPACT_FRAMES;
6347 if use_compact {
6348 *compact_uses = compact_uses.saturating_add(1);
6349 } else {
6350 *compact_uses = 0;
6351 }
6352 (id, use_compact, previous)
6353 } else {
6354 let next = side_state.next_template_id.wrapping_add(1).max(1);
6355 side_state.next_template_id = next;
6356 let evicted = side_state.insert_tx_template(
6357 template.clone(),
6358 next,
6359 opts.max_side_transport_templates,
6360 );
6361 if evicted {
6362 st.side_runtime_stats
6363 .entry(side)
6364 .or_default()
6365 .note_side_transport_template_eviction();
6366 }
6367 if let Some(side_state) = st.side_transport.get_mut(&side) {
6368 side_state.tx_last_timestamps.insert(next, timestamp);
6369 }
6370 (next, false, None)
6371 }
6372 };
6373 if use_compact {
6374 used_compact = true;
6375 compact_payload_len = Some(payload.len());
6376 let timestamp_field = if let Some(previous) = previous_timestamp {
6377 let delta = timestamp.saturating_sub(previous);
6378 let omit_timestamp = opts.omit_unchanged_compact_timestamps
6379 || opts.compact_timestamp_omission_types.contains(ty);
6380 if omit_timestamp && timestamp == previous {
6381 omitted_timestamp = true;
6382 None
6383 } else if timestamp >= previous
6384 && Self::uleb128_len_local(delta) < Self::uleb128_len_local(timestamp)
6385 {
6386 used_timestamp_delta = true;
6387 Some(delta)
6388 } else {
6389 Some(timestamp)
6390 }
6391 } else {
6392 Some(timestamp)
6393 };
6394 let mut body = Vec::with_capacity(payload.len() + 32);
6395 body.push(flags);
6396 Self::write_uleb128_local(u64::from(template_id), &mut body);
6397 Self::write_uleb128_local(data_size, &mut body);
6398 if let Some(timestamp_field) = timestamp_field {
6399 Self::write_uleb128_local(timestamp_field, &mut body);
6400 }
6401 if (flags & SIDE_TRANSPORT_FLAG_PACKET_NONCE) != 0 {
6402 Self::write_uleb128_local(u64::from(nonce), &mut body);
6403 }
6404 if let Some((seq, ack)) = reliable_seq_ack {
6405 Self::write_uleb128_local(u64::from(seq), &mut body);
6406 Self::write_uleb128_local(u64::from(ack), &mut body);
6407 }
6408 body.extend_from_slice(payload);
6409 {
6410 let mut st = self.state.lock();
6411 if let Some(side_state) = st.side_transport.get_mut(&side) {
6412 side_state.tx_last_timestamps.insert(template_id, timestamp);
6413 }
6414 }
6415 let kind = if omitted_timestamp {
6416 SIDE_TRANSPORT_KIND_COMPACT_SAME_TIMESTAMP
6417 } else if used_timestamp_delta {
6418 SIDE_TRANSPORT_KIND_COMPACT_DELTA
6419 } else {
6420 SIDE_TRANSPORT_KIND_COMPACT
6421 };
6422 Self::wrap_side_transport_frame(kind, &body)
6423 } else {
6424 let mut body = Vec::with_capacity(raw.len() + 4);
6425 Self::write_uleb128_local(u64::from(template_id), &mut body);
6426 body.extend_from_slice(raw.as_ref());
6427 Self::wrap_side_transport_frame(SIDE_TRANSPORT_KIND_FULL, &body)
6428 }
6429 } else {
6430 Self::wrap_side_transport_frame(SIDE_TRANSPORT_KIND_FULL, raw.as_ref())
6431 };
6432
6433 let frames = if opts.max_frame_bytes != 0 && wrapped.len() > opts.max_frame_bytes {
6434 self.split_side_transport_frame(side, wrapped, opts.max_frame_bytes)
6435 } else {
6436 Ok(vec![wrapped])
6437 }?;
6438 let wire_len = frames.iter().map(|frame| frame.len()).sum::<usize>();
6439 let mut st = self.state.lock();
6440 let stats = st.side_runtime_stats.entry(side).or_default();
6441 if used_compact {
6442 let overhead = compact_payload_len
6443 .map(|payload_len| wire_len.saturating_sub(payload_len))
6444 .unwrap_or(wire_len);
6445 stats.note_side_transport_compact(
6446 raw_len,
6447 wire_len,
6448 overhead,
6449 used_timestamp_delta,
6450 omitted_timestamp,
6451 );
6452 if opts.compact_header_target_bytes != 0 && overhead > opts.compact_header_target_bytes
6453 {
6454 stats.note_side_transport_compact_target_miss();
6455 }
6456 } else {
6457 stats.note_side_transport_full(raw_len, wire_len);
6458 }
6459 if frames.len() > 1 {
6460 stats.note_side_transport_chunks(frames.len());
6461 }
6462 Ok(frames)
6463 }
6464
6465 fn decode_side_transport_frame(
6466 &self,
6467 side: RouterSideId,
6468 bytes: &[u8],
6469 ) -> TelemetryResult<Option<Arc<[u8]>>> {
6470 let Some((kind, body)) = Self::parse_side_transport_wrapper(bytes)? else {
6471 return Ok(Some(Arc::from(bytes)));
6472 };
6473 match kind {
6474 SIDE_TRANSPORT_KIND_FULL => {
6475 let mut off = 0usize;
6476 let template_id = u32::try_from(Self::read_uleb128_local(body, &mut off)?)
6477 .map_err(|_| TelemetryError::Unpack("side template id too large"))?;
6478 let raw = Arc::<[u8]>::from(&body[off..]);
6479 if let Ok((template, _, _, _, timestamp, _, _, _)) =
6480 Self::extract_side_header_template(raw.as_ref())
6481 {
6482 let mut st = self.state.lock();
6483 let max_templates = st
6484 .sides
6485 .get(side)
6486 .and_then(|side| side.as_ref())
6487 .map(|side| side.opts.max_side_transport_templates)
6488 .unwrap_or(DEFAULT_SIDE_TRANSPORT_TEMPLATE_LIMIT);
6489 let evicted = st.side_transport.get_mut(&side).is_some_and(|side_state| {
6490 let evicted =
6491 side_state.insert_rx_template(template_id, template, max_templates);
6492 side_state.rx_last_timestamps.insert(template_id, timestamp);
6493 evicted
6494 });
6495 if evicted {
6496 st.side_runtime_stats
6497 .entry(side)
6498 .or_default()
6499 .note_side_transport_template_eviction();
6500 }
6501 }
6502 Ok(Some(raw))
6503 }
6504 SIDE_TRANSPORT_KIND_COMPACT
6505 | SIDE_TRANSPORT_KIND_COMPACT_DELTA
6506 | SIDE_TRANSPORT_KIND_COMPACT_SAME_TIMESTAMP => {
6507 if body.is_empty() {
6508 return Err(TelemetryError::Unpack("short side compact frame"));
6509 }
6510 let mut off = 1usize;
6511 let template_id = u32::try_from(Self::read_uleb128_local(body, &mut off)?)
6512 .map_err(|_| TelemetryError::Unpack("side template id too large"))?;
6513 let mut compact_body = Vec::with_capacity(1 + body.len().saturating_sub(off));
6514 compact_body.push(body[0]);
6515 compact_body.extend_from_slice(&body[off..]);
6516 let (template, timestamp_base) = {
6517 let st = self.state.lock();
6518 let state = st.side_transport.get(&side);
6519 let template = state
6520 .and_then(|state| state.rx_templates_by_id.get(&template_id))
6521 .cloned();
6522 let timestamp_base = if matches!(
6523 kind,
6524 SIDE_TRANSPORT_KIND_COMPACT_DELTA
6525 | SIDE_TRANSPORT_KIND_COMPACT_SAME_TIMESTAMP
6526 ) {
6527 state
6528 .and_then(|state| state.rx_last_timestamps.get(&template_id))
6529 .copied()
6530 } else {
6531 None
6532 };
6533 (template, timestamp_base)
6534 };
6535 let Some(template) = template else {
6539 return Ok(None);
6540 };
6541 let timestamp_mode = match kind {
6542 SIDE_TRANSPORT_KIND_COMPACT_DELTA => SideCompactTimestampMode::Delta,
6543 SIDE_TRANSPORT_KIND_COMPACT_SAME_TIMESTAMP => SideCompactTimestampMode::Omitted,
6544 _ => SideCompactTimestampMode::Absolute,
6545 };
6546 let (frame, timestamp) = Self::reconstruct_side_compact_frame(
6547 &template,
6548 &compact_body,
6549 timestamp_mode,
6550 timestamp_base,
6551 )?;
6552 let mut st = self.state.lock();
6553 if let Some(side_state) = st.side_transport.get_mut(&side) {
6554 side_state.rx_last_timestamps.insert(template_id, timestamp);
6555 }
6556 Ok(Some(frame))
6557 }
6558 SIDE_TRANSPORT_KIND_CHUNK => {
6559 if body.len() < 8 {
6560 return Err(TelemetryError::Unpack("short side chunk frame"));
6561 }
6562 let transfer_id = u32::from_le_bytes([body[0], body[1], body[2], body[3]]);
6563 let index = u16::from_le_bytes([body[4], body[5]]);
6564 let total = u16::from_le_bytes([body[6], body[7]]);
6565 let payload = Arc::<[u8]>::from(&body[8..]);
6566 let assembled = {
6567 let mut st = self.state.lock();
6568 let side_state = st
6569 .side_transport
6570 .get_mut(&side)
6571 .ok_or(TelemetryError::BadArg)?;
6572 let entry = side_state.rx_chunks.entry(transfer_id).or_default();
6573 if entry.total == 0 {
6574 entry.total = total;
6575 } else if entry.total != total {
6576 side_state.rx_chunks.remove(&transfer_id);
6577 return Err(TelemetryError::Unpack("side chunk total mismatch"));
6578 }
6579 entry.received.entry(index).or_insert(payload);
6580 if entry.received.len() == usize::from(total) {
6581 let entry = side_state
6582 .rx_chunks
6583 .remove(&transfer_id)
6584 .ok_or(TelemetryError::Unpack("side chunk missing"))?;
6585 let mut out = Vec::new();
6586 for idx in 0..entry.total {
6587 let chunk = entry
6588 .received
6589 .get(&idx)
6590 .ok_or(TelemetryError::Unpack("side chunk gap"))?;
6591 out.extend_from_slice(chunk);
6592 }
6593 Some(Arc::<[u8]>::from(out))
6594 } else {
6595 None
6596 }
6597 };
6598 match assembled {
6599 Some(frame) => self.decode_side_transport_frame(side, frame.as_ref()),
6600 None => Ok(None),
6601 }
6602 }
6603 _ => Err(TelemetryError::Unpack("unknown side transport frame")),
6604 }
6605 }
6606
6607 fn call_side_tx_handler(
6608 &self,
6609 side: RouterSideId,
6610 handler: &RouterTxHandlerFn,
6611 data: &RouterItem,
6612 relayed: bool,
6613 ) -> TelemetryResult<()> {
6614 let opts = {
6615 let st = self.state.lock();
6616 Self::side_ref(&st, side)?.opts
6617 };
6618 let Some(_side_tx_guard) = self.try_enter_side_tx() else {
6619 return Err(TelemetryError::Io("side tx busy"));
6620 };
6621 let started_ms = self.clock.now_ms();
6622 let ty = match data {
6623 RouterItem::Packet(pkt) => pkt.data_type(),
6624 RouterItem::Packed(bytes) => wire_format::peek_envelope(bytes.as_ref())?.ty,
6625 };
6626 let result = match (handler, data) {
6627 (RouterTxHandlerFn::Packed(f), RouterItem::Packed(bytes)) => {
6628 #[cfg(feature = "cryptography")]
6629 let send_bytes = self.prepare_packed_for_remote(bytes.clone(), None)?;
6630 #[cfg(not(feature = "cryptography"))]
6631 let send_bytes = bytes.clone();
6632 let frames = self.encode_side_transport_frames(side, opts, send_bytes)?;
6633 let mut attempts_total = 0usize;
6634 let mut sent_bytes = 0usize;
6635 for frame in frames {
6636 match self
6637 .retry_with_attempts(runtime_max_handler_retries(), || f(frame.as_ref()))
6638 {
6639 Ok((_, attempts)) => {
6640 attempts_total = attempts_total.saturating_add(attempts);
6641 sent_bytes = sent_bytes.saturating_add(frame.len());
6642 }
6643 Err((err, attempts)) => {
6644 self.note_side_tx_failure(
6645 side,
6646 ty,
6647 attempts_total.saturating_add(attempts),
6648 );
6649 return Err(err);
6650 }
6651 }
6652 }
6653 self.record_side_tx_sample(side, sent_bytes, started_ms, self.clock.now_ms());
6654 self.note_side_tx_success(side, ty, sent_bytes, relayed, attempts_total);
6655 return Ok(());
6656 }
6657 (RouterTxHandlerFn::Packet(f), RouterItem::Packet(pkt)) => {
6658 self.retry_with_attempts(runtime_max_handler_retries(), || f(pkt))
6659 }
6660 (RouterTxHandlerFn::Packed(f), RouterItem::Packet(pkt)) => {
6661 let owned = self.pack_packet_for_router(pkt, None)?;
6662 let frames = self.encode_side_transport_frames(side, opts, owned)?;
6663 let mut attempts_total = 0usize;
6664 let mut sent_bytes = 0usize;
6665 for frame in frames {
6666 match self
6667 .retry_with_attempts(runtime_max_handler_retries(), || f(frame.as_ref()))
6668 {
6669 Ok((_, attempts)) => {
6670 attempts_total = attempts_total.saturating_add(attempts);
6671 sent_bytes = sent_bytes.saturating_add(frame.len());
6672 }
6673 Err((err, attempts)) => {
6674 self.note_side_tx_failure(
6675 side,
6676 ty,
6677 attempts_total.saturating_add(attempts),
6678 );
6679 return Err(err);
6680 }
6681 }
6682 }
6683 self.record_side_tx_sample(side, sent_bytes, started_ms, self.clock.now_ms());
6684 self.note_side_tx_success(side, ty, sent_bytes, relayed, attempts_total);
6685 return Ok(());
6686 }
6687 (RouterTxHandlerFn::Packet(f), RouterItem::Packed(bytes)) => {
6688 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
6689 self.retry_with_attempts(runtime_max_handler_retries(), || f(&pkt))
6690 }
6691 };
6692 match result {
6693 Ok((_, attempts)) => {
6694 if let Ok(bytes) = Self::router_item_wire_len(data) {
6695 self.record_side_tx_sample(side, bytes, started_ms, self.clock.now_ms());
6696 self.note_side_tx_success(side, ty, bytes, relayed, attempts);
6697 }
6698 Ok(())
6699 }
6700 Err((err, attempts)) => {
6701 self.note_side_tx_failure(side, ty, attempts);
6702 Err(err)
6703 }
6704 }
6705 }
6706
6707 fn adjust_reliable_for_side(
6708 &self,
6709 opts: RouterSideOptions,
6710 data: RouterItem,
6711 preserve_end_to_end_ack: bool,
6712 ) -> TelemetryResult<Option<RouterItem>> {
6713 if opts.reliable_enabled {
6714 return Ok(Some(data));
6715 }
6716
6717 match data {
6718 RouterItem::Packed(bytes) => {
6719 let frame = wire_format::peek_frame_info(bytes.as_ref())?;
6720 if is_reliable_type(frame.envelope.ty)
6721 && let Some(hdr) = frame.reliable
6722 {
6723 if (hdr.flags & wire_format::RELIABLE_FLAG_ACK_ONLY) != 0 {
6724 return Ok(None);
6725 }
6726 if (hdr.flags & wire_format::RELIABLE_FLAG_UNSEQUENCED) == 0 {
6727 let Some(rewritten) = wire_format::rewrite_reliable_header_owned(
6728 bytes.as_ref(),
6729 wire_format::RELIABLE_FLAG_UNSEQUENCED,
6730 hdr.seq,
6731 0,
6732 )?
6733 else {
6734 return Ok(Some(RouterItem::Packed(bytes)));
6735 };
6736 return Ok(Some(RouterItem::Packed(rewritten)));
6737 }
6738 }
6739 Ok(Some(RouterItem::Packed(bytes)))
6740 }
6741 RouterItem::Packet(pkt) => {
6742 if matches!(
6743 pkt.data_type(),
6744 DataType::ReliableAck
6745 | DataType::ReliablePartialAck
6746 | DataType::ReliablePacketRequest
6747 ) {
6748 if preserve_end_to_end_ack
6749 && pkt.data_type() == DataType::ReliableAck
6750 && Self::is_end_to_end_ack_sender(pkt.sender())
6751 {
6752 return Ok(Some(RouterItem::Packet(pkt)));
6753 }
6754 return Ok(None);
6755 }
6756 Ok(Some(RouterItem::Packet(pkt)))
6757 }
6758 }
6759 }
6760
6761 fn process_reliable_timeouts(&self) -> TelemetryResult<()> {
6762 let now = self.clock.now_ms();
6763 let mut requeue: Vec<(RouterSideId, DataType, u32)> = Vec::new();
6764
6765 {
6766 let mut st = self.state.lock();
6767 if st.reliable_tx.is_empty() {
6768 return Ok(());
6769 }
6770
6771 for ((side, ty_u32), tx_state) in st.reliable_tx.iter_mut() {
6772 let Some(ty) = DataType::try_from_u32(*ty_u32) else {
6773 continue;
6774 };
6775 let sent_order: Vec<u32> = tx_state.sent_order.iter().copied().collect();
6776 for seq in sent_order {
6777 let Some(sent) = tx_state.sent.get_mut(&seq) else {
6778 continue;
6779 };
6780 if sent.queued
6781 || now.wrapping_sub(sent.last_send_ms) < runtime_reliable_retransmit_ms()
6782 {
6783 continue;
6784 }
6785 if sent.partial_acked {
6786 continue;
6787 }
6788 if sent.retries >= runtime_reliable_max_retries() {
6789 tx_state.sent.remove(&seq);
6790 tx_state.sent_order.retain(|existing| *existing != seq);
6791 continue;
6792 }
6793 sent.retries += 1;
6794 requeue.push((*side, ty, seq));
6795 }
6796 }
6797 }
6798
6799 for (side, ty, seq) in requeue {
6800 self.queue_reliable_retransmit(side, ty, seq, true)?;
6801 }
6802
6803 Ok(())
6804 }
6805
6806 fn process_end_to_end_reliable_timeouts(&self) -> TelemetryResult<()> {
6807 let now = self.clock.now_ms();
6808 let mut requeue = Vec::new();
6809
6810 {
6811 let mut st = self.state.lock();
6812 #[cfg(feature = "discovery")]
6813 {
6814 if Self::prune_discovery_routes_locked(&mut st, now) {
6815 Self::note_discovery_topology_change_locked(&mut st, now);
6816 }
6817 self.reconcile_end_to_end_reliable_destinations_locked(&mut st)?;
6818 }
6819 let packet_ids: Vec<u64> = st.end_to_end_reliable_tx.keys().copied().collect();
6820 for packet_id in packet_ids {
6821 let Some(sent) = st.end_to_end_reliable_tx.get_mut(&packet_id) else {
6822 continue;
6823 };
6824 if sent.queued
6825 || now.wrapping_sub(sent.last_send_ms) < runtime_reliable_retransmit_ms()
6826 {
6827 continue;
6828 }
6829 if sent.retries >= runtime_reliable_max_retries() {
6830 st.end_to_end_reliable_tx.remove(&packet_id);
6831 continue;
6832 }
6833 sent.retries += 1;
6834 requeue.push(packet_id);
6835 }
6836 }
6837
6838 for packet_id in requeue {
6839 self.queue_end_to_end_reliable_retransmit(packet_id)?;
6840 }
6841
6842 Ok(())
6843 }
6844
6845 #[cfg(feature = "timesync")]
6846 #[inline]
6847 fn monotonic_now_ns(&self) -> u64 {
6848 self.clock.now_ns()
6849 }
6850
6851 #[cfg(feature = "timesync")]
6852 #[inline]
6853 fn monotonic_now_ms(&self) -> u64 {
6854 self.clock.now_ms()
6855 }
6856
6857 #[cfg(feature = "timesync")]
6858 fn refresh_timesync_state(&self, now_mono_ms: u64) {
6859 let now_mono_ns = self.monotonic_now_ns();
6860 let mut st = self.timesync.lock();
6861 st.clock.prune_expired(now_mono_ms);
6862 let timeout_ms = st.cfg.map(|cfg| cfg.source_timeout_ms).unwrap_or(0);
6863 st.remote_sources
6864 .retain(|_, src| now_mono_ms.saturating_sub(src.last_sample_mono_ms) <= timeout_ms);
6865 let has_usable_time = Self::timesync_has_usable_time_locked(&st, now_mono_ns);
6866 let leader = if let Some(tracker) = st.tracker.as_mut() {
6867 let _ = tracker.refresh(now_mono_ms);
6868 tracker.leader(now_mono_ms, has_usable_time)
6869 } else {
6870 None
6871 };
6872 Self::reconcile_pending_timesync_request_locked(&mut st, &leader, now_mono_ms);
6873 if let Some(TimeSyncLeader::Remote(remote)) = leader.as_ref() {
6874 let target_ms = st
6875 .remote_sources
6876 .get(remote.sender.as_str())
6877 .map(|src| src.sample_unix_ms);
6878 if let Some(target_ms) = target_ms {
6879 st.disciplined_clock.steer_unix_ms(now_mono_ns, target_ms);
6880 }
6881 }
6882 }
6883
6884 #[cfg(feature = "timesync")]
6885 pub fn update_network_time_source(
6887 &self,
6888 source: &str,
6889 priority: u64,
6890 time: PartialNetworkTime,
6891 ttl_ms: Option<u64>,
6892 ) {
6893 let now_ms = self.monotonic_now_ms();
6894 let now_ns = self.monotonic_now_ns();
6895 let mut st = self.timesync.lock();
6896 st.clock
6897 .update_source(source, priority, time, now_ms, now_ns, ttl_ms);
6898 if let Some(unix_ms) = time.to_network_time().and_then(|t| t.as_unix_ms()) {
6899 st.disciplined_clock.steer_unix_ms(now_ns, unix_ms);
6900 }
6901 }
6902
6903 #[cfg(feature = "timesync")]
6904 fn set_network_time_source_impl(
6905 &self,
6906 source: &str,
6907 priority: u64,
6908 time: PartialNetworkTime,
6909 ttl_ms: Option<u64>,
6910 ) {
6911 let observed_mono_ms = self.monotonic_now_ms();
6912 let observed_mono_ns = self.monotonic_now_ns();
6913 let mut st = self.timesync.lock();
6914 let commit_mono_ms = self.monotonic_now_ms();
6915 let commit_mono_ns = self.monotonic_now_ns();
6916 let adjusted = if let Some(base) = time.to_network_time() {
6917 let elapsed_ns = commit_mono_ns.saturating_sub(observed_mono_ns);
6918 advance_network_time(base, elapsed_ns)
6919 .map(PartialNetworkTime::from)
6920 .unwrap_or(time)
6921 } else {
6922 time
6923 };
6924 let adjusted_mono_ms =
6925 observed_mono_ms.saturating_add(commit_mono_ms.saturating_sub(observed_mono_ms));
6926 st.clock.update_source(
6927 source,
6928 priority,
6929 adjusted,
6930 commit_mono_ms.max(adjusted_mono_ms),
6931 commit_mono_ns,
6932 ttl_ms,
6933 );
6934 if let Some(unix_ms) = adjusted.to_network_time().and_then(|t| t.as_unix_ms()) {
6935 st.disciplined_clock.steer_unix_ms(commit_mono_ns, unix_ms);
6936 }
6937 }
6938
6939 #[cfg(feature = "timesync")]
6940 fn local_network_time_priority(&self) -> u64 {
6941 let st = self.timesync.lock();
6942 st.cfg.map(|cfg| cfg.priority).unwrap_or(0)
6943 }
6944
6945 #[cfg(feature = "timesync")]
6946 pub fn set_local_network_time(&self, time: PartialNetworkTime) {
6948 let priority = self.local_network_time_priority();
6949 if time.is_complete_date() && time.is_complete_time() {
6950 self.set_network_time_source_impl(LOCAL_TIMESYNC_FULL_SOURCE_ID, priority, time, None);
6951 let mut st = self.timesync.lock();
6952 st.clock.remove_source(LOCAL_TIMESYNC_DATE_SOURCE_ID);
6953 st.clock.remove_source(LOCAL_TIMESYNC_TOD_SOURCE_ID);
6954 st.clock.remove_source(LOCAL_TIMESYNC_SUBSEC_SOURCE_ID);
6955 return;
6956 }
6957
6958 {
6959 let mut st = self.timesync.lock();
6960 st.clock.remove_source(LOCAL_TIMESYNC_FULL_SOURCE_ID);
6961 }
6962
6963 if time.year.is_some() || time.month.is_some() || time.day.is_some() {
6964 self.set_network_time_source_impl(
6965 LOCAL_TIMESYNC_DATE_SOURCE_ID,
6966 priority,
6967 PartialNetworkTime {
6968 year: time.year,
6969 month: time.month,
6970 day: time.day,
6971 ..Default::default()
6972 },
6973 None,
6974 );
6975 }
6976
6977 if time.hour.is_some() || time.minute.is_some() || time.second.is_some() {
6978 self.set_network_time_source_impl(
6979 LOCAL_TIMESYNC_TOD_SOURCE_ID,
6980 priority,
6981 PartialNetworkTime {
6982 hour: time.hour,
6983 minute: time.minute,
6984 second: time.second,
6985 nanosecond: time.nanosecond,
6986 ..Default::default()
6987 },
6988 None,
6989 );
6990 }
6991
6992 if time.nanosecond.is_some() {
6993 self.set_network_time_source_impl(
6994 LOCAL_TIMESYNC_SUBSEC_SOURCE_ID,
6995 priority,
6996 PartialNetworkTime {
6997 nanosecond: time.nanosecond,
6998 ..Default::default()
6999 },
7000 None,
7001 );
7002 }
7003 }
7004
7005 #[cfg(feature = "timesync")]
7006 pub fn clear_local_network_time(&self) {
7008 let mut st = self.timesync.lock();
7009 st.clock.remove_source(LOCAL_TIMESYNC_FULL_SOURCE_ID);
7010 st.clock.remove_source(LOCAL_TIMESYNC_DATE_SOURCE_ID);
7011 st.clock.remove_source(LOCAL_TIMESYNC_TOD_SOURCE_ID);
7012 st.clock.remove_source(LOCAL_TIMESYNC_SUBSEC_SOURCE_ID);
7013 }
7014
7015 #[cfg(feature = "timesync")]
7016 pub fn set_local_network_date(&self, year: i32, month: u8, day: u8) {
7018 self.set_local_network_time(PartialNetworkTime {
7019 year: Some(year),
7020 month: Some(month),
7021 day: Some(day),
7022 ..Default::default()
7023 });
7024 }
7025
7026 #[cfg(feature = "timesync")]
7027 pub fn set_local_network_time_hm(&self, hour: u8, minute: u8) {
7029 self.set_local_network_time(PartialNetworkTime {
7030 hour: Some(hour),
7031 minute: Some(minute),
7032 ..Default::default()
7033 });
7034 }
7035
7036 #[cfg(feature = "timesync")]
7037 pub fn set_local_network_time_hms(&self, hour: u8, minute: u8, second: u8) {
7039 self.set_local_network_time(PartialNetworkTime {
7040 hour: Some(hour),
7041 minute: Some(minute),
7042 second: Some(second),
7043 ..Default::default()
7044 });
7045 }
7046
7047 #[cfg(feature = "timesync")]
7048 pub fn set_local_network_time_hms_millis(
7050 &self,
7051 hour: u8,
7052 minute: u8,
7053 second: u8,
7054 millisecond: u16,
7055 ) {
7056 self.set_local_network_time(PartialNetworkTime {
7057 hour: Some(hour),
7058 minute: Some(minute),
7059 second: Some(second),
7060 nanosecond: Some((millisecond as u32).saturating_mul(1_000_000)),
7061 ..Default::default()
7062 });
7063 }
7064
7065 #[cfg(feature = "timesync")]
7066 pub fn set_local_network_time_hms_nanos(
7068 &self,
7069 hour: u8,
7070 minute: u8,
7071 second: u8,
7072 nanosecond: u32,
7073 ) {
7074 self.set_local_network_time(PartialNetworkTime {
7075 hour: Some(hour),
7076 minute: Some(minute),
7077 second: Some(second),
7078 nanosecond: Some(nanosecond),
7079 ..Default::default()
7080 });
7081 }
7082
7083 #[cfg(feature = "timesync")]
7084 pub fn set_local_network_datetime(
7086 &self,
7087 year: i32,
7088 month: u8,
7089 day: u8,
7090 hour: u8,
7091 minute: u8,
7092 second: u8,
7093 ) {
7094 self.set_local_network_time(PartialNetworkTime {
7095 year: Some(year),
7096 month: Some(month),
7097 day: Some(day),
7098 hour: Some(hour),
7099 minute: Some(minute),
7100 second: Some(second),
7101 ..Default::default()
7102 });
7103 }
7104
7105 #[cfg(feature = "timesync")]
7106 #[allow(clippy::too_many_arguments)]
7107 pub fn set_local_network_datetime_millis(
7109 &self,
7110 year: i32,
7111 month: u8,
7112 day: u8,
7113 hour: u8,
7114 minute: u8,
7115 second: u8,
7116 millisecond: u16,
7117 ) {
7118 self.set_local_network_time(PartialNetworkTime {
7119 year: Some(year),
7120 month: Some(month),
7121 day: Some(day),
7122 hour: Some(hour),
7123 minute: Some(minute),
7124 second: Some(second),
7125 nanosecond: Some((millisecond as u32).saturating_mul(1_000_000)),
7126 });
7127 }
7128
7129 #[cfg(feature = "timesync")]
7130 #[allow(clippy::too_many_arguments)]
7131 pub fn set_local_network_datetime_nanos(
7133 &self,
7134 year: i32,
7135 month: u8,
7136 day: u8,
7137 hour: u8,
7138 minute: u8,
7139 second: u8,
7140 nanosecond: u32,
7141 ) {
7142 self.set_local_network_time(PartialNetworkTime {
7143 year: Some(year),
7144 month: Some(month),
7145 day: Some(day),
7146 hour: Some(hour),
7147 minute: Some(minute),
7148 second: Some(second),
7149 nanosecond: Some(nanosecond),
7150 });
7151 }
7152
7153 #[cfg(feature = "timesync")]
7154 pub fn clear_network_time_source(&self, source: &str) {
7156 let mut st = self.timesync.lock();
7157 st.clock.remove_source(source);
7158 }
7159
7160 #[cfg(feature = "timesync")]
7161 pub fn set_timesync_config(&self, cfg: Option<TimeSyncConfig>) {
7163 let mut st = self.timesync.lock();
7164 let stale_remote_sources: Vec<String> = st.remote_sources.keys().cloned().collect();
7165 st.cfg = cfg;
7166 st.tracker = cfg.map(TimeSyncTracker::new);
7167 st.disciplined_clock = SlewedNetworkClock::new(
7168 cfg.map(|c| c.max_slew_ppm)
7169 .unwrap_or(TimeSyncConfig::default().max_slew_ppm),
7170 );
7171 st.remote_sources.clear();
7172 st.next_seq = 1;
7173 st.next_announce_mono_ms = 0;
7174 st.next_request_mono_ms = 0;
7175 st.pending_request = None;
7176 st.clock.remove_source(INTERNAL_TIMESYNC_SOURCE_ID);
7177 for source in stale_remote_sources {
7178 st.clock.remove_source(&source);
7179 }
7180 st.clock.remove_source(LOCAL_TIMESYNC_FULL_SOURCE_ID);
7181 st.clock.remove_source(LOCAL_TIMESYNC_DATE_SOURCE_ID);
7182 st.clock.remove_source(LOCAL_TIMESYNC_TOD_SOURCE_ID);
7183 st.clock.remove_source(LOCAL_TIMESYNC_SUBSEC_SOURCE_ID);
7184 }
7185
7186 #[cfg(feature = "timesync")]
7187 pub fn network_time(&self) -> Option<NetworkTimeReading> {
7189 let now_ms = self.monotonic_now_ms();
7190 let now_ns = self.monotonic_now_ns();
7191 self.refresh_timesync_state(now_ms);
7192 let st = self.timesync.lock();
7193 if let Some(unix_ms) = st.disciplined_clock.read_unix_ms(now_ns) {
7194 return Some(NetworkTimeReading {
7195 time: PartialNetworkTime::from_unix_ms(unix_ms),
7196 unix_time_ms: Some(unix_ms),
7197 });
7198 }
7199 st.clock.current_time(now_ns)
7200 }
7201
7202 #[cfg(feature = "timesync")]
7203 pub fn network_time_ms(&self) -> Option<u64> {
7205 self.network_time().and_then(|t| t.unix_time_ms)
7206 }
7207
7208 #[cfg(feature = "timesync")]
7209 fn packet_timestamp_ms(&self) -> u64 {
7210 self.network_time_ms()
7211 .unwrap_or_else(|| self.monotonic_now_ms())
7212 }
7213
7214 #[cfg(not(feature = "timesync"))]
7215 fn packet_timestamp_ms(&self) -> u64 {
7216 self.clock.now_ms()
7217 }
7218
7219 #[cfg(feature = "timesync")]
7220 fn queue_internal_timesync_request(
7221 &self,
7222 seq: u64,
7223 t1_mono_ms: u64,
7224 called_from_queue: bool,
7225 ) -> TelemetryResult<()> {
7226 let pkt_ts = self.packet_timestamp_ms();
7227 if called_from_queue {
7228 self.log_queue_ts(DataType::TimeSyncRequest, pkt_ts, &[seq, t1_mono_ms])
7229 } else {
7230 self.log_ts(DataType::TimeSyncRequest, pkt_ts, &[seq, t1_mono_ms])
7231 }
7232 }
7233
7234 #[cfg(feature = "timesync")]
7235 fn queue_internal_timesync_response(
7236 &self,
7237 seq: u64,
7238 t1_mono_ms: u64,
7239 t2_network_ms: u64,
7240 t3_network_ms: u64,
7241 dst: Option<RouterSideId>,
7242 called_from_queue: bool,
7243 ) -> TelemetryResult<()> {
7244 let pkt_ts = self.packet_timestamp_ms();
7245 let payload = encode_slice_le(&[seq, t1_mono_ms, t2_network_ms, t3_network_ms]);
7246 let sender = self.sender_arc();
7247 let pkt = Packet::new(
7248 DataType::TimeSyncResponse,
7249 &[DataEndpoint::TimeSync],
7250 sender.as_ref(),
7251 pkt_ts,
7252 payload,
7253 )?;
7254 match dst {
7255 Some(dst) => self.emit_internal_tx(
7256 RouterTxItem::ToSide {
7257 src: None,
7258 dst,
7259 data: RouterItem::Packet(pkt),
7260 },
7261 true,
7262 called_from_queue,
7263 ),
7264 None => self.emit_internal_tx(
7265 RouterTxItem::Broadcast(RouterItem::Packet(pkt)),
7266 true,
7267 called_from_queue,
7268 ),
7269 }
7270 }
7271
7272 #[cfg(feature = "timesync")]
7273 pub fn poll_timesync(&self) -> TelemetryResult<bool> {
7275 let now_ms = self.monotonic_now_ms();
7276 let now_ns = self.monotonic_now_ns();
7277 let mut queued_any = false;
7278 let mut announce_priority = None;
7279 let mut request = None;
7280
7281 {
7282 let mut st = self.timesync.lock();
7283 st.clock.prune_expired(now_ms);
7284 let timeout_ms = st.cfg.map(|cfg| cfg.source_timeout_ms).unwrap_or(0);
7285 st.remote_sources
7286 .retain(|_, src| now_ms.saturating_sub(src.last_sample_mono_ms) <= timeout_ms);
7287 let Some(cfg) = st.cfg else {
7288 return Ok(false);
7289 };
7290
7291 let has_usable_time = Self::timesync_has_usable_time_locked(&st, now_ns);
7292 let (leader, announce_prio) = if let Some(tracker) = st.tracker.as_mut() {
7293 let _ = tracker.refresh(now_ms);
7294 (
7295 tracker.leader(now_ms, has_usable_time),
7296 tracker.local_announce_priority(now_ms, has_usable_time),
7297 )
7298 } else {
7299 (None, None)
7300 };
7301 Self::reconcile_pending_timesync_request_locked(&mut st, &leader, now_ms);
7302
7303 if let Some(TimeSyncLeader::Remote(remote)) = leader.as_ref() {
7304 let target_ms = st
7305 .remote_sources
7306 .get(&remote.sender)
7307 .map(|src| src.sample_unix_ms);
7308 if let Some(target_ms) = target_ms {
7309 st.disciplined_clock.steer_unix_ms(now_ns, target_ms);
7310 }
7311 }
7312
7313 if let Some(priority) = announce_prio
7314 && now_ms >= st.next_announce_mono_ms
7315 {
7316 announce_priority = Some(priority);
7317 st.next_announce_mono_ms = now_ms.saturating_add(cfg.announce_interval_ms);
7318 }
7319
7320 if let Some(TimeSyncLeader::Remote(remote)) = leader
7321 && now_ms >= st.next_request_mono_ms
7322 && st.pending_request.is_none()
7323 {
7324 let seq = st.next_seq;
7325 let next = st.next_seq.wrapping_add(1);
7326 st.next_seq = if next == 0 { 1 } else { next };
7327 st.next_request_mono_ms = now_ms.saturating_add(cfg.request_interval_ms);
7328 st.pending_request = Some(PendingTimeSyncRequest {
7329 seq,
7330 t1_mono_ms: now_ms,
7331 source: remote.sender,
7332 });
7333 request = Some((seq, now_ms));
7334 }
7335 }
7336
7337 if let Some(priority) = announce_priority {
7338 let time_ms = self.packet_timestamp_ms();
7339 self.log_queue_ts(DataType::TimeSyncAnnounce, time_ms, &[priority, time_ms])?;
7340 queued_any = true;
7341 }
7342 if let Some((seq, t1_mono_ms)) = request {
7343 self.queue_internal_timesync_request(seq, t1_mono_ms, true)?;
7344 queued_any = true;
7345 }
7346
7347 Ok(queued_any)
7348 }
7349
7350 #[cfg(feature = "timesync")]
7351 fn handle_internal_timesync_packet(
7352 &self,
7353 pkt: &Packet,
7354 src: Option<RouterSideId>,
7355 called_from_queue: bool,
7356 ) -> TelemetryResult<bool> {
7357 let Some(cfg) = self.cfg.timesync_config() else {
7358 if self.should_route_remote(&RouterItem::Packet(pkt.clone()), src)? {
7359 self.relay_send(RouterItem::Packet(pkt.clone()), src, called_from_queue)?;
7360 }
7361 return Ok(true);
7362 };
7363
7364 let now_mono_ms = self.monotonic_now_ms();
7365 let now_mono_ns = self.monotonic_now_ns();
7366 let mut response = None;
7367 let mut poll_after = false;
7368
7369 {
7370 let mut st = self.timesync.lock();
7371 st.clock.prune_expired(now_mono_ms);
7372 let timeout_ms = st.cfg.map(|cfg| cfg.source_timeout_ms).unwrap_or(0);
7373 st.remote_sources
7374 .retain(|_, src| now_mono_ms.saturating_sub(src.last_sample_mono_ms) <= timeout_ms);
7375 let has_usable_time = Self::timesync_has_usable_time_locked(&st, now_mono_ns);
7376 if st.tracker.is_none() {
7377 return Ok(true);
7378 }
7379
7380 match pkt.data_type() {
7381 DataType::TimeSyncAnnounce => {
7382 let ann = decode_timesync_announce(pkt)?;
7383 let should_steer = {
7384 let tracker = st.tracker.as_mut().expect("tracker checked above");
7385 let _ = tracker.handle_announce(pkt, now_mono_ms)?;
7386 matches!(
7387 tracker.leader(now_mono_ms, has_usable_time),
7388 Some(TimeSyncLeader::Remote(ref remote)) if remote.sender == pkt.sender()
7389 )
7390 };
7391 st.remote_sources.insert(
7392 pkt.sender().to_owned(),
7393 RemoteTimeSyncSource {
7394 priority: ann.priority,
7395 last_sample_mono_ms: now_mono_ms,
7396 sample_unix_ms: ann.time_ms,
7397 },
7398 );
7399 st.clock.update_source(
7400 pkt.sender(),
7401 ann.priority,
7402 PartialNetworkTime::from_unix_ms(ann.time_ms),
7403 now_mono_ms,
7404 now_mono_ns,
7405 Some(cfg.source_timeout_ms),
7406 );
7407 if should_steer {
7408 st.disciplined_clock.steer_unix_ms(now_mono_ns, ann.time_ms);
7409 }
7410 poll_after = true;
7411 }
7412 DataType::TimeSyncRequest => {
7413 let should_serve = {
7414 let tracker = st.tracker.as_ref().expect("tracker checked above");
7415 tracker.should_serve(now_mono_ms, has_usable_time)
7416 };
7417 if should_serve {
7418 let req = decode_timesync_request(pkt)?;
7419 let network_now = st
7420 .disciplined_clock
7421 .read_unix_ms(now_mono_ns)
7422 .or_else(|| {
7423 st.clock
7424 .current_time(now_mono_ns)
7425 .and_then(|t| t.unix_time_ms)
7426 })
7427 .unwrap_or(now_mono_ms);
7428 let t2 = network_now;
7429 let t3 = network_now;
7430 response = Some((req.seq, req.t1_ms, t2, t3, src));
7431 }
7432 }
7433 DataType::TimeSyncResponse => {
7434 let resp = decode_timesync_response(pkt)?;
7435 let pending = st.pending_request.clone();
7436 if let Some(pending) = pending
7437 && pending.seq == resp.seq
7438 && pending.source == pkt.sender()
7439 {
7440 let source_priority = {
7441 let tracker = st.tracker.as_ref().expect("tracker checked above");
7442 tracker
7443 .best_active_source(now_mono_ms)
7444 .map(|s| s.priority)
7445 .or_else(|| st.remote_sources.get(pkt.sender()).map(|s| s.priority))
7446 .unwrap_or(cfg.priority)
7447 };
7448 let (estimate_ms, _delay_ms) = compute_network_time_sample(
7449 pending.t1_mono_ms,
7450 resp.t2_ms,
7451 resp.t3_ms,
7452 now_mono_ms,
7453 );
7454 st.remote_sources.insert(
7455 pkt.sender().to_owned(),
7456 RemoteTimeSyncSource {
7457 priority: source_priority,
7458 last_sample_mono_ms: now_mono_ms,
7459 sample_unix_ms: estimate_ms,
7460 },
7461 );
7462 st.clock.update_source(
7463 pkt.sender(),
7464 source_priority,
7465 PartialNetworkTime::from_unix_ms(estimate_ms),
7466 now_mono_ms,
7467 now_mono_ns,
7468 Some(cfg.source_timeout_ms),
7469 );
7470 st.disciplined_clock.steer_unix_ms(now_mono_ns, estimate_ms);
7471 st.pending_request = None;
7472 }
7473 }
7474 _ => {}
7475 }
7476 }
7477
7478 if let Some((seq, t1, t2, t3, dst)) = response {
7479 self.queue_internal_timesync_response(seq, t1, t2, t3, dst, called_from_queue)?;
7480 }
7481 if poll_after {
7482 let _ = self.poll_timesync()?;
7483 }
7484
7485 if self.should_route_remote(&RouterItem::Packet(pkt.clone()), src)? {
7486 self.relay_send(RouterItem::Packet(pkt.clone()), src, called_from_queue)?;
7487 }
7488
7489 Ok(true)
7490 }
7491
7492 #[cfg(feature = "std")]
7494 pub fn new(cfg: RouterConfig) -> Self {
7495 Self::new_with_clock(cfg, Box::new(StdMonotonicClock::default()))
7496 }
7497
7498 pub fn new_with_clock(cfg: RouterConfig, clock: Box<dyn Clock + Send + Sync>) -> Self {
7500 #[cfg(feature = "timesync")]
7501 let timesync_cfg = cfg.timesync_config();
7502 let memory = cfg.memory_config();
7503 let hostname: Arc<str> = Arc::from(cfg.sender());
7504 let address_mode = cfg.address_mode();
7505 let instance_seq = u64::from(ROUTER_INSTANCE_SEQ.fetch_add(1, Ordering::Relaxed));
7506 let owner_hash = Self::sender_hash(hostname.as_ref()) ^ instance_seq;
7507 let fallback = Self::fallback_address_for_hostname(hostname.as_ref());
7508 let requested = address_mode.requested_address();
7509 let address = if requested == 0 { fallback } else { requested };
7510 let local_address = AddressBookEntry {
7511 hostname: hostname.clone(),
7512 address,
7513 requested_address: requested,
7514 mode: address_mode,
7515 birth_ms: clock
7516 .now_ms()
7517 .saturating_mul(1_000_000)
7518 .saturating_add(instance_seq),
7519 owner_hash,
7520 last_seen_ms: clock.now_ms(),
7521 };
7522 let mut address_book = BTreeMap::new();
7523 address_book.insert(hostname.to_string(), local_address.clone());
7524 let mut address_by_value = BTreeMap::new();
7525 address_by_value.insert(address, hostname.to_string());
7526 Self {
7527 sender: RouterMutex::new(hostname),
7528 cfg,
7529 state: RouterMutex::new(RouterInner {
7530 memory,
7531 sides: Vec::new(),
7532 route_overrides: BTreeMap::new(),
7533 typed_route_overrides: BTreeMap::new(),
7534 route_weights: BTreeMap::new(),
7535 route_priorities: BTreeMap::new(),
7536 source_route_modes: BTreeMap::new(),
7537 route_selection_cursors: BTreeMap::new(),
7538 adaptive_route_stats: BTreeMap::new(),
7539 side_runtime_stats: BTreeMap::new(),
7540 side_transport: BTreeMap::new(),
7541 managed_variable_types: BTreeSet::new(),
7542 managed_variable_permissions: BTreeMap::new(),
7543 managed_variable_latest: BTreeMap::new(),
7544 network_variable_update_handlers: BTreeMap::new(),
7545 local_address,
7546 address_book,
7547 address_by_value,
7548 p2p_port_handlers: BTreeMap::new(),
7549 p2p_stream_handlers: BTreeMap::new(),
7550 p2p_stream_sessions: BTreeMap::new(),
7551 next_p2p_stream_id: 1,
7552 received_queue: BoundedDeque::new(
7553 memory.max_queue_budget,
7554 memory.starting_queue_size,
7555 memory.queue_grow_step,
7556 ),
7557 transmit_queue: BoundedDeque::new(
7558 memory.max_queue_budget,
7559 memory.starting_queue_size,
7560 memory.queue_grow_step,
7561 ),
7562 tx_priority_burst: 0,
7563 recent_rx: BoundedDeque::new(
7564 memory.recent_rx_queue_bytes(),
7565 memory.recent_rx_queue_bytes(),
7566 memory.queue_grow_step,
7567 ),
7568 reliable_tx: BTreeMap::new(),
7569 reliable_rx: BTreeMap::new(),
7570 reliable_return_routes: BTreeMap::new(),
7571 reliable_return_route_order: VecDeque::new(),
7572 end_to_end_reliable_tx: BTreeMap::new(),
7573 end_to_end_reliable_tx_order: VecDeque::new(),
7574 total_handler_failures: 0,
7575 total_handler_retries: 0,
7576 #[cfg(feature = "discovery")]
7577 discovery_routes: BTreeMap::new(),
7578 #[cfg(feature = "discovery")]
7579 discovery_cadence: DiscoveryCadenceState::default(),
7580 #[cfg(feature = "discovery")]
7581 discovery_side_throttle: BTreeMap::new(),
7582 #[cfg(all(feature = "discovery", feature = "timesync"))]
7583 timesync_side_throttle: BTreeMap::new(),
7584 }),
7585 isr_rx_queue: IsrRxQueue::new(
7586 memory.max_queue_budget,
7587 memory.starting_queue_size,
7588 memory.queue_grow_step,
7589 ),
7590 side_tx_gate: ReentryGate::new(),
7591 clock,
7592 #[cfg(feature = "timesync")]
7593 timesync: RouterMutex::new(TimeSyncRuntime::new(timesync_cfg)),
7594 }
7595 }
7596
7597 #[inline]
7598 fn sender_arc(&self) -> Arc<str> {
7599 self.sender.lock().clone()
7600 }
7601
7602 #[inline]
7603 pub fn sender(&self) -> Arc<str> {
7604 self.sender_arc()
7605 }
7606
7607 pub fn current_address(&self) -> NodeAddress {
7608 self.state.lock().local_address.address
7609 }
7610
7611 pub fn hostname(&self) -> Arc<str> {
7612 self.sender_arc()
7613 }
7614
7615 pub fn address_book(&self) -> Vec<AddressBookEntry> {
7616 self.state.lock().address_book.values().cloned().collect()
7617 }
7618
7619 pub fn resolve_hostname(&self, hostname: &str) -> Option<AddressBookEntry> {
7620 self.state.lock().address_book.get(hostname).cloned()
7621 }
7622
7623 pub fn resolve_address(&self, address: NodeAddress) -> Option<AddressBookEntry> {
7624 let st = self.state.lock();
7625 st.address_by_value
7626 .get(&address)
7627 .and_then(|hostname| st.address_book.get(hostname))
7628 .cloned()
7629 }
7630
7631 pub fn bind_p2p_port<F>(&self, port: P2pPort, f: F) -> TelemetryResult<()>
7632 where
7633 F: Fn(P2pMessage<'_>) -> TelemetryResult<()> + Send + Sync + 'static,
7634 {
7635 if port == 0 {
7636 return Err(TelemetryError::BadArg);
7637 }
7638 let mut st = self.state.lock();
7639 st.p2p_port_handlers
7640 .entry(port)
7641 .or_default()
7642 .push(P2pPortHandler {
7643 handler: Arc::new(f),
7644 });
7645 Ok(())
7646 }
7647
7648 pub fn clear_p2p_port(&self, port: P2pPort) {
7649 self.state.lock().p2p_port_handlers.remove(&port);
7650 }
7651
7652 pub fn bind_p2p_stream_port<F>(&self, port: P2pPort, f: F) -> TelemetryResult<()>
7653 where
7654 F: Fn(P2pStreamEvent<'_>) -> TelemetryResult<()> + Send + Sync + 'static,
7655 {
7656 if port == 0 {
7657 return Err(TelemetryError::BadArg);
7658 }
7659 let mut st = self.state.lock();
7660 st.p2p_stream_handlers
7661 .entry(port)
7662 .or_default()
7663 .push(P2pStreamHandler {
7664 handler: Arc::new(f),
7665 });
7666 Ok(())
7667 }
7668
7669 pub fn clear_p2p_stream_port(&self, port: P2pPort) {
7670 self.state.lock().p2p_stream_handlers.remove(&port);
7671 }
7672
7673 fn send_p2p_to_entry(
7674 &self,
7675 dst: AddressBookEntry,
7676 dst_port: P2pPort,
7677 src_port: P2pPort,
7678 payload: &[u8],
7679 ) -> TelemetryResult<()> {
7680 if dst_port == 0 {
7681 return Err(TelemetryError::BadArg);
7682 }
7683 let local = self.state.lock().local_address.clone();
7684 let payload = Self::encode_p2p_payload(
7685 local.hostname.as_ref(),
7686 local.address,
7687 src_port,
7688 dst_port,
7689 payload,
7690 )?;
7691 let pkt = Packet::new(
7692 DataType::P2pMessage,
7693 &[DataEndpoint::Discovery],
7694 local.hostname.as_ref(),
7695 self.packet_timestamp_ms(),
7696 payload,
7697 )?;
7698 let target = Self::sender_hash(dst.hostname.as_ref());
7699 let item = self.attach_wire_contract_to_item(RouterItem::Packet(pkt.clone()), &[target])?;
7700 if target == Self::sender_hash(self.sender_arc().as_ref()) {
7701 self.dispatch_p2p_packet(&pkt)?;
7702 return Ok(());
7703 }
7704 self.tx_item_impl(RouterTxItem::Broadcast(item), true, false)
7705 }
7706
7707 pub fn send_p2p_to_hostname(
7708 &self,
7709 hostname: &str,
7710 dst_port: P2pPort,
7711 src_port: P2pPort,
7712 payload: &[u8],
7713 ) -> TelemetryResult<()> {
7714 let dst = self
7715 .resolve_hostname(hostname)
7716 .ok_or(TelemetryError::BadArg)?;
7717 self.send_p2p_to_entry(dst, dst_port, src_port, payload)
7718 }
7719
7720 pub fn send_p2p_to_address(
7721 &self,
7722 address: NodeAddress,
7723 dst_port: P2pPort,
7724 src_port: P2pPort,
7725 payload: &[u8],
7726 ) -> TelemetryResult<()> {
7727 let dst = self
7728 .resolve_address(address)
7729 .ok_or(TelemetryError::BadArg)?;
7730 self.send_p2p_to_entry(dst, dst_port, src_port, payload)
7731 }
7732
7733 fn open_p2p_stream_to_entry(
7734 &self,
7735 dst: AddressBookEntry,
7736 dst_port: P2pPort,
7737 src_port: P2pPort,
7738 ) -> TelemetryResult<P2pStreamId> {
7739 if dst_port == 0 || src_port == 0 {
7740 return Err(TelemetryError::BadArg);
7741 }
7742 let stream_id = {
7743 let mut st = self.state.lock();
7744 let stream_id = Self::allocate_p2p_stream_id_locked(&mut st);
7745 if stream_id == 0 {
7746 return Err(TelemetryError::Io("p2p stream id exhausted"));
7747 }
7748 st.p2p_stream_sessions.insert(
7749 stream_id,
7750 P2pStreamSession {
7751 peer_hostname: dst.hostname.clone(),
7752 peer_address: dst.address,
7753 local_port: src_port,
7754 peer_port: dst_port,
7755 peer_stream_id: 0,
7756 next_sequence: 1,
7757 connected: false,
7758 },
7759 );
7760 stream_id
7761 };
7762 let payload = Self::encode_p2p_stream_payload(P2P_STREAM_SYN, stream_id, 0, 0, &[])?;
7763 self.send_p2p_to_entry(dst, dst_port, src_port, &payload)?;
7764 Ok(stream_id)
7765 }
7766
7767 pub fn open_p2p_stream_to_hostname(
7768 &self,
7769 hostname: &str,
7770 dst_port: P2pPort,
7771 src_port: P2pPort,
7772 ) -> TelemetryResult<P2pStreamId> {
7773 let dst = self
7774 .resolve_hostname(hostname)
7775 .ok_or(TelemetryError::BadArg)?;
7776 self.open_p2p_stream_to_entry(dst, dst_port, src_port)
7777 }
7778
7779 pub fn open_p2p_stream_to_address(
7780 &self,
7781 address: NodeAddress,
7782 dst_port: P2pPort,
7783 src_port: P2pPort,
7784 ) -> TelemetryResult<P2pStreamId> {
7785 let dst = self
7786 .resolve_address(address)
7787 .ok_or(TelemetryError::BadArg)?;
7788 self.open_p2p_stream_to_entry(dst, dst_port, src_port)
7789 }
7790
7791 fn send_p2p_stream_control(
7792 &self,
7793 stream_id: P2pStreamId,
7794 flags: u8,
7795 payload: &[u8],
7796 ) -> TelemetryResult<()> {
7797 let (dst, dst_port, src_port, peer_stream_id, seq, refresh_syn) = {
7798 let mut st = self.state.lock();
7799 let Some(session) = st.p2p_stream_sessions.get_mut(&stream_id) else {
7800 return Err(TelemetryError::BadArg);
7801 };
7802 let peer_hostname = session.peer_hostname.clone();
7803 let peer_address = session.peer_address;
7804 let peer_port = session.peer_port;
7805 let local_port = session.local_port;
7806 let peer_stream_id = session.peer_stream_id;
7807 let refresh_syn = peer_stream_id == 0 && flags & P2P_STREAM_SYN == 0;
7808 let seq = session.next_sequence;
7809 session.next_sequence = session.next_sequence.wrapping_add(1).max(1);
7810 let dst = st
7811 .address_book
7812 .get(peer_hostname.as_ref())
7813 .cloned()
7814 .unwrap_or(AddressBookEntry {
7815 hostname: peer_hostname.clone(),
7816 address: peer_address,
7817 requested_address: peer_address,
7818 mode: AddressAssignmentMode::Dynamic,
7819 birth_ms: self.clock.now_ms(),
7820 owner_hash: Self::sender_hash(peer_hostname.as_ref()),
7821 last_seen_ms: self.clock.now_ms(),
7822 });
7823 (dst, peer_port, local_port, peer_stream_id, seq, refresh_syn)
7824 };
7825 if refresh_syn {
7826 let syn_payload =
7827 Self::encode_p2p_stream_payload(P2P_STREAM_SYN, stream_id, 0, 0, &[])?;
7828 self.send_p2p_to_entry(dst.clone(), dst_port, src_port, &syn_payload)?;
7829 }
7830 let stream_payload =
7831 Self::encode_p2p_stream_payload(flags, stream_id, peer_stream_id, seq, payload)?;
7832 self.send_p2p_to_entry(dst, dst_port, src_port, &stream_payload)?;
7833 if flags & (P2P_STREAM_FIN | P2P_STREAM_RST) != 0 {
7834 self.state.lock().p2p_stream_sessions.remove(&stream_id);
7835 }
7836 Ok(())
7837 }
7838
7839 pub fn send_p2p_stream(&self, stream_id: P2pStreamId, payload: &[u8]) -> TelemetryResult<()> {
7840 self.send_p2p_stream_control(stream_id, P2P_STREAM_DATA, payload)
7841 }
7842
7843 pub fn close_p2p_stream(&self, stream_id: P2pStreamId) -> TelemetryResult<()> {
7844 self.send_p2p_stream_control(stream_id, P2P_STREAM_FIN, &[])
7845 }
7846
7847 pub fn reset_p2p_stream(&self, stream_id: P2pStreamId) -> TelemetryResult<()> {
7848 self.send_p2p_stream_control(stream_id, P2P_STREAM_RST, &[])
7849 }
7850
7851 pub fn set_sender<S: AsRef<str>>(&self, sender: S) {
7852 let hostname: Arc<str> = Arc::from(sender.as_ref());
7853 let mut st = self.state.lock();
7854 let mut local = st.local_address.clone();
7855 local.hostname = hostname.clone();
7856 local.owner_hash = Self::sender_hash(hostname.as_ref());
7857 if matches!(local.mode, AddressAssignmentMode::Dynamic) {
7858 local.address = Self::fallback_address_for_hostname(hostname.as_ref());
7859 local.requested_address = 0;
7860 }
7861 let change =
7862 self.update_local_identity_locked(&mut st, local, AddressChangeReason::Configured);
7863 drop(st);
7864 let _ = self.notify_address_change(change);
7865 }
7866
7867 pub fn set_address_assignment(
7868 &self,
7869 mode: AddressAssignmentMode,
7870 ) -> TelemetryResult<AddressChange> {
7871 let mut st = self.state.lock();
7872 let mut local = st.local_address.clone();
7873 local.mode = mode;
7874 local.requested_address = mode.requested_address();
7875 local.address = match mode {
7876 AddressAssignmentMode::Dynamic => {
7877 Self::fallback_address_for_hostname(local.hostname.as_ref())
7878 }
7879 AddressAssignmentMode::Requested(address) | AddressAssignmentMode::Static(address) => {
7880 if address == 0 {
7881 1
7882 } else {
7883 address
7884 }
7885 }
7886 };
7887 let change =
7888 self.update_local_identity_locked(&mut st, local, AddressChangeReason::Configured);
7889 drop(st);
7890 self.notify_address_change(change.clone())?;
7891 Ok(change)
7892 }
7893
7894 pub fn add_side_packed<N, F>(&self, name: N, tx: F) -> RouterSideId
7903 where
7904 N: AsRef<str>,
7905 F: Fn(&[u8]) -> TelemetryResult<()> + Send + Sync + 'static,
7906 {
7907 self.add_side_packed_with_options(name, tx, RouterSideOptions::default())
7908 }
7909
7910 pub fn add_side_packed_small_packets<N, F>(
7914 &self,
7915 name: N,
7916 tx: F,
7917 max_frame_bytes: usize,
7918 ) -> RouterSideId
7919 where
7920 N: AsRef<str>,
7921 F: Fn(&[u8]) -> TelemetryResult<()> + Send + Sync + 'static,
7922 {
7923 self.add_side_packed_with_options(
7924 name,
7925 tx,
7926 RouterSideOptions::default().with_small_packet_transport(max_frame_bytes),
7927 )
7928 }
7929
7930 pub fn add_side_packed_with_options<N, F>(
7939 &self,
7940 name: N,
7941 tx: F,
7942 opts: RouterSideOptions,
7943 ) -> RouterSideId
7944 where
7945 N: AsRef<str>,
7946 F: Fn(&[u8]) -> TelemetryResult<()> + Send + Sync + 'static,
7947 {
7948 let mut st = self.state.lock();
7949 let side = Some(RouterSide {
7950 name: Arc::from(name.as_ref()),
7951 tx_handler: RouterTxHandlerFn::Packed(Arc::new(tx)),
7952 opts,
7953 });
7954 let id = if let Some(id) = st.sides.iter().position(Option::is_none) {
7955 st.sides[id] = side;
7956 id
7957 } else {
7958 let id = st.sides.len();
7959 st.sides.push(side);
7960 id
7961 };
7962 st.side_runtime_stats
7963 .insert(id, SideRuntimeStatsInner::default());
7964 st.side_transport.insert(id, SideTransportState::default());
7965 #[cfg(feature = "discovery")]
7966 Self::note_discovery_topology_change_locked(&mut st, self.clock.now_ms());
7967 id
7968 }
7969
7970 pub fn add_side_packet<N, F>(&self, name: N, tx: F) -> RouterSideId
7975 where
7976 N: AsRef<str>,
7977 F: Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static,
7978 {
7979 self.add_side_packet_with_options(name, tx, RouterSideOptions::default())
7980 }
7981
7982 pub fn add_side_packet_with_options<N, F>(
7988 &self,
7989 name: N,
7990 tx: F,
7991 opts: RouterSideOptions,
7992 ) -> RouterSideId
7993 where
7994 N: AsRef<str>,
7995 F: Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static,
7996 {
7997 let mut st = self.state.lock();
7998 let side = Some(RouterSide {
7999 name: Arc::from(name.as_ref()),
8000 tx_handler: RouterTxHandlerFn::Packet(Arc::new(tx)),
8001 opts,
8002 });
8003 let id = if let Some(id) = st.sides.iter().position(Option::is_none) {
8004 st.sides[id] = side;
8005 id
8006 } else {
8007 let id = st.sides.len();
8008 st.sides.push(side);
8009 id
8010 };
8011 st.side_runtime_stats
8012 .insert(id, SideRuntimeStatsInner::default());
8013 st.side_transport.insert(id, SideTransportState::default());
8014 #[cfg(feature = "discovery")]
8015 Self::note_discovery_topology_change_locked(&mut st, self.clock.now_ms());
8016 id
8017 }
8018
8019 pub fn remove_side(&self, side: RouterSideId) -> TelemetryResult<()> {
8024 let now_ms = self.clock.now_ms();
8025 {
8026 let mut st = self.state.lock();
8027 let slot = st.sides.get_mut(side).ok_or(TelemetryError::BadArg)?;
8028 if slot.is_none() {
8029 return Err(TelemetryError::BadArg);
8030 }
8031 *slot = None;
8032 while st.sides.last().is_some_and(Option::is_none) {
8033 st.sides.pop();
8034 }
8035 st.route_overrides
8040 .retain(|(src_side, dst_side), _| *src_side != Some(side) && *dst_side != side);
8041 st.typed_route_overrides
8042 .retain(|(src_side, _, dst_side), _| *src_side != Some(side) && *dst_side != side);
8043 st.route_weights
8044 .retain(|(src_side, dst_side), _| *src_side != Some(side) && *dst_side != side);
8045 st.route_priorities
8046 .retain(|(src_side, dst_side), _| *src_side != Some(side) && *dst_side != side);
8047 st.source_route_modes.remove(&Some(side));
8048 st.route_selection_cursors.remove(&Some(side));
8049 st.adaptive_route_stats.remove(&side);
8050 #[cfg(feature = "discovery")]
8051 st.discovery_side_throttle.remove(&side);
8052 #[cfg(all(feature = "discovery", feature = "timesync"))]
8053 st.timesync_side_throttle.remove(&side);
8054 st.side_runtime_stats.remove(&side);
8055 st.side_transport.remove(&side);
8056 st.reliable_return_routes
8057 .retain(|_, route| route.side != side);
8058 st.transmit_queue.retain(
8059 |queued| {
8060 !matches!(&queued.item, RouterTxItem::ToSide { dst, .. } if *dst == side)
8061 && !matches!(&queued.item, RouterTxItem::ReliableReplay { dst, .. } if *dst == side)
8062 },
8063 );
8064 st.received_queue.retain(|queued| queued.src != Some(side));
8065 st.reliable_tx.retain(|(side_id, _), _| *side_id != side);
8066 st.reliable_rx.retain(|(side_id, _), _| *side_id != side);
8067 #[cfg(feature = "discovery")]
8068 {
8069 st.discovery_routes.remove(&side);
8070 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8071 }
8072 }
8073 let mut isr_rx = self.isr_rx_queue.try_lock()?;
8074 isr_rx.retain(|queued| queued.src != Some(side));
8075 Ok(())
8076 }
8077
8078 pub fn set_side_ingress_enabled(
8083 &self,
8084 side: RouterSideId,
8085 enabled: bool,
8086 ) -> TelemetryResult<()> {
8087 let now_ms = self.clock.now_ms();
8088 let mut st = self.state.lock();
8089 let side_ref = st
8090 .sides
8091 .get_mut(side)
8092 .and_then(|side| side.as_mut())
8093 .ok_or(TelemetryError::BadArg)?;
8094 side_ref.opts.ingress_enabled = enabled;
8095 #[cfg(feature = "discovery")]
8096 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8097 Ok(())
8098 }
8099
8100 pub fn set_side_egress_enabled(
8104 &self,
8105 side: RouterSideId,
8106 enabled: bool,
8107 ) -> TelemetryResult<()> {
8108 let now_ms = self.clock.now_ms();
8109 let mut st = self.state.lock();
8110 let side_ref = st
8111 .sides
8112 .get_mut(side)
8113 .and_then(|side| side.as_mut())
8114 .ok_or(TelemetryError::BadArg)?;
8115 side_ref.opts.egress_enabled = enabled;
8116 if !enabled {
8117 st.transmit_queue.retain(
8118 |queued| {
8119 !matches!(&queued.item, RouterTxItem::ToSide { dst, .. } if *dst == side)
8120 && !matches!(&queued.item, RouterTxItem::ReliableReplay { dst, .. } if *dst == side)
8121 },
8122 );
8123 }
8124 #[cfg(feature = "discovery")]
8125 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8126 Ok(())
8127 }
8128
8129 pub fn set_source_route_mode(
8135 &self,
8136 src: Option<RouterSideId>,
8137 mode: RouteSelectionMode,
8138 ) -> TelemetryResult<()> {
8139 let now_ms = self.clock.now_ms();
8140 let mut st = self.state.lock();
8141 if let Some(src) = src {
8142 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8143 }
8144 st.source_route_modes.insert(src, mode);
8148 st.route_selection_cursors.remove(&src);
8149 #[cfg(feature = "discovery")]
8150 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8151 Ok(())
8152 }
8153
8154 pub fn clear_source_route_mode(&self, src: Option<RouterSideId>) -> TelemetryResult<()> {
8156 let now_ms = self.clock.now_ms();
8157 let mut st = self.state.lock();
8158 if let Some(src) = src {
8159 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8160 }
8161 st.source_route_modes.remove(&src);
8162 st.route_selection_cursors.remove(&src);
8163 #[cfg(feature = "discovery")]
8164 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8165 Ok(())
8166 }
8167
8168 pub fn set_route_weight(
8173 &self,
8174 src: Option<RouterSideId>,
8175 dst: RouterSideId,
8176 weight: u32,
8177 ) -> TelemetryResult<()> {
8178 let now_ms = self.clock.now_ms();
8179 let mut st = self.state.lock();
8180 let _ = Self::side_ref(&st, dst).map_err(|_| TelemetryError::BadArg)?;
8181 if let Some(src) = src {
8182 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8183 }
8184 st.route_weights.insert((src, dst), weight);
8185 st.route_selection_cursors.remove(&src);
8186 #[cfg(feature = "discovery")]
8187 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8188 Ok(())
8189 }
8190
8191 pub fn clear_route_weight(
8193 &self,
8194 src: Option<RouterSideId>,
8195 dst: RouterSideId,
8196 ) -> TelemetryResult<()> {
8197 let now_ms = self.clock.now_ms();
8198 let mut st = self.state.lock();
8199 let _ = Self::side_ref(&st, dst).map_err(|_| TelemetryError::BadArg)?;
8200 if let Some(src) = src {
8201 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8202 }
8203 st.route_weights.remove(&(src, dst));
8204 st.route_selection_cursors.remove(&src);
8205 #[cfg(feature = "discovery")]
8206 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8207 Ok(())
8208 }
8209
8210 pub fn set_route_priority(
8215 &self,
8216 src: Option<RouterSideId>,
8217 dst: RouterSideId,
8218 priority: u32,
8219 ) -> TelemetryResult<()> {
8220 let now_ms = self.clock.now_ms();
8221 let mut st = self.state.lock();
8222 let _ = Self::side_ref(&st, dst).map_err(|_| TelemetryError::BadArg)?;
8223 if let Some(src) = src {
8224 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8225 }
8226 st.route_priorities.insert((src, dst), priority);
8227 #[cfg(feature = "discovery")]
8228 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8229 Ok(())
8230 }
8231
8232 pub fn clear_route_priority(
8234 &self,
8235 src: Option<RouterSideId>,
8236 dst: RouterSideId,
8237 ) -> TelemetryResult<()> {
8238 let now_ms = self.clock.now_ms();
8239 let mut st = self.state.lock();
8240 let _ = Self::side_ref(&st, dst).map_err(|_| TelemetryError::BadArg)?;
8241 if let Some(src) = src {
8242 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8243 }
8244 st.route_priorities.remove(&(src, dst));
8245 #[cfg(feature = "discovery")]
8246 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8247 Ok(())
8248 }
8249
8250 pub fn set_route(
8255 &self,
8256 src: Option<RouterSideId>,
8257 dst: RouterSideId,
8258 enabled: bool,
8259 ) -> TelemetryResult<()> {
8260 let now_ms = self.clock.now_ms();
8261 let mut st = self.state.lock();
8262 let _ = Self::side_ref(&st, dst).map_err(|_| TelemetryError::BadArg)?;
8263 if let Some(src) = src {
8264 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8265 }
8266 st.route_overrides.insert((src, dst), enabled);
8267 #[cfg(feature = "discovery")]
8268 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8269 Ok(())
8270 }
8271
8272 pub fn set_typed_route(
8277 &self,
8278 src: Option<RouterSideId>,
8279 ty: DataType,
8280 dst: RouterSideId,
8281 enabled: bool,
8282 ) -> TelemetryResult<()> {
8283 let now_ms = self.clock.now_ms();
8284 let mut st = self.state.lock();
8285 let _ = Self::side_ref(&st, dst).map_err(|_| TelemetryError::BadArg)?;
8286 if let Some(src) = src {
8287 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8288 }
8289 st.typed_route_overrides
8290 .insert((src, ty.as_u32(), dst), enabled);
8291 #[cfg(feature = "discovery")]
8292 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8293 Ok(())
8294 }
8295
8296 pub fn clear_typed_route(
8298 &self,
8299 src: Option<RouterSideId>,
8300 ty: DataType,
8301 dst: RouterSideId,
8302 ) -> TelemetryResult<()> {
8303 let now_ms = self.clock.now_ms();
8304 let mut st = self.state.lock();
8305 let _ = Self::side_ref(&st, dst).map_err(|_| TelemetryError::BadArg)?;
8306 if let Some(src) = src {
8307 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8308 }
8309 st.typed_route_overrides.remove(&(src, ty.as_u32(), dst));
8310 #[cfg(feature = "discovery")]
8311 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8312 Ok(())
8313 }
8314
8315 pub fn clear_route(&self, src: Option<RouterSideId>, dst: RouterSideId) -> TelemetryResult<()> {
8317 let now_ms = self.clock.now_ms();
8318 let mut st = self.state.lock();
8319 let _ = Self::side_ref(&st, dst).map_err(|_| TelemetryError::BadArg)?;
8320 if let Some(src) = src {
8321 let _ = Self::side_ref(&st, src).map_err(|_| TelemetryError::BadArg)?;
8322 }
8323 st.route_overrides.remove(&(src, dst));
8324 #[cfg(feature = "discovery")]
8325 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8326 Ok(())
8327 }
8328
8329 #[cfg(feature = "discovery")]
8331 pub fn announce_discovery(&self) -> TelemetryResult<()> {
8332 self.queue_discovery_announce(true)
8333 }
8334
8335 #[cfg(feature = "discovery")]
8337 pub fn announce_leave(&self) -> TelemetryResult<()> {
8338 let sender = self.sender_arc();
8339 let pkt = discovery::build_discovery_leave(sender.as_ref(), self.clock.now_ms())?;
8340 self.tx_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)))
8341 }
8342
8343 #[cfg(feature = "discovery")]
8345 pub fn poll_discovery(&self) -> TelemetryResult<bool> {
8346 self.poll_discovery_announce()
8347 }
8348
8349 #[cfg(feature = "discovery")]
8350 pub fn request_topology(&self) -> TelemetryResult<()> {
8351 let sender = self.sender_arc();
8352 let pkt =
8353 discovery::build_discovery_topology_request(sender.as_ref(), self.clock.now_ms())?;
8354 self.tx_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)))
8355 }
8356
8357 #[cfg(feature = "discovery")]
8358 pub fn request_schema(&self) -> TelemetryResult<()> {
8359 let sender = self.sender_arc();
8360 let pkt = discovery::build_discovery_schema_request(sender.as_ref(), self.clock.now_ms())?;
8361 self.tx_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)))
8362 }
8363
8364 pub fn enable_managed_variable(&self, ty: DataType) -> TelemetryResult<()> {
8371 self.enable_network_variable(ty, NetworkVariablePermissions::READ_WRITE)
8372 }
8373
8374 pub fn enable_network_variable(
8379 &self,
8380 ty: DataType,
8381 permissions: NetworkVariablePermissions,
8382 ) -> TelemetryResult<()> {
8383 if is_internal_control_type(ty) {
8384 return Err(TelemetryError::InvalidType);
8385 }
8386 let mut st = self.state.lock();
8387 st.managed_variable_types.insert(ty.as_u32());
8388 st.managed_variable_permissions
8389 .insert(ty.as_u32(), permissions);
8390 Ok(())
8391 }
8392
8393 pub fn on_network_variable_update<F>(&self, ty: DataType, f: F) -> TelemetryResult<()>
8399 where
8400 F: Fn(&Packet) -> TelemetryResult<()> + Send + Sync + 'static,
8401 {
8402 if is_internal_control_type(ty) {
8403 return Err(TelemetryError::InvalidType);
8404 }
8405 let mut st = self.state.lock();
8406 st.managed_variable_types.insert(ty.as_u32());
8407 st.network_variable_update_handlers
8408 .entry(ty.as_u32())
8409 .or_default()
8410 .push(NetworkVariableUpdateHandler {
8411 handler: Arc::new(f),
8412 });
8413 Ok(())
8414 }
8415
8416 pub fn disable_managed_variable(&self, ty: DataType) {
8417 let mut st = self.state.lock();
8418 st.managed_variable_types.remove(&ty.as_u32());
8419 st.managed_variable_permissions.remove(&ty.as_u32());
8420 st.managed_variable_latest.remove(&ty.as_u32());
8421 st.network_variable_update_handlers.remove(&ty.as_u32());
8422 }
8423
8424 pub fn seed_managed_variable(&self, pkt: Packet) -> TelemetryResult<()> {
8425 if is_internal_control_type(pkt.data_type()) {
8426 return Err(TelemetryError::InvalidType);
8427 }
8428 pkt.validate()?;
8429 {
8430 let mut st = self.state.lock();
8431 st.managed_variable_types.insert(pkt.data_type().as_u32());
8432 }
8433 self.cache_managed_variable_packet(&pkt, false)
8434 }
8435
8436 pub fn cached_managed_variable(&self, ty: DataType) -> Option<Packet> {
8437 self.managed_variable_latest(ty)
8438 }
8439
8440 pub fn set_network_variable(&self, pkt: Packet) -> TelemetryResult<()> {
8446 if is_internal_control_type(pkt.data_type()) {
8447 return Err(TelemetryError::InvalidType);
8448 }
8449 pkt.validate()?;
8450 let ty = pkt.data_type();
8451 {
8452 let mut st = self.state.lock();
8453 st.managed_variable_types.insert(ty.as_u32());
8454 let perms = Self::managed_variable_permissions_locked(&st, ty);
8455 if !perms.write {
8456 return Err(TelemetryError::PermissionDenied);
8457 }
8458 }
8459 self.cache_managed_variable_packet(&pkt, false)?;
8460 #[cfg(feature = "discovery")]
8461 let _ = self.poll_discovery()?;
8462 let item = RouterTxItem::Broadcast(RouterItem::Packet(pkt));
8463 if self.side_tx_active() {
8464 return self.tx_queue_item_with_priority(
8465 item,
8466 false,
8467 crate::transport_priority(DataType::ManagedVariableValue),
8468 );
8469 }
8470 self.tx_item(item)
8471 }
8472
8473 #[cfg(feature = "discovery")]
8480 pub fn get_network_variable(
8481 &self,
8482 ty: DataType,
8483 stale_after_ms: Option<u64>,
8484 ) -> TelemetryResult<Option<Packet>> {
8485 if is_internal_control_type(ty) {
8486 return Err(TelemetryError::InvalidType);
8487 }
8488 {
8489 let mut st = self.state.lock();
8490 st.managed_variable_types.insert(ty.as_u32());
8491 let perms = Self::managed_variable_permissions_locked(&st, ty);
8492 if !perms.read {
8493 return Err(TelemetryError::PermissionDenied);
8494 }
8495 }
8496 let cached = self.managed_variable_latest_with_age(ty);
8497 let needs_refresh = match (cached.as_ref(), stale_after_ms) {
8498 (None, _) => true,
8499 (Some((_pkt, age_ms)), Some(max_age_ms)) => *age_ms > max_age_ms,
8500 (Some(_), None) => false,
8501 };
8502 if needs_refresh {
8503 self.request_managed_variable(ty)?;
8504 }
8505 Ok(cached.map(|(pkt, _age_ms)| pkt))
8506 }
8507
8508 pub fn get_cached_network_variable(&self, ty: DataType) -> TelemetryResult<Option<Packet>> {
8510 if is_internal_control_type(ty) {
8511 return Err(TelemetryError::InvalidType);
8512 }
8513 if !self.can_read_managed_variable(ty) {
8514 return Err(TelemetryError::PermissionDenied);
8515 }
8516 Ok(self.managed_variable_latest(ty))
8517 }
8518
8519 #[cfg(feature = "discovery")]
8520 pub fn request_managed_variable(&self, ty: DataType) -> TelemetryResult<()> {
8521 if is_internal_control_type(ty) {
8522 return Err(TelemetryError::InvalidType);
8523 }
8524 if !self.can_read_managed_variable(ty) {
8525 return Err(TelemetryError::PermissionDenied);
8526 }
8527 let sender = self.sender_arc();
8528 let pkt =
8529 discovery::build_managed_variable_request(sender.as_ref(), self.clock.now_ms(), ty)?;
8530 self.tx_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)))
8531 }
8532
8533 #[cfg(feature = "discovery")]
8534 pub fn request_managed_variable_by_name(&self, ty_name: &str) -> TelemetryResult<()> {
8535 let ty = DataType::try_named(ty_name).ok_or(TelemetryError::InvalidType)?;
8536 self.request_managed_variable(ty)
8537 }
8538
8539 #[cfg(feature = "discovery")]
8541 pub fn export_topology(&self) -> TopologySnapshot {
8542 let now_ms = self.clock.now_ms();
8543 let mut st = self.state.lock();
8544 if Self::prune_discovery_routes_locked(&mut st, now_ms) {
8545 Self::note_discovery_topology_change_locked(&mut st, now_ms);
8546 }
8547 let routes = st
8548 .discovery_routes
8549 .iter()
8550 .filter_map(|(&side_id, route)| {
8551 let side = st.sides.get(side_id)?.as_ref()?;
8552 let announcers = route
8553 .announcers
8554 .iter()
8555 .map(|(sender_id, sender_state)| TopologyAnnouncerRoute {
8556 sender_id: sender_id.clone(),
8557 reachable_endpoints: sender_state
8558 .reachable
8559 .iter()
8560 .copied()
8561 .filter(|ep| !discovery::is_router_control_endpoint(*ep))
8562 .collect(),
8563 reachable_timesync_sources: sender_state.reachable_timesync_sources.clone(),
8564 routers: sender_state.topology_boards.clone(),
8565 last_seen_ms: sender_state.last_seen_ms,
8566 age_ms: now_ms.saturating_sub(sender_state.last_seen_ms),
8567 })
8568 .collect();
8569 Some(TopologySideRoute {
8570 side_id,
8571 side_name: side.name.to_string(),
8572 reachable_endpoints: route
8573 .reachable
8574 .iter()
8575 .copied()
8576 .filter(|ep| !discovery::is_router_control_endpoint(*ep))
8577 .collect(),
8578 reachable_timesync_sources: route.reachable_timesync_sources.clone(),
8579 announcers,
8580 last_seen_ms: route.last_seen_ms,
8581 age_ms: now_ms.saturating_sub(route.last_seen_ms),
8582 })
8583 })
8584 .collect();
8585 let routers = self.advertised_discovery_topology_for_link_locked(&st, now_ms, true, None);
8586 let advertised_endpoints =
8587 self.advertised_discovery_endpoints_for_link_locked(&st, now_ms, true, None);
8588 let advertised_timesync_sources =
8589 self.advertised_discovery_timesync_sources_for_link_locked(&st, now_ms, None);
8590 let links = discovery::topology_links_from_boards(&routers);
8591 TopologySnapshot {
8592 advertised_endpoints,
8593 advertised_timesync_sources,
8594 routers,
8595 links,
8596 routes,
8597 current_announce_interval_ms: st.discovery_cadence.current_interval_ms,
8598 next_announce_ms: st.discovery_cadence.next_announce_ms,
8599 }
8600 }
8601
8602 #[cfg(feature = "discovery")]
8603 pub fn client_stats(&self, sender_id: &str) -> Option<ClientStatsSnapshot> {
8604 let now_ms = self.clock.now_ms();
8605 let st = self.state.lock();
8606 let mut side_ids = Vec::new();
8607 let mut side_names = Vec::new();
8608 let mut last_seen_ms = None::<u64>;
8609 let mut reachable_endpoints = Vec::new();
8610 let mut reachable_timesync_sources = Vec::new();
8611 let mut packets_sent = 0u64;
8612 let mut packets_received = 0u64;
8613 let mut bytes_sent = 0u64;
8614 let mut bytes_received = 0u64;
8615
8616 for (side_id, route) in &st.discovery_routes {
8617 let Some(sender_state) = route.announcers.get(sender_id) else {
8618 continue;
8619 };
8620 side_ids.push(*side_id);
8621 if let Some(side_name) = st
8622 .sides
8623 .get(*side_id)
8624 .and_then(|side| side.as_ref())
8625 .map(|side| side.name.clone())
8626 {
8627 side_names.push(side_name.to_string());
8628 }
8629 last_seen_ms = Some(last_seen_ms.unwrap_or(0).max(sender_state.last_seen_ms));
8630 reachable_endpoints.extend(sender_state.reachable.iter().copied());
8631 reachable_timesync_sources
8632 .extend(sender_state.reachable_timesync_sources.iter().cloned());
8633 if let Some(stats) = st.side_runtime_stats.get(side_id) {
8634 packets_sent = packets_sent.saturating_add(stats.tx_packets);
8635 packets_received = packets_received.saturating_add(stats.rx_packets);
8636 bytes_sent = bytes_sent.saturating_add(stats.tx_bytes);
8637 bytes_received = bytes_received.saturating_add(stats.rx_bytes);
8638 }
8639 }
8640
8641 if side_ids.is_empty() {
8642 return None;
8643 }
8644 reachable_endpoints.retain(|ep| !discovery::is_router_control_endpoint(*ep));
8645 reachable_endpoints.sort_unstable();
8646 reachable_endpoints.dedup();
8647 reachable_timesync_sources.sort_unstable();
8648 reachable_timesync_sources.dedup();
8649 side_ids.sort_unstable();
8650 side_ids.dedup();
8651 side_names.sort_unstable();
8652 side_names.dedup();
8653 let age_ms = last_seen_ms.map(|seen| now_ms.saturating_sub(seen));
8654 Some(ClientStatsSnapshot {
8655 sender_id: sender_id.to_string(),
8656 connected: age_ms.is_some_and(|age| age <= DISCOVERY_ROUTE_TTL_MS),
8657 side_ids,
8658 side_names,
8659 last_seen_ms,
8660 age_ms,
8661 reachable_endpoints,
8662 reachable_timesync_sources,
8663 packets_sent,
8664 packets_received,
8665 bytes_sent,
8666 bytes_received,
8667 })
8668 }
8669
8670 pub fn export_runtime_stats(&self) -> RuntimeStatsSnapshot {
8671 let now_ms = self.clock.now_ms();
8672 let isr_rx = self.isr_rx_queue.snapshot().unwrap_or((0, 0));
8673 let st = self.state.lock();
8674
8675 let mut sides = Vec::new();
8676 for (side_id, side) in st.sides.iter().enumerate() {
8677 let Some(side) = side.as_ref() else { continue };
8678 let stats = st
8679 .side_runtime_stats
8680 .get(&side_id)
8681 .cloned()
8682 .unwrap_or_default();
8683 let adaptive = st
8684 .adaptive_route_stats
8685 .get(&side_id)
8686 .cloned()
8687 .unwrap_or_default()
8688 .snapshot(now_ms, true);
8689 let (tx_template_count, rx_template_count) = st
8690 .side_transport
8691 .get(&side_id)
8692 .map(|state| (state.tx_template_count(), state.rx_template_count()))
8693 .unwrap_or((0, 0));
8694 let mut data_types: Vec<RuntimeTypeStats> = stats
8695 .data_types
8696 .into_iter()
8697 .map(|(ty, item)| RuntimeTypeStats {
8698 data_type: DataType(ty),
8699 tx_packets: item.tx_packets,
8700 tx_bytes: item.tx_bytes,
8701 rx_packets: item.rx_packets,
8702 rx_bytes: item.rx_bytes,
8703 relayed_tx_packets: item.relayed_tx_packets,
8704 relayed_tx_bytes: item.relayed_tx_bytes,
8705 relayed_rx_packets: item.relayed_rx_packets,
8706 relayed_rx_bytes: item.relayed_rx_bytes,
8707 tx_retries: item.tx_retries,
8708 handler_failures: item.handler_failures,
8709 })
8710 .collect();
8711 data_types.sort_unstable_by_key(|item| item.data_type.as_u32());
8712 sides.push(RuntimeSideStats {
8713 side_id,
8714 side_name: side.name.to_string(),
8715 reliable_enabled: side.opts.reliable_enabled,
8716 link_local_enabled: side.opts.link_local_enabled,
8717 header_template_enabled: side.opts.header_template_enabled,
8718 max_frame_bytes: side.opts.max_frame_bytes,
8719 compact_header_target_bytes: side.opts.compact_header_target_bytes,
8720 side_transport_profile: side.opts.effective_transport_profile().as_str(),
8721 ingress_enabled: side.opts.ingress_enabled,
8722 egress_enabled: side.opts.egress_enabled,
8723 tx_packets: stats.tx_packets,
8724 tx_bytes: stats.tx_bytes,
8725 rx_packets: stats.rx_packets,
8726 rx_bytes: stats.rx_bytes,
8727 relayed_tx_packets: stats.relayed_tx_packets,
8728 relayed_tx_bytes: stats.relayed_tx_bytes,
8729 relayed_rx_packets: stats.relayed_rx_packets,
8730 relayed_rx_bytes: stats.relayed_rx_bytes,
8731 local_delivery_packets: stats.local_delivery_packets,
8732 tx_retries: stats.tx_retries,
8733 tx_handler_failures: stats.tx_handler_failures,
8734 local_handler_failures: stats.local_handler_failures,
8735 total_handler_retries: stats.total_handler_retries,
8736 side_transport_full_frames: stats.side_transport_full_frames,
8737 side_transport_compact_frames: stats.side_transport_compact_frames,
8738 side_transport_compact_delta_frames: stats.side_transport_compact_delta_frames,
8739 side_transport_compact_omitted_timestamp_frames: stats
8740 .side_transport_compact_omitted_timestamp_frames,
8741 side_transport_chunk_frames: stats.side_transport_chunk_frames,
8742 side_transport_raw_bytes: stats.side_transport_raw_bytes,
8743 side_transport_wire_bytes: stats.side_transport_wire_bytes,
8744 side_transport_bytes_saved: stats.side_transport_bytes_saved,
8745 side_transport_min_compact_overhead_bytes: stats
8746 .side_transport_min_compact_overhead_bytes,
8747 side_transport_max_compact_overhead_bytes: stats
8748 .side_transport_max_compact_overhead_bytes,
8749 side_transport_compact_target_misses: stats.side_transport_compact_target_misses,
8750 side_transport_template_evictions: stats.side_transport_template_evictions,
8751 side_transport_tx_template_count: tx_template_count,
8752 side_transport_rx_template_count: rx_template_count,
8753 max_side_transport_templates: side.opts.max_side_transport_templates,
8754 adaptive,
8755 data_types,
8756 });
8757 }
8758
8759 let mut route_modes: Vec<RouteModeStats> = st
8760 .route_selection_cursors
8761 .iter()
8762 .map(|(src, cursor)| RouteModeStats {
8763 src_side_id: *src,
8764 selection_mode: st.source_route_modes.get(src).copied(),
8765 cursor: *cursor,
8766 })
8767 .collect();
8768 for src in st.source_route_modes.keys() {
8769 if !route_modes.iter().any(|mode| mode.src_side_id == *src) {
8770 route_modes.push(RouteModeStats {
8771 src_side_id: *src,
8772 selection_mode: st.source_route_modes.get(src).copied(),
8773 cursor: 0,
8774 });
8775 }
8776 }
8777 route_modes.sort_unstable_by_key(|mode| mode.src_side_id.unwrap_or(usize::MAX));
8778
8779 let mut route_overrides: Vec<RouteOverrideStats> = st
8780 .route_overrides
8781 .iter()
8782 .map(|((src, dst), enabled)| RouteOverrideStats {
8783 src_side_id: *src,
8784 dst_side_id: *dst,
8785 enabled: *enabled,
8786 })
8787 .collect();
8788 route_overrides.sort_unstable_by_key(|item| {
8789 (item.src_side_id.unwrap_or(usize::MAX), item.dst_side_id)
8790 });
8791
8792 let mut typed_route_overrides: Vec<TypedRouteOverrideStats> = st
8793 .typed_route_overrides
8794 .iter()
8795 .map(|((src, ty, dst), enabled)| TypedRouteOverrideStats {
8796 src_side_id: *src,
8797 data_type: DataType(*ty),
8798 dst_side_id: *dst,
8799 enabled: *enabled,
8800 })
8801 .collect();
8802 typed_route_overrides.sort_unstable_by_key(|item| {
8803 (
8804 item.src_side_id.unwrap_or(usize::MAX),
8805 item.data_type.as_u32(),
8806 item.dst_side_id,
8807 )
8808 });
8809
8810 let mut route_weights: Vec<RouteWeightStats> = st
8811 .route_weights
8812 .iter()
8813 .map(|((src, dst), weight)| RouteWeightStats {
8814 src_side_id: *src,
8815 dst_side_id: *dst,
8816 weight: *weight,
8817 })
8818 .collect();
8819 route_weights.sort_unstable_by_key(|item| {
8820 (item.src_side_id.unwrap_or(usize::MAX), item.dst_side_id)
8821 });
8822
8823 let mut route_priorities: Vec<RoutePriorityStats> = st
8824 .route_priorities
8825 .iter()
8826 .map(|((src, dst), priority)| RoutePriorityStats {
8827 src_side_id: *src,
8828 dst_side_id: *dst,
8829 priority: *priority,
8830 })
8831 .collect();
8832 route_priorities.sort_unstable_by_key(|item| {
8833 (item.src_side_id.unwrap_or(usize::MAX), item.dst_side_id)
8834 });
8835
8836 #[cfg(feature = "discovery")]
8837 let discovery = DiscoveryRuntimeStats {
8838 route_count: st.discovery_routes.len(),
8839 announcer_count: st
8840 .discovery_routes
8841 .values()
8842 .map(|route| route.announcers.len())
8843 .sum(),
8844 current_announce_interval_ms: Some(st.discovery_cadence.current_interval_ms),
8845 next_announce_ms: Some(st.discovery_cadence.next_announce_ms),
8846 };
8847 #[cfg(not(feature = "discovery"))]
8848 let discovery = DiscoveryRuntimeStats {
8849 route_count: 0,
8850 announcer_count: 0,
8851 current_announce_interval_ms: None,
8852 next_announce_ms: None,
8853 };
8854
8855 RuntimeStatsSnapshot {
8856 sides,
8857 route_modes,
8858 route_overrides,
8859 typed_route_overrides,
8860 route_weights,
8861 route_priorities,
8862 queues: QueueRuntimeStats {
8863 rx_len: isr_rx.0.saturating_add(st.received_queue.len()),
8864 rx_bytes: isr_rx.1.saturating_add(st.received_queue.bytes_used()),
8865 tx_len: st.transmit_queue.len(),
8866 tx_bytes: st.transmit_queue.bytes_used(),
8867 replay_len: 0,
8868 replay_bytes: 0,
8869 recent_rx_len: st.recent_rx.len(),
8870 recent_rx_bytes: st.recent_rx.bytes_used(),
8871 reliable_rx_buffered_len: st.reliable_rx_buffer_len(),
8872 reliable_rx_buffered_bytes: st.reliable_rx_buffered_bytes(),
8873 shared_queue_bytes_used: st.shared_queue_bytes_used(),
8874 },
8875 reliable: ReliableRuntimeStats {
8876 reliable_return_route_count: st.reliable_return_routes.len(),
8877 end_to_end_pending_count: st.end_to_end_reliable_tx.len(),
8878 end_to_end_pending_destination_count: st
8879 .end_to_end_reliable_tx
8880 .values()
8881 .map(|sent| sent.pending_destinations.len())
8882 .sum(),
8883 end_to_end_acked_cache_count: 0,
8884 },
8885 discovery,
8886 total_handler_failures: st.total_handler_failures,
8887 total_handler_retries: st.total_handler_retries,
8888 }
8889 }
8890
8891 pub fn export_memory_layout_json(&self) -> String {
8893 let isr_rx = self.isr_rx_queue.snapshot().unwrap_or((0, 0));
8894 let st = self.state.lock();
8895 #[cfg(feature = "discovery")]
8896 let discovery_bytes = st.discovery_bytes_used();
8897 #[cfg(not(feature = "discovery"))]
8898 let discovery_bytes = 0usize;
8899 let schema_bytes = crate::config::schema_bytes_used();
8900 let network_variable_cache_bytes = st
8901 .managed_variable_latest
8902 .values()
8903 .map(|entry| entry.packet.byte_cost())
8904 .sum::<usize>();
8905 let mut out = String::new();
8906 let memory = st.memory;
8907 let _ = fmt::Write::write_fmt(
8908 &mut out,
8909 format_args!(
8910 "{{\"kind\":\"router\",\
8911 \"shared_queue_bytes_used\":{},\"shared_queue_bytes_allocated\":{},\
8912 \"rx_queue_bytes_used\":{},\"rx_queue_bytes_allocated\":{},\"rx_queue_len\":{},\
8913 \"isr_rx_queue_bytes_used\":{},\"isr_rx_queue_bytes_allocated\":{},\"isr_rx_queue_len\":{},\
8914 \"tx_queue_bytes_used\":{},\"tx_queue_bytes_allocated\":{},\"tx_queue_len\":{},\
8915 \"recent_rx_bytes_used\":{},\"recent_rx_bytes_allocated\":{},\"recent_rx_len\":{},\
8916 \"reliable_rx_buffer_bytes_used\":{},\"reliable_rx_buffer_bytes_allocated\":{},\"reliable_rx_buffer_len\":{},\
8917 \"discovery_bytes_used\":{},\"discovery_bytes_allocated\":{},\
8918 \"schema_bytes_used\":{},\"schema_bytes_allocated\":{},\
8919 \"network_variable_cache_bytes_used\":{},\"network_variable_cache_bytes_allocated\":{},\"network_variable_cache_len\":{}}}",
8920 st.shared_queue_bytes_used(),
8921 memory.max_queue_budget,
8922 st.received_queue.bytes_used(),
8923 st.received_queue.max_bytes(),
8924 st.received_queue.len(),
8925 isr_rx.1,
8926 memory.max_queue_budget,
8927 isr_rx.0,
8928 st.transmit_queue.bytes_used(),
8929 st.transmit_queue.max_bytes(),
8930 st.transmit_queue.len(),
8931 st.recent_rx.bytes_used(),
8932 st.recent_rx.max_bytes(),
8933 st.recent_rx.len(),
8934 st.reliable_rx_buffered_bytes(),
8935 memory.max_queue_budget,
8936 st.reliable_rx_buffer_len(),
8937 discovery_bytes,
8938 memory.max_queue_budget,
8939 schema_bytes,
8940 memory.max_queue_budget,
8941 network_variable_cache_bytes,
8942 memory.max_queue_budget,
8943 st.managed_variable_latest.len(),
8944 ),
8945 );
8946 out
8947 }
8948
8949 #[cfg(test)]
8950 pub(crate) fn debug_end_to_end_pending_destination_count(
8951 &self,
8952 packet_id: u64,
8953 ) -> Option<usize> {
8954 let st = self.state.lock();
8955 st.end_to_end_reliable_tx
8956 .get(&packet_id)
8957 .map(|sent| sent.pending_destinations.len())
8958 }
8959
8960 #[cfg(test)]
8961 pub(crate) fn debug_end_to_end_tracked_count(&self) -> usize {
8962 let st = self.state.lock();
8963 st.end_to_end_reliable_tx.len()
8964 }
8965
8966 #[cfg(test)]
8967 pub(crate) fn debug_reliable_return_route_count(&self) -> usize {
8968 let st = self.state.lock();
8969 st.reliable_return_routes.len()
8970 }
8971
8972 #[cfg(test)]
8973 pub(crate) fn debug_side_storage(&self) -> (usize, usize) {
8974 let st = self.state.lock();
8975 (st.sides.len(), st.sides.capacity())
8976 }
8977
8978 #[cfg(test)]
8979 pub(crate) fn debug_queue_lengths(&self) -> (usize, usize, usize) {
8980 let st = self.state.lock();
8981 (
8982 st.received_queue.len(),
8983 st.transmit_queue.len(),
8984 st.recent_rx.len(),
8985 )
8986 }
8987
8988 #[cfg(test)]
8989 pub(crate) fn debug_shared_queue_bytes_used(&self) -> usize {
8990 let st = self.state.lock();
8991 st.shared_queue_bytes_used()
8992 }
8993
8994 #[cfg(test)]
8995 pub(crate) fn debug_recent_rx_capacity(&self) -> (usize, usize) {
8996 let st = self.state.lock();
8997 (st.recent_rx.capacity(), st.recent_rx.max_bytes())
8998 }
8999
9000 fn get_hash(item: &RouterItem) -> u64 {
9004 match item {
9005 RouterItem::Packet(pkt) => pkt.packet_id(),
9006 RouterItem::Packed(bytes) => {
9007 match wire_format::packet_id_from_wire(bytes.as_ref()) {
9008 Ok(id) => id,
9009 Err(_e) => {
9010 let h: u64 = 0x9E37_79B9_7F4A_7C15;
9013 hash_bytes_u64(h, bytes.as_ref())
9014 }
9015 }
9016 }
9017 }
9018 }
9019
9020 fn remove_pkt_id(&self, item: &RouterItem) {
9022 let hash = Self::get_hash(item);
9023 let mut st = self.state.lock();
9024 st.recent_rx.remove_value(&hash);
9025 }
9026
9027 fn is_duplicate_pkt(&self, item: &RouterItem) -> TelemetryResult<bool> {
9030 let id = Self::get_hash(item);
9031 let mut st = self.state.lock();
9032 if st.recent_rx.contains(&id) {
9033 Ok(true)
9034 } else {
9035 st.push_recent_rx(id)?;
9036 Ok(false)
9037 }
9038 }
9039
9040 fn handle_callback_error(
9045 &self,
9046 pkt: &Packet,
9047 dest: Option<DataEndpoint>,
9048 e: TelemetryError,
9049 called_from_queue: bool,
9050 ) -> TelemetryResult<()> {
9051 let device = self.sender_arc();
9052 let error_msg = match dest {
9053 Some(failed_local) => format!(
9054 "Handler for endpoint {:?} failed on device {:?}: {:?}",
9055 failed_local, device, e
9056 ),
9057 None => format!("TX Handler failed on device {:?}: {:?}", device, e),
9058 };
9059
9060 let mut recipients: Vec<DataEndpoint> = pkt
9061 .endpoints()
9062 .iter()
9063 .copied()
9064 .filter(|&ep| self.cfg.is_local_endpoint(ep))
9065 .collect();
9066 recipients.sort_unstable();
9067 recipients.dedup();
9068
9069 if let Some(failed_local) = dest {
9070 recipients.retain(|&ep| ep != failed_local);
9071 }
9072
9073 if recipients.is_empty() && dest.is_none() {
9077 fallback_stdout(&error_msg);
9078 return Ok(());
9079 }
9080
9081 if recipients.is_empty() {
9084 recipients = pkt.endpoints().to_vec();
9085 recipients.sort_unstable();
9086 recipients.dedup();
9087 if let Some(failed_local) = dest {
9088 recipients.retain(|&ep| ep != failed_local);
9089 }
9090 }
9091
9092 if recipients.is_empty() {
9093 fallback_stdout(&error_msg);
9094 return Ok(());
9095 }
9096
9097 let payload = make_error_payload(&error_msg);
9098
9099 let sender = self.sender_arc();
9100 let error_pkt = Packet::new(
9101 DataType::TelemetryError,
9102 &recipients,
9103 sender.as_ref(),
9104 self.packet_timestamp_ms(),
9105 payload,
9106 )?;
9107
9108 self.emit_internal_tx(
9109 RouterTxItem::Broadcast(RouterItem::Packet(error_pkt)),
9110 false,
9111 called_from_queue,
9112 )
9113 }
9114
9115 #[inline]
9119 pub fn process_tx_queue(&self) -> TelemetryResult<()> {
9120 self.process_tx_queue_with_timeout(0)
9121 }
9122
9123 #[inline]
9125 pub fn process_all_queues(&self) -> TelemetryResult<()> {
9126 self.process_all_queues_with_timeout(0)
9127 }
9128
9129 #[inline]
9131 pub fn clear_queues(&self) {
9132 let mut st = self.state.lock();
9133 st.transmit_queue.clear();
9134 st.received_queue.clear();
9135 drop(st);
9136 let _ = self.isr_rx_queue.clear();
9137 }
9138
9139 #[inline]
9141 pub fn clear_rx_queue(&self) {
9142 let mut st = self.state.lock();
9143 st.received_queue.clear();
9144 drop(st);
9145 let _ = self.isr_rx_queue.clear();
9146 }
9147
9148 #[inline]
9150 pub fn clear_tx_queue(&self) {
9151 let mut st = self.state.lock();
9152 st.transmit_queue.clear();
9153 st.tx_priority_burst = 0;
9154 }
9155
9156 fn pop_transmit_queue_locked(st: &mut RouterInner) -> Option<TxQueued> {
9157 st.transmit_queue
9158 .pop_front_fair(&mut st.tx_priority_burst, MAX_PRIORITY_BURST, |item| {
9159 item.priority
9160 })
9161 }
9162
9163 fn process_tx_queue_with_timeout_impl(&self, timeout_ms: u32) -> TelemetryResult<()> {
9166 let start = self.clock.now_ms();
9167 loop {
9168 self.process_reliable_timeouts()?;
9169 self.process_end_to_end_reliable_timeouts()?;
9170 #[cfg(feature = "discovery")]
9171 let _ = self.drain_queued_discovery_rx_before_tx()?;
9172 let pkt_opt = {
9173 let mut st = self.state.lock();
9174 Self::pop_transmit_queue_locked(&mut st)
9175 };
9176 let Some(pkt) = pkt_opt else { break };
9177 self.tx_item_impl(pkt.item, pkt.ignore_local, true)?;
9178 if timeout_ms != 0 && self.clock.now_ms().wrapping_sub(start) >= timeout_ms as u64 {
9179 break;
9180 }
9181 }
9182 Ok(())
9183 }
9184
9185 pub fn process_tx_queue_with_timeout(&self, timeout_ms: u32) -> TelemetryResult<()> {
9188 #[cfg(feature = "timesync")]
9189 let _ = self.poll_timesync()?;
9190 #[cfg(feature = "discovery")]
9191 let _ = self.poll_discovery()?;
9192 self.process_tx_queue_with_timeout_impl(timeout_ms)
9193 }
9194
9195 #[inline]
9197 fn process_rx_queue_item(&self, item: RouterRxItem) -> TelemetryResult<()> {
9198 self.rx_item(&item, true)
9199 }
9200
9201 fn process_rx_queue_with_timeout_impl(&self, timeout_ms: u32) -> TelemetryResult<()> {
9204 let start = self.clock.now_ms();
9205 loop {
9206 let item_opt = self.isr_rx_queue.pop_front().unwrap_or(None).or_else(|| {
9207 let mut st = self.state.lock();
9208 st.received_queue.pop_front()
9209 });
9210 let Some(item) = item_opt else { break };
9211 self.process_rx_queue_item(item)?;
9212 if timeout_ms != 0 && self.clock.now_ms().wrapping_sub(start) >= timeout_ms as u64 {
9213 break;
9214 }
9215 }
9216 Ok(())
9217 }
9218
9219 pub fn process_rx_queue_with_timeout(&self, timeout_ms: u32) -> TelemetryResult<()> {
9222 #[cfg(feature = "timesync")]
9223 let _ = self.poll_timesync()?;
9224 #[cfg(feature = "discovery")]
9225 let _ = self.poll_discovery()?;
9226 self.process_rx_queue_with_timeout_impl(timeout_ms)
9227 }
9228
9229 fn process_all_queues_with_timeout_impl(&self, timeout_ms: u32) -> TelemetryResult<()> {
9232 if timeout_ms == 0 {
9233 loop {
9234 let mut did_any = false;
9235 self.process_reliable_timeouts()?;
9236 self.process_end_to_end_reliable_timeouts()?;
9237 #[cfg(feature = "discovery")]
9238 if self.drain_queued_discovery_rx_before_tx()? {
9239 did_any = true;
9240 }
9241
9242 if let Some(pkt) = {
9243 let mut st = self.state.lock();
9244 Self::pop_transmit_queue_locked(&mut st)
9245 } {
9246 self.tx_item_impl(pkt.item, pkt.ignore_local, true)?;
9247 did_any = true;
9248 }
9249
9250 if let Some(item) = self.isr_rx_queue.pop_front().unwrap_or(None).or_else(|| {
9251 let mut st = self.state.lock();
9252 st.received_queue.pop_front()
9253 }) {
9254 self.process_rx_queue_item(item)?;
9255 did_any = true;
9256 }
9257
9258 if !did_any {
9259 break;
9260 }
9261 }
9262 return Ok(());
9263 }
9264
9265 let tx_budget_ms = u64::from(timeout_ms / 2);
9266 let rx_budget_ms = u64::from(timeout_ms) - tx_budget_ms;
9267
9268 let tx_start = self.clock.now_ms();
9269 loop {
9270 self.process_reliable_timeouts()?;
9271 self.process_end_to_end_reliable_timeouts()?;
9272 #[cfg(feature = "discovery")]
9273 let _ = self.drain_queued_discovery_rx_before_tx()?;
9274 let pkt_opt = {
9275 let mut st = self.state.lock();
9276 Self::pop_transmit_queue_locked(&mut st)
9277 };
9278 let Some(pkt) = pkt_opt else { break };
9279 self.tx_item_impl(pkt.item, pkt.ignore_local, true)?;
9280 if self.clock.now_ms().wrapping_sub(tx_start) >= tx_budget_ms {
9281 break;
9282 }
9283 }
9284
9285 let rx_start = self.clock.now_ms();
9286 loop {
9287 let item_opt = self.isr_rx_queue.pop_front().unwrap_or(None).or_else(|| {
9288 let mut st = self.state.lock();
9289 st.received_queue.pop_front()
9290 });
9291 let Some(item) = item_opt else { break };
9292 self.process_rx_queue_item(item)?;
9293 if self.clock.now_ms().wrapping_sub(rx_start) >= rx_budget_ms {
9294 break;
9295 }
9296 }
9297
9298 Ok(())
9299 }
9300
9301 pub fn process_all_queues_with_timeout(&self, timeout_ms: u32) -> TelemetryResult<()> {
9304 #[cfg(feature = "timesync")]
9305 let _ = self.poll_timesync()?;
9306 #[cfg(feature = "discovery")]
9307 let _ = self.poll_discovery()?;
9308 self.process_all_queues_with_timeout_impl(timeout_ms)
9309 }
9310
9311 pub fn periodic(&self, timeout_ms: u32) -> TelemetryResult<()> {
9316 #[cfg(feature = "timesync")]
9317 let _ = self.poll_timesync()?;
9318
9319 #[cfg(feature = "discovery")]
9320 {
9321 let _ = self.poll_discovery()?;
9322 }
9323
9324 self.process_all_queues_with_timeout_impl(timeout_ms)
9325 }
9326
9327 pub fn periodic_no_timesync(&self, timeout_ms: u32) -> TelemetryResult<()> {
9332 #[cfg(feature = "discovery")]
9333 {
9334 let _ = self.poll_discovery()?;
9335 }
9336
9337 self.process_all_queues_with_timeout_impl(timeout_ms)
9338 }
9339
9340 #[inline]
9342 fn tx_queue_item_with_flags(
9343 &self,
9344 item: RouterTxItem,
9345 ignore_local: bool,
9346 ) -> TelemetryResult<()> {
9347 let priority = match &item {
9348 RouterTxItem::Broadcast(data) => Self::router_item_priority(data)?,
9349 RouterTxItem::EndToEndReplay { .. } => {
9350 Self::router_item_priority_bumped(DataType::ReliableAck)
9351 }
9352 RouterTxItem::ToSide { data, .. } => Self::router_item_priority(data)?,
9353 RouterTxItem::ReliableReplay { bytes, .. } => {
9354 let ty = wire_format::peek_envelope(bytes.as_ref())?.ty;
9355 Self::router_item_priority_bumped(ty)
9356 }
9357 };
9358 self.tx_queue_item_with_priority(item, ignore_local, priority)
9359 }
9360
9361 #[inline]
9362 fn tx_queue_item_with_priority(
9363 &self,
9364 item: RouterTxItem,
9365 ignore_local: bool,
9366 priority: u8,
9367 ) -> TelemetryResult<()> {
9368 let mut st = self.state.lock();
9369 st.push_transmit(TxQueued {
9370 item,
9371 ignore_local,
9372 priority,
9373 })?;
9374 Ok(())
9375 }
9376
9377 #[inline]
9379 fn tx_queue_item(&self, item: RouterTxItem) -> TelemetryResult<()> {
9380 self.tx_queue_item_with_flags(item, false)
9381 }
9382
9383 #[inline]
9384 fn try_enter_side_tx(&self) -> Option<crate::lock::ReentryGuard<'_>> {
9385 self.side_tx_gate.try_enter()
9386 }
9387
9388 #[inline]
9389 fn side_tx_active(&self) -> bool {
9390 self.side_tx_gate.is_active()
9391 }
9392
9393 #[inline]
9397 pub fn process_rx_queue(&self) -> TelemetryResult<()> {
9398 self.process_rx_queue_with_timeout(0)
9399 }
9400
9401 #[inline]
9403 pub fn rx_packed_queue(&self, bytes: &[u8]) -> TelemetryResult<()> {
9404 let data = RouterItem::Packed(Arc::from(bytes));
9405 let priority = Self::router_item_priority(&data)?;
9406 let mut st = self.state.lock();
9407 st.push_received(RouterRxItem {
9408 src: None,
9409 data,
9410 priority,
9411 })?;
9412 Ok(())
9413 }
9414
9415 #[inline]
9420 pub fn rx_packed_queue_isr(&self, bytes: &[u8]) -> TelemetryResult<()> {
9421 let data = RouterItem::Packed(Arc::from(bytes));
9422 let priority = Self::router_item_priority(&data)?;
9423 self.isr_rx_queue.push_back_prioritized(RouterRxItem {
9424 src: None,
9425 data,
9426 priority,
9427 })
9428 }
9429
9430 #[inline]
9432 pub fn rx_queue(&self, pkt: Packet) -> TelemetryResult<()> {
9433 pkt.validate()?;
9434 let data = RouterItem::Packet(pkt);
9435 let priority = Self::router_item_priority(&data)?;
9436 let mut st = self.state.lock();
9437 st.push_received(RouterRxItem {
9438 src: None,
9439 data,
9440 priority,
9441 })?;
9442 Ok(())
9443 }
9444
9445 #[inline]
9450 pub fn rx_queue_isr(&self, pkt: Packet) -> TelemetryResult<()> {
9451 pkt.validate()?;
9452 let data = RouterItem::Packet(pkt);
9453 let priority = Self::router_item_priority(&data)?;
9454 self.isr_rx_queue.push_back_prioritized(RouterRxItem {
9455 src: None,
9456 data,
9457 priority,
9458 })
9459 }
9460
9461 #[inline]
9463 pub fn rx_queue_from_side(&self, pkt: Packet, side: RouterSideId) -> TelemetryResult<()> {
9464 self.ensure_side_ingress_enabled(side)?;
9465 pkt.validate()?;
9466 let data = RouterItem::Packet(pkt);
9467 let priority = Self::router_item_priority(&data)?;
9468 let mut st = self.state.lock();
9469 st.push_received(RouterRxItem {
9470 src: Some(side),
9471 data,
9472 priority,
9473 })?;
9474 Ok(())
9475 }
9476
9477 #[inline]
9482 pub fn rx_queue_from_side_isr(&self, pkt: Packet, side: RouterSideId) -> TelemetryResult<()> {
9483 self.ensure_side_ingress_enabled(side)?;
9484 pkt.validate()?;
9485 let data = RouterItem::Packet(pkt);
9486 let priority = Self::router_item_priority(&data)?;
9487 self.isr_rx_queue.push_back_prioritized(RouterRxItem {
9488 src: Some(side),
9489 data,
9490 priority,
9491 })
9492 }
9493
9494 #[inline]
9496 pub fn rx_packed_queue_from_side(
9497 &self,
9498 bytes: &[u8],
9499 side: RouterSideId,
9500 ) -> TelemetryResult<()> {
9501 self.ensure_side_ingress_enabled(side)?;
9502 let Some(decoded) = self.decode_side_transport_frame(side, bytes)? else {
9503 return Ok(());
9504 };
9505 let data = RouterItem::Packed(decoded);
9506 let priority = Self::router_item_priority(&data)?;
9507 let mut st = self.state.lock();
9508 st.push_received(RouterRxItem {
9509 src: Some(side),
9510 data,
9511 priority,
9512 })?;
9513 Ok(())
9514 }
9515
9516 #[inline]
9521 pub fn rx_packed_queue_from_side_isr(
9522 &self,
9523 bytes: &[u8],
9524 side: RouterSideId,
9525 ) -> TelemetryResult<()> {
9526 self.ensure_side_ingress_enabled(side)?;
9527 let data = RouterItem::Packed(Arc::from(bytes));
9528 let priority = Self::router_item_priority(&data)?;
9529 self.isr_rx_queue.push_back_prioritized(RouterRxItem {
9530 src: Some(side),
9531 data,
9532 priority,
9533 })
9534 }
9535
9536 fn retry_with_attempts<F, T, E>(&self, times: usize, f: F) -> Result<(T, usize), (E, usize)>
9537 where
9538 F: Fn() -> Result<T, E>,
9539 {
9540 let mut last_err = None;
9541 for attempt in 0..times {
9542 match f() {
9543 Ok(v) => return Ok((v, attempt + 1)),
9544 Err(e) => last_err = Some((e, attempt + 1)),
9545 }
9546 }
9547 Err(last_err.expect("times > 0"))
9548 }
9549
9550 #[inline]
9552 fn endpoint_has_packet_handler(&self, ep: DataEndpoint) -> bool {
9553 self.cfg
9554 .handlers
9555 .iter()
9556 .any(|h| h.endpoint == ep && matches!(h.handler, EndpointHandlerFn::Packet(_)))
9557 }
9558
9559 #[inline]
9561 fn endpoint_has_packed_handler(&self, ep: DataEndpoint) -> bool {
9562 self.cfg
9563 .handlers
9564 .iter()
9565 .any(|h| h.endpoint == ep && matches!(h.handler, EndpointHandlerFn::Packed(_)))
9566 }
9567
9568 fn packet_has_local_handler(&self, pkt: &Packet) -> bool {
9569 pkt.endpoints()
9570 .iter()
9571 .copied()
9572 .any(|ep| self.endpoint_has_packet_handler(ep) || self.endpoint_has_packed_handler(ep))
9573 }
9574
9575 fn call_handler_with_retries(
9581 &self,
9582 dest: DataEndpoint,
9583 handler: &EndpointHandler,
9584 data: Option<&[u8]>,
9585 pkt_for_ctx: Option<&Packet>,
9586 env_for_ctx: Option<&wire_format::TelemetryEnvelope>,
9587 called_from_queue: bool,
9588 ) -> TelemetryResult<()> {
9589 let owned_tmp: Option<RouterItem>;
9590
9591 let item_for_ctx: &RouterItem = match (data, pkt_for_ctx) {
9592 (Some(d), _) => {
9593 owned_tmp = Some(RouterItem::Packed(Arc::from(d)));
9594 owned_tmp.as_ref().unwrap()
9595 }
9596 (None, Some(pkt)) => {
9597 owned_tmp = Some(RouterItem::Packet(pkt.clone()));
9598 owned_tmp.as_ref().unwrap()
9599 }
9600 (None, None) => {
9601 debug_assert!(
9602 false,
9603 "call_handler_with_retries called without data or packet context"
9604 );
9605 return Ok(());
9606 }
9607 };
9608
9609 match (&handler.handler, data) {
9610 (EndpointHandlerFn::Packet(f), _) => {
9611 let pkt = pkt_for_ctx.expect("Packet handler requires Packet context");
9612 with_retries(
9613 self,
9614 dest,
9615 item_for_ctx,
9616 pkt_for_ctx,
9617 env_for_ctx,
9618 called_from_queue,
9619 || f(pkt),
9620 )
9621 }
9622
9623 (EndpointHandlerFn::Packed(f), Some(bytes)) => with_retries(
9624 self,
9625 dest,
9626 item_for_ctx,
9627 pkt_for_ctx,
9628 env_for_ctx,
9629 called_from_queue,
9630 || f(bytes),
9631 ),
9632
9633 (EndpointHandlerFn::Packed(_), None) => Ok(()),
9634 }
9635 }
9636
9637 fn handle_callback_error_from_env(
9642 &self,
9643 env: &wire_format::TelemetryEnvelope,
9644 dest: Option<DataEndpoint>,
9645 e: TelemetryError,
9646 called_from_queue: bool,
9647 ) -> TelemetryResult<()> {
9648 let mut recipients: Vec<DataEndpoint> = env
9649 .endpoints
9650 .iter()
9651 .copied()
9652 .filter(|&ep| self.cfg.is_local_endpoint(ep))
9653 .collect();
9654 recipients.sort_unstable();
9655 recipients.dedup();
9656 if let Some(failed) = dest {
9657 recipients.retain(|&ep| ep != failed);
9658 }
9659
9660 let device = self.sender_arc();
9661 let error_msg = format!(
9662 "Handler for endpoint {:?} failed on device {:?}: {:?}",
9663 dest, device, e
9664 );
9665
9666 if recipients.is_empty() && dest.is_none() {
9667 fallback_stdout(&error_msg);
9668 return Ok(());
9669 }
9670
9671 if recipients.is_empty() {
9672 recipients = env.endpoints.to_vec();
9673 recipients.sort_unstable();
9674 recipients.dedup();
9675 if let Some(failed) = dest {
9676 recipients.retain(|&ep| ep != failed);
9677 }
9678 }
9679
9680 if recipients.is_empty() {
9681 fallback_stdout(&error_msg);
9682 return Ok(());
9683 }
9684
9685 let payload = make_error_payload(&error_msg);
9686
9687 let error_pkt = Packet::new(
9688 DataType::TelemetryError,
9689 &recipients,
9690 &env.sender.clone(),
9691 env.timestamp_ms,
9692 payload,
9693 )?;
9694 self.emit_internal_tx(
9695 RouterTxItem::Broadcast(RouterItem::Packet(error_pkt)),
9696 false,
9697 called_from_queue,
9698 )
9699 }
9700
9701 fn handle_internal_reliable_packet(
9702 &self,
9703 pkt: &Packet,
9704 src: Option<RouterSideId>,
9705 called_from_queue: bool,
9706 ) -> TelemetryResult<bool> {
9707 if !matches!(
9708 pkt.data_type(),
9709 DataType::ReliableAck | DataType::ReliablePartialAck | DataType::ReliablePacketRequest
9710 ) {
9711 return Ok(false);
9712 }
9713
9714 let Some(src) = src else {
9715 return Ok(false);
9716 };
9717
9718 if pkt.data_type() == DataType::ReliableAck
9719 && Self::is_end_to_end_ack_sender(pkt.sender())
9720 && let Ok(packet_id) = Self::decode_end_to_end_reliable_ack(pkt.payload())
9721 {
9722 let mut st = self.state.lock();
9723 if let Some(sent) = st.end_to_end_reliable_tx.get_mut(&packet_id) {
9724 if let Some(sender_hash) = Self::decode_end_to_end_ack_sender_hash(pkt.sender()) {
9725 sent.pending_destinations.remove(&sender_hash);
9726 if sent.pending_destinations.is_empty() {
9727 st.end_to_end_reliable_tx.remove(&packet_id);
9728 }
9729 return Ok(true);
9730 }
9731 st.end_to_end_reliable_tx.remove(&packet_id);
9732 return Ok(true);
9733 }
9734 return Ok(false);
9735 }
9736
9737 let vals = pkt.data_as_u32()?;
9738 if vals.len() != 2 {
9739 return Err(TelemetryError::Unpack("bad reliable control payload"));
9740 }
9741 let ty = DataType::try_from_u32(vals[0]).ok_or(TelemetryError::InvalidType)?;
9742 let seq = vals[1];
9743
9744 match pkt.data_type() {
9745 DataType::ReliableAck => {
9746 self.handle_reliable_ack(src, ty, seq);
9747 Ok(true)
9748 }
9749 DataType::ReliablePartialAck => {
9750 self.handle_reliable_partial_ack(src, ty, seq);
9751 Ok(true)
9752 }
9753 DataType::ReliablePacketRequest => {
9754 self.queue_reliable_retransmit(src, ty, seq, called_from_queue)?;
9755 Ok(true)
9756 }
9757 _ => Ok(false),
9758 }
9759 }
9760
9761 fn rx_item(&self, item: &RouterRxItem, called_from_queue: bool) -> TelemetryResult<()> {
9767 if let Some(src) = item.src {
9768 self.ensure_side_ingress_enabled(src)?;
9769 match &item.data {
9770 RouterItem::Packet(pkt) => {
9771 let bytes = wire_format::pack_packet(pkt).len();
9772 self.note_side_rx(src, pkt.data_type(), bytes, true);
9773 }
9774 RouterItem::Packed(bytes) => {
9775 if let Ok(env) = wire_format::peek_envelope(bytes.as_ref()) {
9776 self.note_side_rx(src, env.ty, bytes.len(), true);
9777 }
9778 }
9779 }
9780 match &item.data {
9781 RouterItem::Packet(pkt) => {
9782 if is_reliable_type(pkt.data_type())
9783 && !is_internal_control_type(pkt.data_type())
9784 {
9785 self.note_reliable_return_route(src, pkt.packet_id());
9786 }
9787 }
9788 RouterItem::Packed(bytes) => {
9789 if let Ok(env) = wire_format::peek_envelope(bytes.as_ref())
9790 && is_reliable_type(env.ty)
9791 && !is_internal_control_type(env.ty)
9792 && let Ok(packet_id) = wire_format::packet_id_from_wire(bytes.as_ref())
9793 {
9794 self.note_reliable_return_route(src, packet_id);
9795 }
9796 }
9797 }
9798 }
9799 match &item.data {
9800 RouterItem::Packet(pkt) => {
9801 if !is_internal_control_type(pkt.data_type()) {
9802 self.remember_managed_variable_packet(pkt)?;
9803 }
9804 }
9805 RouterItem::Packed(bytes) => {
9806 if let Ok(env) = wire_format::peek_envelope(bytes.as_ref())
9807 && !is_internal_control_type(env.ty)
9808 && self.is_managed_variable_type(env.ty)
9809 {
9810 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
9811 pkt.validate()?;
9812 self.remember_managed_variable_packet(&pkt)?;
9813 }
9814 }
9815 }
9816 let mut released_buffered: Vec<Arc<[u8]>> = Vec::new();
9817 if let (Some(src), RouterItem::Packed(bytes)) = (item.src, &item.data) {
9818 let (_opts, handler_is_packed, hop_reliable_enabled) = {
9819 let st = self.state.lock();
9820 let side_ref = Self::side_ref(&st, src)?;
9821 let opts = side_ref.opts;
9822 (
9823 opts,
9824 matches!(side_ref.tx_handler, RouterTxHandlerFn::Packed(_)),
9825 opts.reliable_enabled
9826 && self.cfg.reliable_enabled()
9827 && !self.side_has_multiple_announcers_locked(&st, src, self.clock.now_ms()),
9828 )
9829 };
9830
9831 if hop_reliable_enabled && handler_is_packed {
9832 let frame = match wire_format::peek_frame_info(bytes.as_ref()) {
9833 Ok(frame) => frame,
9834 Err(e) => {
9835 if matches!(e, TelemetryError::Unpack(msg) if msg == "crc32 mismatch") {
9836 if let Ok(frame) =
9837 wire_format::peek_frame_info_unchecked(bytes.as_ref())
9838 && is_reliable_type(frame.envelope.ty)
9839 && let Some(hdr) = frame.reliable
9840 {
9841 let unordered =
9842 (hdr.flags & wire_format::RELIABLE_FLAG_UNORDERED) != 0;
9843 let unsequenced =
9844 (hdr.flags & wire_format::RELIABLE_FLAG_UNSEQUENCED) != 0;
9845
9846 if !unsequenced {
9847 let requested = if unordered {
9848 hdr.seq
9849 } else {
9850 let mut st = self.state.lock();
9851 let rx_state = self.reliable_rx_state_mut(
9852 &mut st,
9853 src,
9854 frame.envelope.ty,
9855 );
9856 rx_state.expected_seq.min(hdr.seq)
9857 };
9858 self.queue_reliable_packet_request(
9859 src,
9860 frame.envelope.ty,
9861 requested,
9862 called_from_queue,
9863 )?;
9864 }
9865 }
9866 return Ok(());
9867 }
9868 return Err(e);
9869 }
9870 };
9871 if is_reliable_type(frame.envelope.ty)
9872 && let Some(hdr) = frame.reliable
9873 {
9874 if frame.ack_only() {
9875 self.handle_reliable_ack(src, frame.envelope.ty, hdr.ack);
9876 return Ok(());
9877 }
9878 let unordered = (hdr.flags & wire_format::RELIABLE_FLAG_UNORDERED) != 0;
9879 let unsequenced = (hdr.flags & wire_format::RELIABLE_FLAG_UNSEQUENCED) != 0;
9880
9881 if !unsequenced {
9882 if unordered {
9883 self.queue_reliable_ack(
9884 src,
9885 frame.envelope.ty,
9886 hdr.seq,
9887 called_from_queue,
9888 )?;
9889 } else {
9890 let mut release: Vec<Arc<[u8]>> = Vec::new();
9891 let mut last_delivered = None;
9892 let mut ack_old = None;
9893 let mut request_missing = None;
9894 let mut partial_ack = None;
9895 {
9896 let mut st = self.state.lock();
9897 let rx_state =
9898 self.reliable_rx_state_mut(&mut st, src, frame.envelope.ty);
9899 let expected_seq = rx_state.expected_seq;
9900 if hdr.seq < expected_seq {
9901 ack_old = Some(expected_seq.saturating_sub(1));
9902 } else if hdr.seq > expected_seq {
9903 request_missing = Some(expected_seq);
9904 partial_ack = Some(hdr.seq);
9905 st.buffer_reliable_rx(
9906 src,
9907 frame.envelope.ty,
9908 hdr.seq,
9909 bytes.clone(),
9910 )?;
9911 } else {
9912 release.push(bytes.clone());
9913 last_delivered = Some(hdr.seq);
9914 let mut next_expected = hdr.seq.wrapping_add(1);
9915 while let Some(buf) = rx_state.buffered.remove(&next_expected) {
9916 release.push(buf);
9917 last_delivered = Some(next_expected);
9918 let next = next_expected.wrapping_add(1);
9919 next_expected = if next == 0 { 1 } else { next };
9920 }
9921 rx_state.expected_seq = next_expected;
9922 }
9923 }
9924
9925 if let Some(ack_seq) = ack_old {
9926 self.queue_reliable_ack(
9927 src,
9928 frame.envelope.ty,
9929 ack_seq,
9930 called_from_queue,
9931 )?;
9932 return Ok(());
9933 }
9934 if let Some(request_seq) = request_missing {
9935 if let Some(partial_seq) = partial_ack {
9936 self.queue_reliable_partial_ack(
9937 src,
9938 frame.envelope.ty,
9939 partial_seq,
9940 called_from_queue,
9941 )?;
9942 }
9943 self.queue_reliable_packet_request(
9944 src,
9945 frame.envelope.ty,
9946 request_seq,
9947 called_from_queue,
9948 )?;
9949 return Ok(());
9950 }
9951
9952 if let Some(ack_seq) = last_delivered {
9953 self.queue_reliable_ack(
9954 src,
9955 frame.envelope.ty,
9956 ack_seq,
9957 called_from_queue,
9958 )?;
9959 }
9960
9961 released_buffered.extend(release.into_iter().skip(1));
9962 }
9963 }
9964 }
9965 } else {
9966 match wire_format::peek_frame_info(bytes.as_ref()) {
9967 Ok(frame) => {
9968 if frame.ack_only() {
9969 return Ok(());
9970 }
9971 }
9972 Err(e) => {
9973 if matches!(e, TelemetryError::Unpack(msg) if msg == "crc32 mismatch") {
9974 return Ok(());
9975 }
9976 return Err(e);
9977 }
9978 }
9979 }
9980 }
9981
9982 if self.is_duplicate_pkt(&item.data)? {
9983 if item.src.is_some() {
9984 let local_sender = self.sender_arc();
9985 match &item.data {
9986 RouterItem::Packet(pkt)
9987 if (is_reliable_type(pkt.data_type())
9988 || !pkt.wire_target_senders().is_empty())
9989 && pkt.sender() != local_sender.as_ref()
9990 && self.item_targets_local_sender(&item.data)?
9991 && self.packet_has_local_handler(pkt) =>
9992 {
9993 self.queue_end_to_end_reliable_ack(pkt, called_from_queue)?;
9994 }
9995 RouterItem::Packed(bytes) => {
9996 if let Ok(pkt) = wire_format::unpack_packet(bytes.as_ref())
9997 && (is_reliable_type(pkt.data_type())
9998 || !pkt.wire_target_senders().is_empty())
9999 && pkt.sender() != local_sender.as_ref()
10000 && self.item_targets_local_sender(&item.data)?
10001 && self.packet_has_local_handler(&pkt)
10002 {
10003 let packet_id = wire_format::packet_id_from_wire(bytes.as_ref())
10004 .unwrap_or_else(|_| pkt.packet_id());
10005 self.queue_end_to_end_reliable_ack_for_packet_id(
10006 packet_id,
10007 called_from_queue,
10008 )?;
10009 }
10010 }
10011 _ => {}
10012 }
10013 }
10014 return Ok(());
10015 }
10016
10017 self.dispatch_rx_data(item, called_from_queue)?;
10018
10019 for release_bytes in released_buffered {
10020 let release_data = RouterItem::Packed(release_bytes.clone());
10021 if self.is_duplicate_pkt(&release_data)? {
10022 continue;
10023 }
10024 let release_item = RouterRxItem {
10025 src: item.src,
10026 priority: Self::router_item_priority(&release_data)?,
10027 data: release_data,
10028 };
10029 self.dispatch_rx_data(&release_item, called_from_queue)?;
10030 }
10031
10032 Ok(())
10033 }
10034
10035 fn dispatch_rx_data(
10036 &self,
10037 item: &RouterRxItem,
10038 called_from_queue: bool,
10039 ) -> TelemetryResult<()> {
10040 match &item.data {
10041 RouterItem::Packet(pkt) => {
10042 pkt.validate()?;
10043
10044 if self.handle_internal_reliable_packet(pkt, item.src, called_from_queue)? {
10045 return Ok(());
10046 }
10047
10048 if pkt.data_type() == DataType::P2pMessage {
10049 if self.item_targets_local_sender(&item.data)? {
10050 self.dispatch_p2p_packet(pkt)?;
10051 if item.src.is_some() {
10052 self.queue_end_to_end_reliable_ack(pkt, called_from_queue)?;
10053 }
10054 }
10055 if self.should_route_remote(&item.data, item.src)? {
10056 self.relay_send(
10057 RouterItem::Packet(pkt.to_owned()),
10058 item.src,
10059 called_from_queue,
10060 )?;
10061 }
10062 return Ok(());
10063 }
10064
10065 #[cfg(feature = "timesync")]
10066 if matches!(
10067 pkt.data_type(),
10068 DataType::TimeSyncAnnounce
10069 | DataType::TimeSyncRequest
10070 | DataType::TimeSyncResponse
10071 ) {
10072 self.handle_internal_timesync_packet(pkt, item.src, called_from_queue)?;
10073 return Ok(());
10074 }
10075
10076 if self.learn_discovery_packet(pkt, item.src, called_from_queue)? {
10077 if !discovery_is_hop_local_advertisement(pkt.data_type())
10082 && self.should_route_remote(&item.data, item.src)?
10083 {
10084 self.relay_send(
10085 RouterItem::Packet(pkt.to_owned()),
10086 item.src,
10087 called_from_queue,
10088 )?;
10089 }
10090 return Ok(());
10091 }
10092
10093 let mut eps: Vec<DataEndpoint> = pkt.endpoints().to_vec();
10094 eps.sort_unstable();
10095 eps.dedup();
10096 let had_local_handler = eps.iter().copied().any(|ep| {
10097 self.endpoint_has_packet_handler(ep) || self.endpoint_has_packed_handler(ep)
10098 });
10099
10100 let has_remote = self.should_route_remote(&item.data, item.src)?;
10101 let targets_local = self.item_targets_local_sender(&item.data)?;
10102
10103 let has_packed_local = eps
10104 .iter()
10105 .copied()
10106 .any(|ep| self.endpoint_has_packed_handler(ep));
10107 let bytes_opt = if has_packed_local {
10108 Some(wire_format::pack_packet(pkt))
10109 } else {
10110 None
10111 };
10112
10113 if targets_local {
10114 for dest in eps {
10115 for h in self.cfg.handlers.iter().filter(|h| h.endpoint == dest) {
10116 let result = match (&h.handler, &bytes_opt) {
10117 (EndpointHandlerFn::Packed(_), Some(bytes)) => self
10118 .call_handler_with_retries(
10119 dest,
10120 h,
10121 Some(bytes.as_ref()),
10122 Some(pkt),
10123 None,
10124 called_from_queue,
10125 ),
10126 (EndpointHandlerFn::Packed(_), None) => {
10127 let bytes = wire_format::pack_packet(pkt);
10128 self.call_handler_with_retries(
10129 dest,
10130 h,
10131 Some(bytes.as_ref()),
10132 Some(pkt),
10133 None,
10134 called_from_queue,
10135 )
10136 }
10137 (EndpointHandlerFn::Packet(_), _) => self
10138 .call_handler_with_retries(
10139 dest,
10140 h,
10141 None,
10142 Some(pkt),
10143 None,
10144 called_from_queue,
10145 ),
10146 };
10147 if result.is_err()
10148 && let Some(src) = item.src
10149 {
10150 self.note_side_local_handler_failure(
10151 src,
10152 pkt.data_type(),
10153 runtime_max_handler_retries(),
10154 );
10155 }
10156 }
10157 }
10158 }
10159
10160 if let Some(src) = item.src
10161 && had_local_handler
10162 && targets_local
10163 {
10164 self.note_side_local_delivery(src, pkt.data_type());
10165 }
10166
10167 if item.src.is_some()
10168 && had_local_handler
10169 && targets_local
10170 && (is_reliable_type(pkt.data_type()) || !pkt.wire_target_senders().is_empty())
10171 {
10172 self.queue_end_to_end_reliable_ack(pkt, called_from_queue)?;
10173 }
10174
10175 if has_remote {
10176 let relay_item = RouterItem::Packet(pkt.to_owned());
10177 self.relay_send(relay_item, item.src, called_from_queue)?;
10178 }
10179
10180 Ok(())
10181 }
10182 RouterItem::Packed(bytes) => {
10183 let env = wire_format::peek_envelope(bytes.as_ref())?;
10184
10185 if matches!(
10186 env.ty,
10187 DataType::ReliableAck
10188 | DataType::ReliablePartialAck
10189 | DataType::ReliablePacketRequest
10190 ) {
10191 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
10192 pkt.validate()?;
10193 let _ =
10194 self.handle_internal_reliable_packet(&pkt, item.src, called_from_queue)?;
10195 return Ok(());
10196 }
10197
10198 if env.ty == DataType::P2pMessage {
10199 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
10200 pkt.validate()?;
10201 if self.item_targets_local_sender(&item.data)? {
10202 self.dispatch_p2p_packet(&pkt)?;
10203 if item.src.is_some() {
10204 let packet_id = wire_format::packet_id_from_wire(bytes.as_ref())
10205 .unwrap_or_else(|_| pkt.packet_id());
10206 self.queue_end_to_end_reliable_ack_for_packet_id(
10207 packet_id,
10208 called_from_queue,
10209 )?;
10210 }
10211 }
10212 if self.should_route_remote(&item.data, item.src)? {
10213 self.relay_send(RouterItem::Packet(pkt), item.src, called_from_queue)?;
10214 }
10215 return Ok(());
10216 }
10217
10218 #[cfg(feature = "timesync")]
10219 if matches!(
10220 env.ty,
10221 DataType::TimeSyncAnnounce
10222 | DataType::TimeSyncRequest
10223 | DataType::TimeSyncResponse
10224 ) {
10225 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
10226 pkt.validate()?;
10227 self.handle_internal_timesync_packet(&pkt, item.src, called_from_queue)?;
10228 return Ok(());
10229 }
10230
10231 #[cfg(feature = "discovery")]
10232 if discovery::is_discovery_type(env.ty) {
10233 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
10234 pkt.validate()?;
10235 let _ = self.learn_discovery_packet(&pkt, item.src, called_from_queue)?;
10236 if !discovery_is_hop_local_advertisement(env.ty)
10237 && self.should_route_remote(&item.data, item.src)?
10238 {
10239 self.relay_send(RouterItem::Packet(pkt), item.src, called_from_queue)?;
10240 }
10241 return Ok(());
10242 }
10243
10244 let any_packet_needed = env
10245 .endpoints
10246 .iter()
10247 .copied()
10248 .any(|ep| self.endpoint_has_packet_handler(ep));
10249
10250 let mut pkt_opt = if any_packet_needed {
10251 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
10252 pkt.validate()?;
10253 Some(pkt)
10254 } else {
10255 None
10256 };
10257
10258 let mut eps: Vec<DataEndpoint> = env.endpoints.iter().copied().collect();
10259 eps.sort_unstable();
10260 eps.dedup();
10261 let had_local_handler = eps.iter().copied().any(|ep| {
10262 self.endpoint_has_packet_handler(ep) || self.endpoint_has_packed_handler(ep)
10263 });
10264
10265 let has_remote = self.should_route_remote(&item.data, item.src)?;
10266 let targets_local = self.item_targets_local_sender(&item.data)?;
10267
10268 if targets_local {
10269 for dest in eps {
10270 for h in self.cfg.handlers.iter().filter(|h| h.endpoint == dest) {
10271 let result = match &h.handler {
10272 EndpointHandlerFn::Packed(_) => self.call_handler_with_retries(
10273 dest,
10274 h,
10275 Some(bytes.as_ref()),
10276 pkt_opt.as_ref(),
10277 Some(&env),
10278 called_from_queue,
10279 ),
10280 EndpointHandlerFn::Packet(_) => {
10281 if pkt_opt.is_none() {
10282 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
10283 pkt.validate()?;
10284 pkt_opt = Some(pkt);
10285 }
10286 let pkt_ref = pkt_opt.as_ref().expect("just set");
10287 self.call_handler_with_retries(
10288 dest,
10289 h,
10290 None,
10291 Some(pkt_ref),
10292 Some(&env),
10293 called_from_queue,
10294 )
10295 }
10296 };
10297 if result.is_err()
10298 && let Some(src) = item.src
10299 {
10300 self.note_side_local_handler_failure(
10301 src,
10302 env.ty,
10303 runtime_max_handler_retries(),
10304 );
10305 }
10306 }
10307 }
10308 }
10309
10310 if item.src.is_some()
10311 && had_local_handler
10312 && targets_local
10313 && (is_reliable_type(env.ty) || !env.target_senders.is_empty())
10314 && let Some(pkt) = pkt_opt.as_ref()
10315 {
10316 let packet_id = wire_format::packet_id_from_wire(bytes.as_ref())
10317 .unwrap_or_else(|_| pkt.packet_id());
10318 self.queue_end_to_end_reliable_ack_for_packet_id(packet_id, called_from_queue)?;
10319 }
10320
10321 if has_remote {
10322 let relay_item = match pkt_opt {
10323 Some(ref p) => RouterItem::Packet(p.clone()),
10324 None => RouterItem::Packed(bytes.clone()),
10325 };
10326 self.relay_send(relay_item, item.src, called_from_queue)?;
10327 }
10328
10329 Ok(())
10330 }
10331 }
10332 }
10333
10334 fn dispatch_local_for_item(
10335 &self,
10336 item: &RouterItem,
10337 called_from_queue: bool,
10338 ) -> TelemetryResult<()> {
10339 match item {
10340 RouterItem::Packet(pkt) => {
10341 pkt.validate()?;
10342 if is_internal_control_type(pkt.data_type()) {
10343 return Ok(());
10344 }
10345 self.ensure_e2e_policy_supported_for_type(pkt.data_type())?;
10346 if !self.item_targets_local_sender(item)? {
10347 return Ok(());
10348 }
10349
10350 let mut eps: Vec<DataEndpoint> = pkt.endpoints().to_vec();
10351 eps.sort_unstable();
10352 eps.dedup();
10353
10354 let has_packed_local = eps
10355 .iter()
10356 .copied()
10357 .any(|ep| self.endpoint_has_packed_handler(ep));
10358 let bytes_opt = if has_packed_local {
10359 Some(wire_format::pack_packet(pkt))
10360 } else {
10361 None
10362 };
10363
10364 for dest in eps {
10365 for h in self.cfg.handlers.iter().filter(|h| h.endpoint == dest) {
10366 match (&h.handler, &bytes_opt) {
10367 (EndpointHandlerFn::Packed(_), Some(bytes)) => {
10368 self.call_handler_with_retries(
10369 dest,
10370 h,
10371 Some(bytes.as_ref()),
10372 Some(pkt),
10373 None,
10374 called_from_queue,
10375 )?;
10376 }
10377 (EndpointHandlerFn::Packed(_), None) => {
10378 let bytes = wire_format::pack_packet(pkt);
10379 self.call_handler_with_retries(
10380 dest,
10381 h,
10382 Some(bytes.as_ref()),
10383 Some(pkt),
10384 None,
10385 called_from_queue,
10386 )?;
10387 }
10388 (EndpointHandlerFn::Packet(_), _) => {
10389 self.call_handler_with_retries(
10390 dest,
10391 h,
10392 None,
10393 Some(pkt),
10394 None,
10395 called_from_queue,
10396 )?;
10397 }
10398 }
10399 }
10400 }
10401 }
10402 RouterItem::Packed(bytes) => {
10403 let env = wire_format::peek_envelope(bytes.as_ref())?;
10404 if is_internal_control_type(env.ty) {
10405 return Ok(());
10406 }
10407 self.ensure_e2e_policy_supported_for_type(env.ty)?;
10408 if !self.item_targets_local_sender(item)? {
10409 return Ok(());
10410 }
10411
10412 let any_packet_needed = env
10413 .endpoints
10414 .iter()
10415 .copied()
10416 .any(|ep| self.endpoint_has_packet_handler(ep));
10417
10418 let mut pkt_opt = if any_packet_needed {
10419 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
10420 pkt.validate()?;
10421 Some(pkt)
10422 } else {
10423 None
10424 };
10425
10426 let mut eps: Vec<DataEndpoint> = env.endpoints.iter().copied().collect();
10427 eps.sort_unstable();
10428 eps.dedup();
10429
10430 for dest in eps {
10431 for h in self.cfg.handlers.iter().filter(|h| h.endpoint == dest) {
10432 match &h.handler {
10433 EndpointHandlerFn::Packed(_) => {
10434 self.call_handler_with_retries(
10435 dest,
10436 h,
10437 Some(bytes.as_ref()),
10438 pkt_opt.as_ref(),
10439 Some(&env),
10440 called_from_queue,
10441 )?;
10442 }
10443 EndpointHandlerFn::Packet(_) => {
10444 if pkt_opt.is_none() {
10445 let pkt = wire_format::unpack_packet(bytes.as_ref())?;
10446 pkt.validate()?;
10447 pkt_opt = Some(pkt);
10448 }
10449 let pkt_ref = pkt_opt.as_ref().expect("just set");
10450 self.call_handler_with_retries(
10451 dest,
10452 h,
10453 None,
10454 Some(pkt_ref),
10455 Some(&env),
10456 called_from_queue,
10457 )?;
10458 }
10459 }
10460 }
10461 }
10462 }
10463 }
10464
10465 Ok(())
10466 }
10467
10468 fn tx_item_impl(
10474 &self,
10475 item: RouterTxItem,
10476 ignore_local: bool,
10477 called_from_queue: bool,
10478 ) -> TelemetryResult<()> {
10479 match item {
10480 RouterTxItem::Broadcast(data) => {
10481 self.ensure_e2e_policy_supported_for_type(Self::item_data_type(&data)?)?;
10482 if let RouterItem::Packet(pkt) = &data
10483 && !is_internal_control_type(pkt.data_type())
10484 {
10485 self.remember_managed_variable_packet(pkt)?;
10486 }
10487 #[cfg(feature = "discovery")]
10488 let is_discovery = matches!(&data, RouterItem::Packet(pkt) if discovery::is_discovery_type(pkt.data_type()))
10489 || matches!(&data, RouterItem::Packed(bytes)
10490 if wire_format::peek_envelope(bytes.as_ref())
10491 .map(|env| discovery::is_discovery_type(env.ty))
10492 .unwrap_or(false));
10493 if !ignore_local {
10494 if self.is_duplicate_pkt(&data)? {
10495 return Ok(());
10496 }
10497 #[cfg(feature = "discovery")]
10498 if !is_discovery
10499 && !matches!(&data, RouterItem::Packet(pkt) if is_internal_control_type(pkt.data_type()))
10500 && !matches!(&data, RouterItem::Packed(bytes)
10501 if wire_format::peek_envelope(bytes.as_ref())
10502 .map(|env| is_internal_control_type(env.ty))
10503 .unwrap_or(false))
10504 {
10505 self.dispatch_local_for_item(&data, called_from_queue)?;
10506 }
10507 #[cfg(not(feature = "discovery"))]
10508 if !matches!(&data, RouterItem::Packet(pkt) if is_internal_control_type(pkt.data_type()))
10509 && !matches!(&data, RouterItem::Packed(bytes)
10510 if wire_format::peek_envelope(bytes.as_ref())
10511 .map(|env| is_internal_control_type(env.ty))
10512 .unwrap_or(false))
10513 {
10514 self.dispatch_local_for_item(&data, called_from_queue)?;
10515 }
10516 }
10517
10518 let send_remote = match &data {
10519 RouterItem::Packet(pkt) => {
10520 pkt.validate()?;
10521 self.should_route_remote(&data, None)?
10522 }
10523 RouterItem::Packed(bytes) => {
10524 let _ = wire_format::peek_envelope(bytes.as_ref())?;
10525 self.should_route_remote(&data, None)?
10526 }
10527 };
10528
10529 if !send_remote {
10530 return Ok(());
10531 }
10532 let mut data = data;
10533 let ty = match &data {
10534 RouterItem::Packet(pkt) => pkt.data_type(),
10535 RouterItem::Packed(bytes) => wire_format::peek_envelope(bytes.as_ref())?.ty,
10536 };
10537 if !ignore_local && !is_internal_control_type(ty) {
10538 #[cfg(feature = "discovery")]
10539 {
10540 let pending = {
10541 let st = self.state.lock();
10542 let mut pending =
10543 self.expected_end_to_end_destinations_locked(&st, &data)?;
10544 self.filter_trackable_end_to_end_destinations_locked(
10545 &st,
10546 ty,
10547 &mut pending,
10548 );
10549 pending
10550 };
10551 if !pending.is_empty() {
10552 let mut targets: Vec<u64> = pending.keys().copied().collect();
10553 targets.sort_unstable();
10554 targets.dedup();
10555 data = self.attach_wire_contract_to_item(data, &targets)?;
10556 self.register_end_to_end_reliable_tx(&data)?;
10557 }
10558 }
10559 }
10560 let RemoteSidePlan::Target(sides) = self.remote_side_plan(&data, None)?;
10561 for (idx, side) in sides.iter().copied().enumerate() {
10562 if let Err(e) = self.send_reliable_to_side(side, data.clone(), false) {
10563 if Self::is_side_tx_busy(&e) {
10564 for retry_side in sides[idx..].iter().copied() {
10565 self.tx_queue_item_with_flags(
10566 RouterTxItem::ToSide {
10567 src: None,
10568 dst: retry_side,
10569 data: data.clone(),
10570 },
10571 true,
10572 )?;
10573 }
10574 return Ok(());
10575 }
10576 match &data {
10577 RouterItem::Packet(pkt) => {
10578 let _ = self.handle_callback_error(pkt, None, e, called_from_queue);
10579 }
10580 RouterItem::Packed(bytes) => {
10581 if let Ok(env) = wire_format::peek_envelope(bytes.as_ref()) {
10582 let _ = self.handle_callback_error_from_env(
10583 &env,
10584 None,
10585 e,
10586 called_from_queue,
10587 );
10588 }
10589 }
10590 }
10591 return Err(TelemetryError::HandlerError("tx handler failed"));
10592 }
10593 }
10594 }
10595 RouterTxItem::ToSide { src, dst, data } => {
10596 self.ensure_e2e_policy_supported_for_type(Self::item_data_type(&data)?)?;
10597 if let RouterItem::Packet(pkt) = &data
10598 && !is_internal_control_type(pkt.data_type())
10599 {
10600 self.remember_managed_variable_packet(pkt)?;
10601 }
10602 if !ignore_local {
10603 if self.is_duplicate_pkt(&data)? {
10604 return Ok(());
10605 }
10606 let suppress_local = matches!(&data, RouterItem::Packet(pkt) if is_internal_control_type(pkt.data_type()))
10607 || matches!(&data, RouterItem::Packed(bytes)
10608 if wire_format::peek_envelope(bytes.as_ref())
10609 .map(|env| is_internal_control_type(env.ty))
10610 .unwrap_or(false));
10611 if !suppress_local {
10612 self.dispatch_local_for_item(&data, called_from_queue)?;
10613 }
10614 }
10615 let allowed = {
10616 let mut st = self.state.lock();
10617 let ty = match &data {
10618 RouterItem::Packet(pkt) => Some(pkt.data_type()),
10619 RouterItem::Packed(bytes) => {
10620 Some(wire_format::peek_envelope(bytes.as_ref())?.ty)
10621 }
10622 };
10623 let route_allowed = self.route_allowed_locked(&st, src, ty, dst);
10624 #[cfg(all(feature = "discovery", feature = "timesync"))]
10625 let timesync_allowed = ty
10626 .map(|ty| {
10627 Self::timesync_allowed_for_side_locked(
10628 &mut st,
10629 dst,
10630 ty,
10631 self.clock.now_ms(),
10632 )
10633 })
10634 .unwrap_or(true);
10635 #[cfg(not(all(feature = "discovery", feature = "timesync")))]
10636 let timesync_allowed = true;
10637 route_allowed && timesync_allowed
10638 };
10639 if !allowed {
10640 return Ok(());
10641 }
10642 if let Err(e) = self.send_reliable_to_side(dst, data.clone(), src.is_some()) {
10643 if Self::is_side_tx_busy(&e) {
10644 self.tx_queue_item_with_flags(
10645 RouterTxItem::ToSide { src, dst, data },
10646 true,
10647 )?;
10648 return Ok(());
10649 }
10650 match &data {
10651 RouterItem::Packet(pkt) => {
10652 let _ = self.handle_callback_error(pkt, None, e, called_from_queue);
10653 }
10654 RouterItem::Packed(bytes) => {
10655 if let Ok(env) = wire_format::peek_envelope(bytes.as_ref()) {
10656 let _ = self.handle_callback_error_from_env(
10657 &env,
10658 None,
10659 e,
10660 called_from_queue,
10661 );
10662 }
10663 }
10664 }
10665 return Err(TelemetryError::HandlerError("tx handler failed"));
10666 }
10667 }
10668 RouterTxItem::EndToEndReplay { packet_id } => {
10669 let Some((data, mut sides)) = self.end_to_end_retransmit_sides(packet_id) else {
10670 return Ok(());
10671 };
10672 if sides.is_empty() {
10673 let RemoteSidePlan::Target(fallback_sides) =
10674 self.remote_side_plan(&data, None)?;
10675 sides = fallback_sides;
10676 }
10677 for (idx, side) in sides.iter().copied().enumerate() {
10678 if let Err(e) = self.send_reliable_to_side(side, data.clone(), false) {
10679 if Self::is_side_tx_busy(&e) {
10680 for retry_side in sides[idx..].iter().copied() {
10681 self.tx_queue_item_with_flags(
10682 RouterTxItem::ToSide {
10683 src: None,
10684 dst: retry_side,
10685 data: data.clone(),
10686 },
10687 true,
10688 )?;
10689 }
10690 return Ok(());
10691 }
10692 match &data {
10693 RouterItem::Packet(pkt) => {
10694 let _ = self.handle_callback_error(pkt, None, e, called_from_queue);
10695 }
10696 RouterItem::Packed(bytes) => {
10697 if let Ok(env) = wire_format::peek_envelope(bytes.as_ref()) {
10698 let _ = self.handle_callback_error_from_env(
10699 &env,
10700 None,
10701 e,
10702 called_from_queue,
10703 );
10704 }
10705 }
10706 }
10707 return Err(TelemetryError::HandlerError("tx handler failed"));
10708 }
10709 }
10710 }
10711 RouterTxItem::ReliableReplay { dst, bytes } => {
10712 let frame = wire_format::peek_frame_info(bytes.as_ref())?;
10713 let ty = frame.envelope.ty;
10714 let Some(hdr) = frame.reliable else {
10715 return Ok(());
10716 };
10717 {
10718 let mut st = self.state.lock();
10719 let tx_state = self.reliable_tx_state_mut(&mut st, dst, ty);
10720 if !tx_state.sent.contains_key(&hdr.seq) {
10721 return Ok(());
10722 }
10723 }
10724 if let Err(e) = self.send_reliable_raw_to_side(dst, bytes.clone(), false) {
10725 if Self::is_side_tx_busy(&e) {
10726 self.tx_queue_item_with_flags(
10727 RouterTxItem::ReliableReplay { dst, bytes },
10728 true,
10729 )?;
10730 return Ok(());
10731 }
10732 return Err(e);
10733 }
10734 let mut st = self.state.lock();
10735 let tx_state = self.reliable_tx_state_mut(&mut st, dst, ty);
10736 if let Some(sent) = tx_state.sent.get_mut(&hdr.seq) {
10737 sent.last_send_ms = self.clock.now_ms();
10738 sent.queued = false;
10739 }
10740 }
10741 }
10742
10743 Ok(())
10744 }
10745
10746 #[inline]
10748 fn tx_item(&self, item: RouterTxItem) -> TelemetryResult<()> {
10749 self.tx_item_impl(item, false, false)
10750 }
10751
10752 #[inline]
10759 pub fn rx_packed(&self, bytes: &[u8]) -> TelemetryResult<()> {
10760 if self.side_tx_active() {
10761 return self.rx_packed_queue(bytes);
10762 }
10763 let data = RouterItem::Packed(Arc::from(bytes));
10764 let item = RouterRxItem {
10765 src: None,
10766 priority: Self::router_item_priority(&data)?,
10767 data,
10768 };
10769 self.rx_item(&item, false)
10770 }
10771
10772 #[inline]
10777 pub fn rx(&self, pkt: &Packet) -> TelemetryResult<()> {
10778 if self.side_tx_active() {
10779 return self.rx_queue(pkt.clone());
10780 }
10781 let data = RouterItem::Packet(pkt.clone());
10782 let item = RouterRxItem {
10783 src: None,
10784 priority: Self::router_item_priority(&data)?,
10785 data,
10786 };
10787 self.rx_item(&item, false)
10788 }
10789
10790 #[inline]
10795 pub fn rx_from_side(&self, pkt: &Packet, side: RouterSideId) -> TelemetryResult<()> {
10796 if self.side_tx_active() {
10797 return self.rx_queue_from_side(pkt.clone(), side);
10798 }
10799 self.ensure_side_ingress_enabled(side)?;
10800 let data = RouterItem::Packet(pkt.clone());
10801 let item = RouterRxItem {
10802 src: Some(side),
10803 priority: Self::router_item_priority(&data)?,
10804 data,
10805 };
10806 self.rx_item(&item, false)
10807 }
10808
10809 #[inline]
10814 pub fn rx_packed_from_side(&self, bytes: &[u8], side: RouterSideId) -> TelemetryResult<()> {
10815 if self.side_tx_active() {
10816 return self.rx_packed_queue_from_side(bytes, side);
10817 }
10818 self.ensure_side_ingress_enabled(side)?;
10819 let Some(decoded) = self.decode_side_transport_frame(side, bytes)? else {
10820 return Ok(());
10821 };
10822 let data = RouterItem::Packed(decoded);
10823 let item = RouterRxItem {
10824 src: Some(side),
10825 priority: Self::router_item_priority(&data)?,
10826 data,
10827 };
10828 self.rx_item(&item, false)
10829 }
10830
10831 #[inline]
10838 pub fn tx(&self, pkt: Packet) -> TelemetryResult<()> {
10839 #[cfg(feature = "discovery")]
10840 let _ = self.poll_discovery()?;
10841 if self.side_tx_active() {
10842 return self.tx_queue_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)));
10843 }
10844 self.tx_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)))
10845 }
10846
10847 #[inline]
10852 pub fn tx_packed(&self, pkt: Arc<[u8]>) -> TelemetryResult<()> {
10853 #[cfg(feature = "discovery")]
10854 let _ = self.poll_discovery()?;
10855 if self.side_tx_active() {
10856 return self.tx_queue_item(RouterTxItem::Broadcast(RouterItem::Packed(pkt)));
10857 }
10858 self.tx_item(RouterTxItem::Broadcast(RouterItem::Packed(pkt)))
10859 }
10860
10861 #[inline]
10865 pub fn tx_queue(&self, pkt: Packet) -> TelemetryResult<()> {
10866 #[cfg(feature = "discovery")]
10867 let _ = self.poll_discovery()?;
10868 self.tx_queue_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)))
10869 }
10870
10871 #[inline]
10873 pub fn tx_packed_queue(&self, data: Arc<[u8]>) -> TelemetryResult<()> {
10874 #[cfg(feature = "discovery")]
10875 let _ = self.poll_discovery()?;
10876 self.tx_queue_item(RouterTxItem::Broadcast(RouterItem::Packed(data)))
10877 }
10878
10879 #[inline]
10886 pub fn log<T: LeBytes>(&self, ty: DataType, data: &[T]) -> TelemetryResult<()> {
10887 #[cfg(feature = "discovery")]
10888 let _ = self.poll_discovery()?;
10889 if self.side_tx_active() {
10890 return self.log_queue(ty, data);
10891 }
10892 let sender = self.sender_arc();
10893 log_raw(
10894 sender.as_ref(),
10895 ty,
10896 data,
10897 self.packet_timestamp_ms(),
10898 |pkt| self.tx_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt))),
10899 )
10900 }
10901
10902 #[inline]
10904 pub fn log_queue<T: LeBytes>(&self, ty: DataType, data: &[T]) -> TelemetryResult<()> {
10905 #[cfg(feature = "discovery")]
10906 let _ = self.poll_discovery()?;
10907 let sender = self.sender_arc();
10908 log_raw(
10909 sender.as_ref(),
10910 ty,
10911 data,
10912 self.packet_timestamp_ms(),
10913 |pkt| self.tx_queue_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt))),
10914 )
10915 }
10916
10917 #[inline]
10919 pub fn log_ts<T: LeBytes>(
10920 &self,
10921 ty: DataType,
10922 timestamp: u64,
10923 data: &[T],
10924 ) -> TelemetryResult<()> {
10925 #[cfg(feature = "discovery")]
10926 let _ = self.poll_discovery()?;
10927 if self.side_tx_active() {
10928 return self.log_queue_ts(ty, timestamp, data);
10929 }
10930 let sender = self.sender_arc();
10931 log_raw(sender.as_ref(), ty, data, timestamp, |pkt| {
10932 self.tx_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)))
10933 })
10934 }
10935
10936 #[inline]
10938 pub fn log_queue_ts<T: LeBytes>(
10939 &self,
10940 ty: DataType,
10941 timestamp: u64,
10942 data: &[T],
10943 ) -> TelemetryResult<()> {
10944 #[cfg(feature = "discovery")]
10945 let _ = self.poll_discovery()?;
10946 let sender = self.sender_arc();
10947 log_raw(sender.as_ref(), ty, data, timestamp, |pkt| {
10948 self.tx_queue_item(RouterTxItem::Broadcast(RouterItem::Packet(pkt)))
10949 })
10950 }
10951}