Skip to main content

sedsnet/
routing_config.rs

1//! Configuration shared by every routing role.
2
3use crate::DataType;
4#[cfg(feature = "discovery")]
5use crate::discovery;
6use crate::router::{
7    CompactTimestampOmissionPolicy, DEFAULT_SIDE_TRANSPORT_TEMPLATE_LIMIT,
8    IPV4_LIKE_COMPACT_HEADER_TARGET_BYTES, IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES,
9    SideTransportProfile,
10};
11
12#[derive(Clone, Debug)]
13pub struct SideOptions {
14    /// Enables the router's per-link reliable transport layer on this side.
15    ///
16    /// When `true` and the side uses a packed TX handler, reliable schema types gain
17    /// sequence numbers, ACKs, packet requests, and retransmits on this specific hop.
18    /// When `false`, the router strips the reliable framing for that side and sends only the
19    /// application packet payload once.
20    ///
21    /// This setting only affects the hop between this router and the side's TX callback. It does
22    /// not change whether a schema `DataType` is defined as reliable, and it does not disable the
23    /// router's end-to-end reliable tracking for packets originated elsewhere in the network.
24    pub reliable_enabled: bool,
25    /// Marks the side as eligible for link-local-only endpoints and discovery routes.
26    pub link_local_enabled: bool,
27    /// Enables a side-local header-template dictionary for packed transport.
28    ///
29    /// The first frame for a stable header shape is sent in full. Later frames
30    /// on the same side can replace the repeated static header bytes with a
31    /// compact template hash plus only the fields that still vary packet to
32    /// packet.
33    pub header_template_enabled: bool,
34    /// Maximum number of bytes to emit per packed TX callback.
35    ///
36    /// When non-zero and a wrapped packed frame would exceed this size, the
37    /// router splits it into ordered chunks and reassembles those chunks on RX
38    /// before normal packet processing.
39    pub max_frame_bytes: usize,
40    /// Target total side-transport overhead for compact follow-up frames.
41    ///
42    /// This is a profiling/negotiation target rather than a hard limit. The
43    /// canonical packet is still reconstructed before normal router handling,
44    /// so constrained links should watch runtime stats to confirm compact
45    /// frames are meeting their IPv4/IPv6-like overhead budget.
46    pub compact_header_target_bytes: usize,
47    /// Maximum side-local header templates retained for TX and RX dictionaries.
48    ///
49    /// This keeps compact-link state bounded. When the dictionary is full, the
50    /// oldest deterministic entry is evicted and a later packet with that
51    /// shape will refresh the receiver with a full template frame.
52    pub max_side_transport_templates: usize,
53    /// Omits the timestamp field from compact follow-up frames when it is unchanged.
54    ///
55    /// The receiver reconstructs the canonical packet from the previous timestamp for that
56    /// side-local template. This is only used after a full or compact frame has established
57    /// timestamp context.
58    pub omit_unchanged_compact_timestamps: bool,
59    /// Optional per-data-type timestamp omission policy for compact follow-up frames.
60    ///
61    /// This allows a side to omit unchanged timestamps only for selected traffic while keeping
62    /// absolute/delta timestamps for other data types on the same link.
63    pub compact_timestamp_omission_types: CompactTimestampOmissionPolicy,
64    /// Declared compact-link profile for stats and future negotiation.
65    pub side_transport_profile: SideTransportProfile,
66    /// Allows packets received from this side to enter router processing.
67    pub ingress_enabled: bool,
68    /// Allows the router to transmit packets toward this side.
69    pub egress_enabled: bool,
70}
71
72impl Default for SideOptions {
73    fn default() -> Self {
74        Self {
75            reliable_enabled: false,
76            link_local_enabled: false,
77            header_template_enabled: false,
78            max_frame_bytes: 0,
79            compact_header_target_bytes: 0,
80            max_side_transport_templates: DEFAULT_SIDE_TRANSPORT_TEMPLATE_LIMIT,
81            omit_unchanged_compact_timestamps: false,
82            compact_timestamp_omission_types: CompactTimestampOmissionPolicy::none(),
83            side_transport_profile: SideTransportProfile::Canonical,
84            ingress_enabled: true,
85            egress_enabled: true,
86        }
87    }
88}
89
90impl SideOptions {
91    /// Convenience preset for compact packed-side transport.
92    ///
93    /// This enables header-template reuse and, when `max_frame_bytes > 0`,
94    /// router-managed chunking/reassembly for fixed-size transports.
95    #[inline]
96    pub fn with_small_packet_transport(mut self, max_frame_bytes: usize) -> Self {
97        self.header_template_enabled = true;
98        self.max_frame_bytes = max_frame_bytes;
99        self.compact_header_target_bytes = IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES;
100        self.side_transport_profile = SideTransportProfile::Ipv6Like;
101        self
102    }
103
104    #[inline]
105    pub fn with_ipv4_like_compact_header_target(mut self) -> Self {
106        self.header_template_enabled = true;
107        self.compact_header_target_bytes = IPV4_LIKE_COMPACT_HEADER_TARGET_BYTES;
108        self.omit_unchanged_compact_timestamps = true;
109        self.side_transport_profile = SideTransportProfile::Ipv4Like;
110        self
111    }
112
113    #[inline]
114    pub fn with_ipv6_like_compact_header_target(mut self) -> Self {
115        self.header_template_enabled = true;
116        self.compact_header_target_bytes = IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES;
117        self.side_transport_profile = SideTransportProfile::Ipv6Like;
118        self
119    }
120
121    #[inline]
122    pub fn with_template_transport(mut self) -> Self {
123        self.header_template_enabled = true;
124        self.side_transport_profile = SideTransportProfile::Template;
125        self
126    }
127
128    #[inline]
129    pub fn with_omitted_unchanged_compact_timestamps(mut self) -> Self {
130        self.header_template_enabled = true;
131        self.omit_unchanged_compact_timestamps = true;
132        self
133    }
134
135    #[inline]
136    pub fn with_omitted_unchanged_compact_timestamps_for_type(mut self, ty: DataType) -> Self {
137        self.header_template_enabled = true;
138        self.compact_timestamp_omission_types.insert(ty);
139        self
140    }
141
142    #[inline]
143    pub fn effective_transport_profile(&self) -> SideTransportProfile {
144        if !self.header_template_enabled && self.max_frame_bytes == 0 {
145            SideTransportProfile::Canonical
146        } else if self.side_transport_profile == SideTransportProfile::Canonical {
147            SideTransportProfile::Template
148        } else {
149            self.side_transport_profile
150        }
151    }
152
153    #[cfg(feature = "discovery")]
154    #[inline]
155    pub fn link_capabilities(&self) -> discovery::LinkCapabilities {
156        let mut flags = discovery::LINK_CAPABILITY_END_TO_END_RELIABILITY;
157        if self.header_template_enabled {
158            flags |= discovery::LINK_CAPABILITY_HEADER_TEMPLATES;
159        }
160        if self.max_frame_bytes != 0 {
161            flags |= discovery::LINK_CAPABILITY_CHUNKING;
162        }
163        if self.reliable_enabled {
164            flags |= discovery::LINK_CAPABILITY_RELIABILITY;
165        }
166        if self.omit_unchanged_compact_timestamps
167            || !self.compact_timestamp_omission_types.is_empty()
168        {
169            flags |= discovery::LINK_CAPABILITY_OMIT_UNCHANGED_TIMESTAMPS;
170        }
171        #[cfg(feature = "cryptography")]
172        {
173            flags |= discovery::LINK_CAPABILITY_CRYPTO;
174        }
175        #[cfg(feature = "compression")]
176        {
177            flags |= discovery::LINK_CAPABILITY_PAYLOAD_COMPRESSION;
178        }
179        discovery::LinkCapabilities {
180            version: 1,
181            flags,
182            profile: self.effective_transport_profile().discovery_code(),
183            max_frame_bytes: self.max_frame_bytes.min(u32::MAX as usize) as u32,
184            compact_header_target_bytes: self.compact_header_target_bytes.min(u32::MAX as usize)
185                as u32,
186            max_side_transport_templates: self.max_side_transport_templates.min(u32::MAX as usize)
187                as u32,
188        }
189    }
190}
191
192/// Immutable internal presets for the shared engine. Public compatibility
193/// facades choose a preset; forwarding can never grant application ownership.
194#[derive(Clone, Copy, Debug, PartialEq, Eq)]
195pub(crate) enum RoutingRole {
196    Router,
197    Relay,
198}
199impl RoutingRole {
200    pub(crate) fn local_services(self) -> bool {
201        self == Self::Router
202    }
203}