1use super::*;
2
3impl TransportEngine {
4 pub fn lowest_interface_bitrate(&self) -> Option<u64> {
9 super::path_requests::lowest_interface_bitrate(&self.interfaces)
10 }
11
12 pub fn medium_path_timeout(&self) -> f64 {
18 super::path_requests::medium_path_timeout(&self.interfaces)
19 }
20
21 pub fn path_table_entries(&self) -> impl Iterator<Item = (&[u8; 16], &PathEntry)> {
22 self.path_table
23 .iter()
24 .filter_map(|(k, ps)| ps.primary().map(|e| (k, e)))
25 }
26
27 pub fn path_table_sets(&self) -> impl Iterator<Item = (&[u8; 16], &PathSet)> {
28 self.path_table.iter()
29 }
30
31 pub fn interface_count(&self) -> usize {
32 self.interfaces.len()
33 }
34
35 pub fn link_table_count(&self) -> usize {
36 self.link_table.len()
37 }
38
39 pub fn active_link_count(&self) -> usize {
40 self.link_table
41 .values()
42 .filter(|entry| entry.validated)
43 .count()
44 }
45
46 pub fn is_unvalidated_link_packet(&self, packet: &crate::packet::RawPacket) -> bool {
47 packet.flags.packet_type != crate::constants::PACKET_TYPE_ANNOUNCE
48 && packet.flags.packet_type != crate::constants::PACKET_TYPE_LINKREQUEST
49 && packet.context != crate::constants::CONTEXT_LRPROOF
50 && self
51 .link_table
52 .get(&packet.destination_hash)
53 .is_some_and(|entry| !entry.validated)
54 }
55
56 pub fn is_packet_filter_protocol_violation(
58 &self,
59 packet: &crate::packet::RawPacket,
60 interface: InterfaceId,
61 ) -> bool {
62 let mut hops = packet.hops.saturating_add(1);
63 if self.interface_is_local_client(interface) {
64 hops = hops.saturating_sub(1);
65 }
66 if packet.flags.packet_type == crate::constants::PACKET_TYPE_ANNOUNCE {
67 return packet.flags.destination_type != crate::constants::DESTINATION_SINGLE;
68 }
69 (packet.flags.destination_type == crate::constants::DESTINATION_PLAIN
70 || packet.flags.destination_type == crate::constants::DESTINATION_GROUP)
71 && hops > 1
72 }
73
74 pub fn path_table_count(&self) -> usize {
75 self.path_table.len()
76 }
77
78 pub fn announce_table_count(&self) -> usize {
79 self.announce_table.len()
80 }
81
82 pub fn reverse_table_count(&self) -> usize {
83 self.reverse_table.len()
84 }
85
86 pub fn held_announces_count(&self) -> usize {
87 self.held_announces.len()
88 }
89
90 pub fn packet_hashlist_len(&self) -> usize {
91 self.packet_hashlist.len()
92 }
93
94 #[doc(hidden)]
100 pub fn forget_packet_hash(&mut self, packet_hash: &[u8; 32]) -> bool {
101 self.packet_hashlist.remove(packet_hash)
102 }
103
104 pub fn announce_sig_cache_len(&self) -> usize {
105 self.announce_sig_cache.len()
106 }
107
108 pub fn rate_limiter_count(&self) -> usize {
109 self.rate_limiter.len()
110 }
111
112 pub fn blackholed_count(&self) -> usize {
113 self.blackholed_identities.len()
114 }
115
116 pub fn tunnel_count(&self) -> usize {
117 self.tunnel_table.len()
118 }
119
120 pub fn discovery_pr_tags_count(&self) -> usize {
121 self.discovery_pr_tags.len()
122 }
123
124 #[cfg(test)]
125 pub(crate) fn has_discovery_pr_tag(&self, unique_tag: &[u8; 32]) -> bool {
126 self.discovery_pr_tag_set.contains(unique_tag)
127 }
128
129 pub fn discovery_path_requests_count(&self) -> usize {
130 self.discovery_path_requests.len()
131 }
132
133 pub fn announce_queue_count(&self) -> usize {
134 self.announce_queues.queue_count()
135 }
136
137 pub fn nonempty_announce_queue_count(&self) -> usize {
138 self.announce_queues.nonempty_queue_count()
139 }
140
141 pub fn queued_announce_count(&self) -> usize {
142 self.announce_queues.total_queued_announces()
143 }
144
145 pub fn queued_announce_bytes(&self) -> usize {
146 self.announce_queues.total_queued_bytes()
147 }
148
149 pub fn announce_queue_interface_cap_drop_count(&self) -> u64 {
150 self.announce_queues.interface_cap_drop_count()
151 }
152
153 pub fn local_destinations_count(&self) -> usize {
154 self.local_destinations.len()
155 }
156
157 pub fn rate_limiter(&self) -> &AnnounceRateLimiter {
158 &self.rate_limiter
159 }
160
161 pub fn interface_info(&self, id: &InterfaceId) -> Option<&InterfaceInfo> {
162 self.interfaces.get(id)
163 }
164
165 pub fn redirect_path(&mut self, dest_hash: &[u8; 16], interface: InterfaceId, now: f64) {
166 if let Some(entry) = self
167 .path_table
168 .get_mut(dest_hash)
169 .and_then(|ps| ps.primary_mut())
170 {
171 entry.receiving_interface = interface;
172 entry.next_hop = *dest_hash;
176 entry.hops = 1;
177 entry.timestamp = now;
178 entry.expires = now + 3600.0;
179 } else {
180 self.upsert_path_destination(
181 *dest_hash,
182 PathEntry {
183 timestamp: now,
184 next_hop: *dest_hash,
185 hops: 1,
186 expires: now + 3600.0,
187 random_blobs: Vec::new(),
188 receiving_interface: interface,
189 packet_hash: [0u8; 32],
190 announce_raw: None,
191 },
192 now,
193 );
194 }
195 }
196
197 pub fn inject_path(&mut self, dest_hash: [u8; 16], entry: PathEntry) {
198 self.upsert_path_destination(dest_hash, entry.clone(), entry.timestamp);
199 }
200
201 pub fn drop_path(&mut self, dest_hash: &[u8; 16]) -> bool {
202 self.path_table.remove(dest_hash).is_some()
203 }
204
205 pub fn drop_all_via(&mut self, transport_hash: &[u8; 16]) -> usize {
206 let mut removed = 0usize;
207 for ps in self.path_table.values_mut() {
208 let before = ps.len();
209 ps.retain(|entry| &entry.next_hop != transport_hash);
210 removed += before - ps.len();
211 }
212 self.path_table.retain(|_, ps| !ps.is_empty());
213 removed
214 }
215
216 pub fn drop_paths_for_interface(&mut self, interface: InterfaceId) -> usize {
217 let mut removed = 0usize;
218 let mut cleared_destinations = Vec::new();
219 for (dest_hash, ps) in self.path_table.iter_mut() {
220 let before = ps.len();
221 ps.retain(|entry| entry.receiving_interface != interface);
222 if ps.is_empty() {
223 cleared_destinations.push(*dest_hash);
224 }
225 removed += before - ps.len();
226 }
227 self.path_table.retain(|_, ps| !ps.is_empty());
228 for dest_hash in cleared_destinations {
229 self.path_states.remove(&dest_hash);
230 }
231 removed
232 }
233
234 pub fn drop_reverse_for_interface(&mut self, interface: InterfaceId) -> usize {
235 let before = self.reverse_table.len();
236 self.reverse_table.retain(|_, entry| {
237 entry.receiving_interface != interface && entry.outbound_interface != interface
238 });
239 before - self.reverse_table.len()
240 }
241
242 pub fn drop_links_for_interface(&mut self, interface: InterfaceId) -> usize {
243 let before = self.link_table.len();
244 self.link_table.retain(|_, entry| {
245 entry.next_hop_interface != interface && entry.received_interface != interface
246 });
247 before - self.link_table.len()
248 }
249
250 pub fn drop_announce_queues(&mut self) {
251 self.announce_table.clear();
252 self.held_announces.clear();
253 self.announce_queues = AnnounceQueues::new(self.config.announce_queue_max_interfaces);
254 self.ingress_control.clear();
255 }
256
257 pub fn void_queues(&mut self) {
258 self.drop_announce_queues();
259 self.reverse_table.clear();
260 }
261
262 pub fn identity_hash(&self) -> Option<&[u8; 16]> {
263 self.config.identity_hash.as_ref()
264 }
265
266 pub fn transport_enabled(&self) -> bool {
267 self.config.transport_enabled
268 }
269
270 pub fn config(&self) -> &TransportConfig {
271 &self.config
272 }
273
274 pub fn set_packet_hashlist_max_entries(&mut self, max_entries: usize) {
275 self.config.packet_hashlist_max_entries = max_entries;
276 self.packet_hashlist =
277 PacketHashlist::with_allocation(max_entries, self.config.packet_hashlist_allocation);
278 }
279
280 pub fn get_path_table(&self, max_hops: Option<u8>) -> Vec<PathTableRow> {
281 let mut result = Vec::new();
282 for (dest_hash, ps) in self.path_table.iter() {
283 if let Some(entry) = ps.primary() {
284 if let Some(max) = max_hops {
285 if entry.hops > max {
286 continue;
287 }
288 }
289 let iface_name = self
290 .interfaces
291 .get(&entry.receiving_interface)
292 .map(|i| i.name.clone())
293 .unwrap_or_else(|| {
294 alloc::format!("Interface({})", entry.receiving_interface.0)
295 });
296 result.push((
297 *dest_hash,
298 entry.timestamp,
299 entry.next_hop,
300 entry.hops,
301 entry.expires,
302 iface_name,
303 ));
304 }
305 }
306 result
307 }
308
309 pub fn get_rate_table(&self) -> Vec<RateTableRow> {
310 self.rate_limiter
311 .entries()
312 .map(|(hash, entry)| {
313 (
314 *hash,
315 entry.last,
316 entry.rate_violations,
317 entry.blocked_until,
318 entry.timestamps.clone(),
319 )
320 })
321 .collect()
322 }
323
324 pub fn get_blackholed(&self) -> Vec<([u8; 16], f64, f64, Option<alloc::string::String>)> {
325 self.blackholed_entries()
326 .map(|(hash, entry)| (*hash, entry.created, entry.expires, entry.reason.clone()))
327 .collect()
328 }
329
330 pub fn active_destination_hashes(&self) -> alloc::collections::BTreeSet<[u8; 16]> {
331 self.path_table.keys().copied().collect()
332 }
333
334 pub fn path_destination_cap_evict_count(&self) -> usize {
335 self.path_destination_cap_evict_count
336 }
337
338 pub fn active_packet_hashes(&self) -> Vec<[u8; 32]> {
339 let mut hashes: Vec<[u8; 32]> = self
340 .path_table
341 .values()
342 .flat_map(|ps| ps.iter().map(|p| p.packet_hash))
343 .collect();
344
345 hashes.extend(
346 self.tunnel_table
347 .iter()
348 .flat_map(|(_, tunnel)| tunnel.paths.values().map(|p| p.packet_hash)),
349 );
350 hashes.sort_unstable();
351 hashes.dedup();
352 hashes
353 }
354
355 pub fn cull_rate_limiter(
356 &mut self,
357 active: &alloc::collections::BTreeSet<[u8; 16]>,
358 now: f64,
359 ttl_secs: f64,
360 ) -> usize {
361 self.rate_limiter.cull_stale(active, now, ttl_secs)
362 }
363
364 pub fn update_interface_freq(&mut self, id: InterfaceId, ia_freq: f64) {
365 if let Some(info) = self.interfaces.get_mut(&id) {
366 info.ia_freq = ia_freq;
367 }
368 }
369
370 pub fn update_interface_freqs(
371 &mut self,
372 id: InterfaceId,
373 ia_freq: f64,
374 ip_freq: f64,
375 op_freq: f64,
376 op_samples: usize,
377 ) {
378 if let Some(info) = self.interfaces.get_mut(&id) {
379 info.ia_freq = ia_freq;
380 info.ip_freq = ip_freq;
381 info.op_freq = op_freq;
382 info.op_samples = op_samples;
383 }
384 }
385
386 pub fn held_announce_count(&self, interface: &InterfaceId) -> usize {
387 self.ingress_control.held_count(interface)
388 }
389
390 pub fn burst_active(&self, interface: &InterfaceId) -> bool {
391 self.ingress_control.burst_active(interface)
392 }
393
394 pub fn burst_activated(&self, interface: &InterfaceId) -> f64 {
395 self.ingress_control.burst_activated(interface)
396 }
397
398 pub fn pr_burst_active(&self, interface: &InterfaceId) -> bool {
399 self.ingress_control.pr_burst_active(interface)
400 }
401
402 pub fn pr_burst_activated(&self, interface: &InterfaceId) -> f64 {
403 self.ingress_control.pr_burst_activated(interface)
404 }
405
406 #[cfg(test)]
407 #[allow(dead_code)]
408 pub(crate) fn path_table(&self) -> &BTreeMap<[u8; 16], PathSet> {
409 &self.path_table
410 }
411
412 #[cfg(test)]
413 #[allow(dead_code)]
414 pub(crate) fn announce_table(&self) -> &BTreeMap<[u8; 16], AnnounceEntry> {
415 &self.announce_table
416 }
417
418 #[cfg(test)]
419 #[allow(dead_code)]
420 pub(crate) fn held_announces(&self) -> &BTreeMap<[u8; 16], AnnounceEntry> {
421 &self.held_announces
422 }
423
424 #[cfg(test)]
425 #[allow(dead_code)]
426 pub(crate) fn announce_retained_bytes(&self) -> usize {
427 self.announce_retained_bytes_total()
428 }
429
430 #[cfg(test)]
431 #[allow(dead_code)]
432 pub(crate) fn reverse_table(&self) -> &BTreeMap<[u8; 16], tables::ReverseEntry> {
433 &self.reverse_table
434 }
435}