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