1use super::*;
2
3fn traffic_detail(stats: &crate::interface::InterfaceStats) -> TrafficDetail {
4 TrafficDetail {
5 rxs: stats.traffic_rates.rxs,
6 txs: stats.traffic_rates.txs,
7 arxb: stats.arxb,
8 atxb: stats.atxb,
9 arxc: stats.arxc,
10 atxc: stats.atxc,
11 arxs: stats.traffic_rates.arxs,
12 atxs: stats.traffic_rates.atxs,
13 prxb: stats.prxb,
14 ptxb: stats.ptxb,
15 prxc: stats.prxc,
16 ptxc: stats.ptxc,
17 prxs: stats.traffic_rates.prxs,
18 ptxs: stats.traffic_rates.ptxs,
19 arxf: stats.incoming_announce_freq(),
20 atxf: stats.outgoing_announce_freq(),
21 prxf: stats.incoming_path_request_freq(),
22 ptxf: stats.outgoing_path_request_freq(),
23 }
24}
25
26fn add_traffic(total: &mut TrafficDetail, detail: TrafficDetail) {
27 total.rxs += detail.rxs;
28 total.txs += detail.txs;
29 total.arxb += detail.arxb;
30 total.atxb += detail.atxb;
31 total.arxc += detail.arxc;
32 total.atxc += detail.atxc;
33 total.arxs += detail.arxs;
34 total.atxs += detail.atxs;
35 total.prxb += detail.prxb;
36 total.ptxb += detail.ptxb;
37 total.prxc += detail.prxc;
38 total.ptxc += detail.ptxc;
39 total.prxs += detail.prxs;
40 total.ptxs += detail.ptxs;
41 total.arxf += detail.arxf;
42 total.atxf += detail.atxf;
43 total.prxf += detail.prxf;
44 total.ptxf += detail.ptxf;
45}
46
47fn hex_bytes(bytes: &[u8]) -> String {
48 bytes.iter().map(|byte| format!("{byte:02x}")).collect()
49}
50
51impl Driver {
52 pub(crate) fn wants_destination_type(&mut self, full_name: &str, requester: &[u8]) -> bool {
55 use rns_core::transport::destination_filter::destination_type;
56 let registered = self
57 .engine
58 .destination_filter_mut()
59 .want(destination_type(full_name), requester);
60 if registered {
61 log::debug!(
62 "Registered <{full_name}> destinations requirement for <{}>",
63 hex_bytes(requester)
64 );
65 }
66 registered
67 }
68
69 pub(crate) fn unwants_destination_type(&mut self, full_name: &str, requester: &[u8]) -> bool {
72 use rns_core::transport::destination_filter::destination_type;
73 let destination_type = destination_type(full_name);
74 let filter = self.engine.destination_filter_mut();
75 let was_registered = filter.unwant(destination_type, requester);
76 if was_registered {
77 log::debug!(
78 "Deregistered <{full_name}> destinations requirement for <{}>",
79 hex_bytes(requester)
80 );
81 if !filter.is_wanted(&destination_type) {
82 log::debug!(
83 "No remaining requesters for <{full_name}> destinations, type deregistered"
84 );
85 }
86 }
87 was_registered
88 }
89
90 pub(super) fn dynamic_burst_counts(&self, parent_id: InterfaceId) -> (usize, usize) {
91 self.dynamic_interface_parents
92 .iter()
93 .filter(|(_, candidate_parent)| **candidate_parent == parent_id)
94 .fold((0, 0), |(announce_count, path_request_count), (id, _)| {
95 (
96 announce_count + usize::from(self.engine.burst_active(id)),
97 path_request_count + usize::from(self.engine.pr_burst_active(id)),
98 )
99 })
100 }
101
102 #[cfg(feature = "iface-backbone")]
104 pub fn backbone_burst_counts(&self, parent_id: InterfaceId) -> Option<(usize, usize)> {
105 self.backbone_peer_state
106 .values()
107 .any(|handle| handle.interface_id == parent_id)
108 .then(|| self.dynamic_burst_counts(parent_id))
109 }
110
111 pub(crate) fn handle_interface_stats_query(&self) -> QueryResponse {
112 QueryResponse::InterfaceStats(self.interface_stats())
113 }
114
115 pub(crate) fn interface_stats(&self) -> InterfaceStatsResponse {
116 let now = time::now();
117 let mut interfaces = Vec::new();
118 let mut total_rxb: u64 = 0;
119 let mut total_txb: u64 = 0;
120 let mut total_rx_packets: u64 = 0;
121 let mut total_tx_packets: u64 = 0;
122 let mut total_announce_rx: u64 = 0;
123 let mut total_announce_tx: u64 = 0;
124 let mut total_path_request_rx: u64 = 0;
125 let mut total_path_request_tx: u64 = 0;
126 let mut rx_pps = 0.0;
127 let mut tx_pps = 0.0;
128 let mut total_traffic = TrafficDetail::default();
129 for entry in self.interfaces.values() {
130 let traffic = traffic_detail(&entry.stats);
131 if !entry.info.is_local_client {
132 total_rxb += entry.stats.rxb;
133 total_txb += entry.stats.txb;
134 total_rx_packets += entry.stats.rx_packets;
135 total_tx_packets += entry.stats.tx_packets;
136 total_announce_rx += entry.stats.arxc;
137 total_announce_tx += entry.stats.atxc;
138 total_path_request_rx += entry.stats.prxc;
139 total_path_request_tx += entry.stats.ptxc;
140 rx_pps += entry.stats.traffic_rates.rxpps;
141 tx_pps += entry.stats.traffic_rates.txpps;
142 add_traffic(&mut total_traffic, traffic);
143 }
144 let interface_id = entry.info.id;
145 interfaces.push(SingleInterfaceStat {
146 id: interface_id.0,
147 name: entry.info.name.clone(),
148 status: entry.online && entry.enabled,
149 mode: entry.info.mode,
150 gravity: entry.info.gravity,
151 announces_to_internal: entry.info.announces_to_internal,
152 rxb: entry.stats.rxb,
153 txb: entry.stats.txb,
154 tx_drops: entry
155 .async_writer_metrics
156 .as_ref()
157 .map(crate::interface::AsyncWriterMetrics::tx_drops)
158 .unwrap_or(0),
159 tx_dropped_bytes: entry
160 .async_writer_metrics
161 .as_ref()
162 .map(crate::interface::AsyncWriterMetrics::tx_dropped_bytes)
163 .unwrap_or(0),
164 tx_stalled: entry
165 .async_writer_metrics
166 .as_ref()
167 .is_some_and(crate::interface::AsyncWriterMetrics::tx_stalled),
168 tx_buffered: entry
169 .async_writer_metrics
170 .as_ref()
171 .map(crate::interface::AsyncWriterMetrics::tx_buffered)
172 .unwrap_or(0),
173 traffic,
174 protocol_violations: entry.stats.protocol_violations,
175 ifac_violations: entry.stats.ifac_violations,
176 packet_filter_hits: entry.stats.packet_filter_hits,
177 hop_limiter_hits: entry.stats.hop_limiter_hits,
178 stamped_path_requests: entry.stats.stamped_path_requests,
179 rx_packets: entry.stats.rx_packets,
180 tx_packets: entry.stats.tx_packets,
181 cpu_load: entry.stats.cpu_load,
182 mem_load: entry.stats.mem_load,
183 switch_id: entry.stats.switch_id,
184 endpoint_id: entry.stats.endpoint_id,
185 via_switch_id: entry.stats.via_switch_id,
186 peers: entry.stats.peers,
187 rssi: entry.stats.rssi,
188 snr: entry.stats.snr,
189 signal_quality: entry.stats.signal_quality,
190 frequency: entry.stats.frequency,
191 bandwidth: entry.stats.bandwidth,
192 txpower: entry.stats.txpower,
193 spreading_factor: entry.stats.spreading_factor,
194 coding_rate: entry.stats.coding_rate,
195 channel: entry.stats.channel,
196 modulation: entry.stats.modulation.clone(),
197 bitrate: entry.info.bitrate,
198 mtu: Some(entry.info.mtu),
199 ifac_size: entry.ifac.as_ref().map(|s| s.size),
200 started: entry.stats.started,
201 ia_freq: entry.stats.incoming_announce_freq(),
202 oa_freq: entry.stats.outgoing_announce_freq(),
203 ip_freq: entry.stats.incoming_path_request_freq(),
204 op_freq: entry.stats.outgoing_path_request_freq(),
205 op_samples: entry.stats.outgoing_path_request_samples(),
206 burst_active: self.engine.burst_active(&interface_id),
207 burst_activated: self.engine.burst_activated(&interface_id),
208 pr_burst_active: self.engine.pr_burst_active(&interface_id),
209 pr_burst_activated: self.engine.pr_burst_activated(&interface_id),
210 clients: None,
211 blocked_ips: None,
212 blocked_ip_list: None,
213 announce_rate_target: entry.info.announce_rate_target,
214 announce_rate_grace: entry.info.announce_rate_grace,
215 announce_rate_penalty: entry.info.announce_rate_penalty,
216 interface_type: entry.interface_type.clone(),
217 });
218 }
219 #[cfg(feature = "iface-backbone")]
220 for handle in self.backbone_peer_state.values() {
221 let clients = recover_mutex_guard(&handle.peer_state, "backbone peer state")
222 .list(&handle.interface_name)
223 .into_iter()
224 .map(|entry| entry.connected_count as u64)
225 .sum();
226 let blocked_ip_list =
227 recover_mutex_guard(&handle.fast_flap_state, "backbone fast-flap state")
228 .blocked_ip_list(&handle.fast_flap, std::time::Instant::now())
229 .into_iter()
230 .map(|peer_ip| peer_ip.to_string())
231 .collect::<Vec<_>>();
232 let blocked_ips = blocked_ip_list.len() as u64;
233 let mut traffic = TrafficDetail::default();
234 let mut protocol_violations = 0;
235 let mut ifac_violations = 0;
236 let mut packet_filter_hits = 0;
237 let mut hop_limiter_hits = 0;
238 let mut stamped_path_requests = 0;
239 let mut tx_drops = 0;
240 let mut tx_dropped_bytes = 0;
241 let mut tx_stalled = false;
242 let mut tx_buffered = 0;
243 for (child_id, parent_id) in &self.dynamic_interface_parents {
244 if *parent_id == handle.interface_id {
245 if let Some(child) = self.interfaces.get(child_id) {
246 add_traffic(&mut traffic, traffic_detail(&child.stats));
247 protocol_violations += child.stats.protocol_violations;
248 ifac_violations += child.stats.ifac_violations;
249 packet_filter_hits += child.stats.packet_filter_hits;
250 hop_limiter_hits += child.stats.hop_limiter_hits;
251 stamped_path_requests += child.stats.stamped_path_requests;
252 if let Some(metrics) = &child.async_writer_metrics {
253 tx_drops += metrics.tx_drops();
254 tx_dropped_bytes += metrics.tx_dropped_bytes();
255 tx_stalled |= metrics.tx_stalled();
256 tx_buffered += metrics.tx_buffered();
257 }
258 }
259 }
260 }
261 interfaces.push(SingleInterfaceStat {
262 id: handle.interface_id.0,
263 name: handle.interface_name.clone(),
264 status: true,
265 mode: handle.mode,
266 gravity: handle.gravity,
267 announces_to_internal: handle.announces_to_internal,
268 rxb: 0,
269 txb: 0,
270 tx_drops,
271 tx_dropped_bytes,
272 tx_stalled,
273 tx_buffered,
274 traffic,
275 protocol_violations,
276 ifac_violations,
277 packet_filter_hits,
278 hop_limiter_hits,
279 stamped_path_requests,
280 rx_packets: 0,
281 tx_packets: 0,
282 cpu_load: None,
283 mem_load: None,
284 switch_id: None,
285 endpoint_id: None,
286 via_switch_id: None,
287 peers: None,
288 rssi: None,
289 snr: None,
290 signal_quality: None,
291 frequency: None,
292 bandwidth: None,
293 txpower: None,
294 spreading_factor: None,
295 coding_rate: None,
296 channel: None,
297 modulation: None,
298 bitrate: Some(crate::interface::backbone::SERVER_BITRATE_GUESS),
299 mtu: Some(crate::interface::backbone::HW_MTU as u32),
300 ifac_size: None,
301 started: self.started,
302 ia_freq: 0.0,
303 oa_freq: 0.0,
304 ip_freq: 0.0,
305 op_freq: 0.0,
306 op_samples: 0,
307 burst_active: false,
308 burst_activated: 0.0,
309 pr_burst_active: false,
310 pr_burst_activated: 0.0,
311 clients: Some(clients),
312 blocked_ips: Some(blocked_ips),
313 blocked_ip_list: Some(blocked_ip_list),
314 announce_rate_target: None,
315 announce_rate_grace: 0,
316 announce_rate_penalty: 0.0,
317 interface_type: "BackboneInterface".into(),
318 });
319 }
320 interfaces.sort_by(|a, b| a.name.cmp(&b.name));
321 let (path_pool_total, path_pool_unused) = self.engine.path_pool_counts();
322 let total_links = self.engine.link_table_count() + self.link_manager.link_count();
323 let active_links = self.engine.active_link_count() + self.link_manager.active_link_count();
324 InterfaceStatsResponse {
325 interfaces,
326 transport_id: self.engine.identity_hash().copied(),
327 transport_enabled: self.engine.transport_enabled(),
328 transport_uptime: now - self.started,
329 total_rxb,
330 total_txb,
331 total_rx_packets,
332 total_tx_packets,
333 total_announce_rx,
334 total_announce_tx,
335 total_path_request_rx,
336 total_path_request_tx,
337 total_links,
338 active_links,
339 pending_links: total_links.saturating_sub(active_links),
340 path_pool_total,
341 path_pool_unused,
342 path_pool_active: path_pool_total.saturating_sub(path_pool_unused),
343 rx_pps,
344 tx_pps,
345 traffic: total_traffic,
346 probe_responder: self.probe_responder_hash,
347 #[cfg(feature = "iface-backbone")]
348 backbone_peer_pool: self.backbone_peer_pool_status(),
349 #[cfg(not(feature = "iface-backbone"))]
350 backbone_peer_pool: None,
351 }
352 }
353
354 pub(crate) fn link_info_entries(&self) -> Vec<crate::event::LinkInfoEntry> {
356 let counts = self.event_tx.link_send_pool().snapshot();
357 let mut links = self.link_manager.link_entries();
358 for link in &mut links {
359 if let Some(counts) = counts.get(&link.link_id) {
360 link.pending_send_packets = counts.pending;
361 link.waiting_send_packets = counts.waiting;
362 }
363 }
364 links
365 }
366
367 pub(crate) fn publish_state_snapshot(&mut self) {
370 let links = self.link_info_entries();
371 let interfaces = self.interface_stats();
372 let sequence = self.state_snapshot_schedule.published(links.len());
373 self.event_tx
374 .state_snapshot()
375 .store(crate::state_snapshot::StateSnapshot {
376 sequence,
377 published_at: time::now(),
378 links,
379 interfaces,
380 });
381 }
382
383 pub(crate) fn handle_path_table_query(&self, max_hops: Option<u8>) -> QueryResponse {
384 let entries: Vec<PathTableEntry> = self
385 .engine
386 .path_table_entries()
387 .filter(|(_, entry)| max_hops.is_none_or(|max| entry.hops <= max))
388 .map(|(hash, entry)| {
389 let iface_name = self
390 .interfaces
391 .get(&entry.receiving_interface)
392 .map(|e| e.info.name.clone())
393 .or_else(|| {
394 self.engine
395 .interface_info(&entry.receiving_interface)
396 .map(|i| i.name.clone())
397 })
398 .unwrap_or_default();
399 let known = self.known_destinations.get(hash);
400 PathTableEntry {
401 hash: *hash,
402 timestamp: entry.timestamp,
403 via: entry.next_hop,
404 hops: entry.hops,
405 expires: entry.expires,
406 used: entry.used,
407 interface: entry.receiving_interface,
408 interface_name: iface_name,
409 stamp_value: known.map(|known| known.stamp_value),
410 lr_cost: known.and_then(|known| known.lr_cost),
411 }
412 })
413 .collect();
414 QueryResponse::PathTable(entries)
415 }
416
417 pub(crate) fn handle_runtime_config_query(
418 &self,
419 request: QueryRequest,
420 ) -> Option<QueryResponse> {
421 match request {
422 QueryRequest::ListRuntimeConfig => {
423 Some(QueryResponse::RuntimeConfigList(self.list_runtime_config()))
424 }
425 QueryRequest::GetRuntimeConfig { key } => Some(QueryResponse::RuntimeConfigEntry(
426 self.runtime_config_entry(&key),
427 )),
428 QueryRequest::BackbonePeerState { interface_name } => {
429 Some(QueryResponse::BackbonePeerState(
430 self.list_backbone_peer_state(interface_name.as_deref()),
431 ))
432 }
433 QueryRequest::SetRuntimeConfig { .. } => {
434 Some(QueryResponse::RuntimeConfigSet(Err(RuntimeConfigError {
435 code: RuntimeConfigErrorCode::Unsupported,
436 message: "mutating runtime config is handled separately".to_string(),
437 })))
438 }
439 QueryRequest::ResetRuntimeConfig { .. } => {
440 Some(QueryResponse::RuntimeConfigReset(Err(RuntimeConfigError {
441 code: RuntimeConfigErrorCode::Unsupported,
442 message: "mutating runtime config is handled separately".to_string(),
443 })))
444 }
445 QueryRequest::ClearBackbonePeerState { .. } => {
446 Some(QueryResponse::ClearBackbonePeerState(false))
447 }
448 QueryRequest::BlacklistBackbonePeer { .. } => {
449 Some(QueryResponse::BlacklistBackbonePeer(false))
450 }
451 _ => None,
452 }
453 }
454
455 pub(crate) fn handle_mutation_query(&mut self, request: QueryRequest) -> Option<QueryResponse> {
456 match request {
457 QueryRequest::BlackholeIdentity {
458 identity_hash,
459 duration_hours,
460 reason,
461 } => {
462 let now = time::now();
463 self.engine
464 .blackhole_identity(identity_hash, now, duration_hours, reason);
465 Some(QueryResponse::BlackholeResult(true))
466 }
467 QueryRequest::UnblackholeIdentity { identity_hash } => Some(
468 QueryResponse::UnblackholeResult(self.engine.unblackhole_identity(&identity_hash)),
469 ),
470 QueryRequest::DropPath { dest_hash } => {
471 Some(QueryResponse::DropPath(self.engine.drop_path(&dest_hash)))
472 }
473 QueryRequest::DropAllVia { transport_hash } => Some(QueryResponse::DropAllVia(
474 self.engine.drop_all_via(&transport_hash),
475 )),
476 QueryRequest::DropAnnounceQueues => {
477 self.engine.drop_announce_queues();
478 Some(QueryResponse::DropAnnounceQueues)
479 }
480 QueryRequest::ClearBackbonePeerState {
481 interface_name,
482 peer_ip,
483 } => Some(QueryResponse::ClearBackbonePeerState(
484 self.clear_backbone_peer_state(&interface_name, peer_ip),
485 )),
486 QueryRequest::BlacklistBackbonePeer {
487 interface_name,
488 peer_ip,
489 duration,
490 reason,
491 penalty_level,
492 } => Some(QueryResponse::BlacklistBackbonePeer(
493 self.blacklist_backbone_peer(
494 &interface_name,
495 peer_ip,
496 duration,
497 reason,
498 penalty_level,
499 ),
500 )),
501 QueryRequest::InjectPath {
502 dest_hash,
503 next_hop,
504 hops,
505 expires,
506 interface_name,
507 packet_hash,
508 } => {
509 let iface_id = self
510 .interfaces
511 .iter()
512 .find(|(_, entry)| entry.info.name == interface_name)
513 .map(|(id, _)| *id);
514 Some(match iface_id {
515 Some(id) => {
516 let entry = PathEntry {
517 timestamp: time::now(),
518 next_hop,
519 hops,
520 expires,
521 random_blobs: Vec::new(),
522 receiving_interface: id,
523 packet_hash,
524 used: 0.0,
525 announce_raw: None,
526 };
527 self.engine.inject_path(dest_hash, entry);
528 QueryResponse::InjectPath(true)
529 }
530 None => QueryResponse::InjectPath(false),
531 })
532 }
533 QueryRequest::InjectIdentity {
534 dest_hash,
535 identity_hash,
536 public_key,
537 app_data,
538 hops,
539 received_at,
540 } => {
541 self.upsert_known_destination(
542 dest_hash,
543 crate::destination::AnnouncedIdentity {
544 dest_hash: rns_core::types::DestHash(dest_hash),
545 identity_hash: rns_core::types::IdentityHash(identity_hash),
546 public_key,
547 app_data,
548 hops,
549 received_at,
550 receiving_interface: rns_core::transport::types::InterfaceId(0),
551 rssi: None,
552 snr: None,
553 },
554 );
555 Some(QueryResponse::InjectIdentity(true))
556 }
557 QueryRequest::RestoreKnownDestination(entry) => {
558 self.known_destinations.insert(
559 entry.dest_hash,
560 KnownDestinationState {
561 announced: crate::destination::AnnouncedIdentity {
562 dest_hash: rns_core::types::DestHash(entry.dest_hash),
563 identity_hash: rns_core::types::IdentityHash(entry.identity_hash),
564 public_key: entry.public_key,
565 app_data: entry.app_data,
566 hops: entry.hops,
567 received_at: entry.received_at,
568 receiving_interface: entry.receiving_interface,
569 rssi: None,
570 snr: None,
571 },
572 was_used: entry.was_used,
573 last_used_at: entry.last_used_at,
574 retained: entry.retained,
575 stamp: entry.stamp,
576 stamp_value: entry.stamp_value,
577 lr_cost: entry.lr_cost,
578 },
579 );
580 Some(QueryResponse::RestoreKnownDestination(true))
581 }
582 QueryRequest::RetainKnownDestination { dest_hash } => Some(
583 QueryResponse::RetainKnownDestination(self.retain_known_destination(&dest_hash)),
584 ),
585 QueryRequest::RetainIdentity { identity_hash } => Some(QueryResponse::RetainIdentity(
586 self.retain_identity(&identity_hash),
587 )),
588 QueryRequest::UnretainKnownDestination { dest_hash } => {
589 Some(QueryResponse::UnretainKnownDestination(
590 self.unretain_known_destination(&dest_hash),
591 ))
592 }
593 QueryRequest::MarkKnownDestinationUsed { dest_hash } => {
594 Some(QueryResponse::MarkKnownDestinationUsed(
595 self.mark_known_destination_used(&dest_hash),
596 ))
597 }
598 _ => None,
599 }
600 }
601
602 pub(crate) fn runtime_config_query_fallback(request: &QueryRequest) -> QueryResponse {
603 match request {
604 QueryRequest::ListRuntimeConfig => QueryResponse::RuntimeConfigList(Vec::new()),
605 QueryRequest::GetRuntimeConfig { .. } => QueryResponse::RuntimeConfigEntry(None),
606 QueryRequest::BackbonePeerState { .. } => QueryResponse::BackbonePeerState(Vec::new()),
607 QueryRequest::SetRuntimeConfig { key, .. } => {
608 QueryResponse::RuntimeConfigSet(Err(RuntimeConfigError {
609 code: RuntimeConfigErrorCode::ApplyFailed,
610 message: format!(
611 "internal error: no response generated for runtime-config set '{}'",
612 key
613 ),
614 }))
615 }
616 QueryRequest::ResetRuntimeConfig { key } => {
617 QueryResponse::RuntimeConfigReset(Err(RuntimeConfigError {
618 code: RuntimeConfigErrorCode::ApplyFailed,
619 message: format!(
620 "internal error: no response generated for runtime-config reset '{}'",
621 key
622 ),
623 }))
624 }
625 QueryRequest::ClearBackbonePeerState { .. } => {
626 QueryResponse::ClearBackbonePeerState(false)
627 }
628 QueryRequest::BlacklistBackbonePeer { .. } => {
629 QueryResponse::BlacklistBackbonePeer(false)
630 }
631 _ => QueryResponse::RuntimeConfigEntry(None),
632 }
633 }
634
635 pub(crate) fn mutation_query_fallback(request: &QueryRequest) -> QueryResponse {
636 match request {
637 QueryRequest::BlackholeIdentity { .. } => QueryResponse::BlackholeResult(false),
638 QueryRequest::UnblackholeIdentity { .. } => QueryResponse::UnblackholeResult(false),
639 QueryRequest::DropPath { .. } => QueryResponse::DropPath(false),
640 QueryRequest::DropAllVia { .. } => QueryResponse::DropAllVia(0),
641 QueryRequest::DropAnnounceQueues => QueryResponse::DropAnnounceQueues,
642 QueryRequest::ClearBackbonePeerState { .. } => {
643 QueryResponse::ClearBackbonePeerState(false)
644 }
645 QueryRequest::BlacklistBackbonePeer { .. } => {
646 QueryResponse::BlacklistBackbonePeer(false)
647 }
648 QueryRequest::InjectPath { .. } => QueryResponse::InjectPath(false),
649 QueryRequest::InjectIdentity { .. } => QueryResponse::InjectIdentity(false),
650 QueryRequest::RestoreKnownDestination(..) => {
651 QueryResponse::RestoreKnownDestination(false)
652 }
653 QueryRequest::RetainKnownDestination { .. } => {
654 QueryResponse::RetainKnownDestination(false)
655 }
656 QueryRequest::RetainIdentity { .. } => QueryResponse::RetainIdentity(false),
657 QueryRequest::UnretainKnownDestination { .. } => {
658 QueryResponse::UnretainKnownDestination(false)
659 }
660 QueryRequest::MarkKnownDestinationUsed { .. } => {
661 QueryResponse::MarkKnownDestinationUsed(false)
662 }
663 _ => QueryResponse::InjectIdentity(false),
664 }
665 }
666
667 pub(crate) fn handle_query(&self, request: QueryRequest) -> QueryResponse {
669 match request {
670 QueryRequest::ManageInterface { .. } => QueryResponse::InterfaceManagement(Some(false)),
671 QueryRequest::InterfaceStats => self.handle_interface_stats_query(),
672 QueryRequest::BackboneInterfaces => {
673 QueryResponse::BackboneInterfaces(self.list_backbone_interfaces())
674 }
675 QueryRequest::ProviderBridgeStats => {
676 #[cfg(feature = "hooks")]
677 {
678 QueryResponse::ProviderBridgeStats(
679 self.provider_bridge.as_ref().map(|bridge| bridge.stats()),
680 )
681 }
682 #[cfg(not(feature = "hooks"))]
683 {
684 QueryResponse::ProviderBridgeStats(None::<crate::event::ProviderBridgeStats>)
685 }
686 }
687 QueryRequest::DrainStatus => QueryResponse::DrainStatus(self.drain_status()),
688 QueryRequest::PathTable { max_hops } => self.handle_path_table_query(max_hops),
689 QueryRequest::RateTable => {
690 let entries: Vec<RateTableEntry> = self
691 .engine
692 .rate_limiter()
693 .entries()
694 .map(|(hash, entry)| RateTableEntry {
695 hash: *hash,
696 last: entry.last,
697 rate_violations: entry.rate_violations,
698 blocked_until: entry.blocked_until,
699 timestamps: entry.timestamps.clone(),
700 })
701 .collect();
702 QueryResponse::RateTable(entries)
703 }
704 QueryRequest::LowestInterfaceBitrate => {
705 QueryResponse::LowestInterfaceBitrate(self.engine.lowest_interface_bitrate())
706 }
707 QueryRequest::MediumPathTimeout => {
708 QueryResponse::MediumPathTimeout(self.engine.medium_path_timeout())
709 }
710 QueryRequest::FirstHopTimeout { dest_hash } => {
711 let bitrate = self
712 .engine
713 .next_hop_interface(&dest_hash)
714 .and_then(|id| self.interfaces.get(&id))
715 .and_then(|entry| entry.info.bitrate)
716 .filter(|bitrate| *bitrate > 0);
717 let timeout = rns_core::constants::LINK_ESTABLISHMENT_TIMEOUT_PER_HOP
718 + bitrate
719 .map(|bitrate| rns_core::constants::MTU as f64 * 8.0 / bitrate as f64)
720 .unwrap_or(0.0);
721 QueryResponse::FirstHopTimeout(timeout)
722 }
723 QueryRequest::NextHop { dest_hash } => {
724 let resp = self
725 .engine
726 .next_hop(&dest_hash)
727 .map(|next_hop| NextHopResponse {
728 next_hop,
729 hops: self.engine.hops_to(&dest_hash).unwrap_or(0),
730 interface: self
731 .engine
732 .next_hop_interface(&dest_hash)
733 .unwrap_or(InterfaceId(0)),
734 });
735 QueryResponse::NextHop(resp)
736 }
737 QueryRequest::NextHopIfName { dest_hash } => {
738 let name = self
739 .engine
740 .next_hop_interface(&dest_hash)
741 .and_then(|id| self.interfaces.get(&id))
742 .map(|entry| entry.info.name.clone());
743 QueryResponse::NextHopIfName(name)
744 }
745 QueryRequest::LinkCount => QueryResponse::LinkCount(
746 self.engine.link_table_count() + self.link_manager.link_count(),
747 ),
748 QueryRequest::ActiveLinkCount => QueryResponse::ActiveLinkCount(
749 self.engine.active_link_count() + self.link_manager.active_link_count(),
750 ),
751 QueryRequest::LinkDistribution => QueryResponse::LinkDistribution(
752 self.engine
753 .link_distribution()
754 .into_iter()
755 .map(
756 |(destination_hash, total, active)| crate::event::LinkDistributionEntry {
757 destination_hash,
758 total,
759 active,
760 },
761 )
762 .collect(),
763 ),
764 QueryRequest::DropPath { .. } => {
765 QueryResponse::DropPath(false)
767 }
768 QueryRequest::DropAllVia { .. } => QueryResponse::DropAllVia(0),
769 QueryRequest::DropAnnounceQueues => QueryResponse::DropAnnounceQueues,
770 QueryRequest::WantsDestinationType { .. }
771 | QueryRequest::UnwantsDestinationType { .. }
772 | QueryRequest::UnwantsAllDestinationTypes { .. }
773 | QueryRequest::SetRequiredDestinationsOnly { .. } => {
774 QueryResponse::DestinationTypeRegistration(false)
776 }
777 QueryRequest::TransportIdentity => {
778 QueryResponse::TransportIdentity(self.engine.identity_hash().copied())
779 }
780 QueryRequest::TransportStateSnapshot => {
781 QueryResponse::TransportStateSnapshot(self.engine.persistence_snapshot())
782 }
783 QueryRequest::GetBlackholed => {
784 let now = time::now();
785 let entries: Vec<BlackholeInfo> = self
786 .engine
787 .blackholed_entries()
788 .filter(|(_, e)| e.expires == 0.0 || e.expires > now)
789 .map(|(hash, entry)| BlackholeInfo {
790 identity_hash: *hash,
791 created: entry.created,
792 expires: entry.expires,
793 reason: entry.reason.clone(),
794 })
795 .collect();
796 QueryResponse::Blackholed(entries)
797 }
798 QueryRequest::BlackholeIdentity { .. } | QueryRequest::UnblackholeIdentity { .. } => {
799 QueryResponse::BlackholeResult(false)
801 }
802 QueryRequest::InjectPath { .. } => {
803 QueryResponse::InjectPath(false)
805 }
806 QueryRequest::InjectIdentity { .. } => {
807 QueryResponse::InjectIdentity(false)
809 }
810 QueryRequest::RestoreKnownDestination(..) => {
811 QueryResponse::RestoreKnownDestination(false)
812 }
813 QueryRequest::RetainKnownDestination { .. } => {
814 QueryResponse::RetainKnownDestination(false)
815 }
816 QueryRequest::RetainIdentity { .. } => QueryResponse::RetainIdentity(false),
817 QueryRequest::UnretainKnownDestination { .. } => {
818 QueryResponse::UnretainKnownDestination(false)
819 }
820 QueryRequest::MarkKnownDestinationUsed { .. } => {
821 QueryResponse::MarkKnownDestinationUsed(false)
822 }
823 QueryRequest::HasPath { dest_hash } => {
824 QueryResponse::HasPath(self.engine.has_path(&dest_hash))
825 }
826 QueryRequest::HopsTo { dest_hash } => {
827 QueryResponse::HopsTo(self.engine.hops_to(&dest_hash))
828 }
829 QueryRequest::RecallIdentity { .. } => QueryResponse::RecallIdentity(None),
830 QueryRequest::RecallDestinationStamp { .. } => {
831 QueryResponse::RecallDestinationStamp(None)
832 }
833 QueryRequest::KnownDestinations => {
834 QueryResponse::KnownDestinations(self.known_destination_entries())
835 }
836 QueryRequest::LocalDestinations => {
837 let entries: Vec<LocalDestinationEntry> = self
838 .local_destinations
839 .iter()
840 .map(|(hash, dest_type)| LocalDestinationEntry {
841 hash: *hash,
842 dest_type: *dest_type,
843 })
844 .collect();
845 QueryResponse::LocalDestinations(entries)
846 }
847 QueryRequest::Links => QueryResponse::Links(self.link_info_entries()),
848 QueryRequest::Resources => {
849 QueryResponse::Resources(self.link_manager.resource_entries())
850 }
851 QueryRequest::DiscoveredInterfaces {
852 only_available,
853 only_transport,
854 } => {
855 let mut interfaces = self.discovered_interfaces.list().unwrap_or_default();
856 crate::discovery::filter_and_sort_interfaces(
857 &mut interfaces,
858 only_available,
859 only_transport,
860 );
861 QueryResponse::DiscoveredInterfaces(interfaces)
862 }
863 request @ (QueryRequest::ListRuntimeConfig
864 | QueryRequest::GetRuntimeConfig { .. }
865 | QueryRequest::BackbonePeerState { .. }
866 | QueryRequest::SetRuntimeConfig { .. }
867 | QueryRequest::ResetRuntimeConfig { .. }
868 | QueryRequest::ClearBackbonePeerState { .. }
869 | QueryRequest::BlacklistBackbonePeer { .. }) => {
870 let fallback = Self::runtime_config_query_fallback(&request);
871 self.handle_runtime_config_query(request)
872 .unwrap_or_else(|| {
873 log::error!(
874 "runtime-config query branch unexpectedly returned no response"
875 );
876 fallback
877 })
878 }
879 QueryRequest::SendProbe { .. } => {
881 QueryResponse::SendProbe(Err(crate::event::SendProbeError::PackFailed))
882 }
883 QueryRequest::CheckProof { .. } => QueryResponse::CheckProof(None),
884 }
885 }
886
887 pub(crate) fn handle_query_mut(&mut self, request: QueryRequest) -> QueryResponse {
889 match request {
890 QueryRequest::WantsDestinationType {
891 full_name,
892 requester,
893 } => QueryResponse::DestinationTypeRegistration(
894 self.wants_destination_type(&full_name, &requester),
895 ),
896 QueryRequest::UnwantsDestinationType {
897 full_name,
898 requester,
899 } => QueryResponse::DestinationTypeRegistration(
900 self.unwants_destination_type(&full_name, &requester),
901 ),
902 QueryRequest::UnwantsAllDestinationTypes { requester } => {
903 self.engine.destination_filter_mut().unwant_all(&requester);
904 log::debug!(
905 "Deregistered all destination requirements for <{}>",
906 hex_bytes(&requester)
907 );
908 QueryResponse::DestinationTypeRegistration(true)
909 }
910 QueryRequest::SetRequiredDestinationsOnly { enabled } => {
911 self.engine
912 .destination_filter_mut()
913 .set_required_only(enabled);
914 if enabled {
915 log::debug!("Setting announce filtering to required only");
916 } else {
917 log::debug!("Setting announce filtering to all");
918 }
919 QueryResponse::DestinationTypeRegistration(true)
920 }
921 QueryRequest::ManageInterface { operation, name } => {
922 QueryResponse::InterfaceManagement(self.manage_interface(operation, &name))
923 }
924 request @ (QueryRequest::BlackholeIdentity { .. }
925 | QueryRequest::UnblackholeIdentity { .. }
926 | QueryRequest::DropPath { .. }
927 | QueryRequest::DropAllVia { .. }
928 | QueryRequest::DropAnnounceQueues
929 | QueryRequest::ClearBackbonePeerState { .. }
930 | QueryRequest::BlacklistBackbonePeer { .. }
931 | QueryRequest::InjectPath { .. }
932 | QueryRequest::InjectIdentity { .. }
933 | QueryRequest::RestoreKnownDestination(..)
934 | QueryRequest::RetainKnownDestination { .. }
935 | QueryRequest::RetainIdentity { .. }
936 | QueryRequest::UnretainKnownDestination { .. }
937 | QueryRequest::MarkKnownDestinationUsed { .. }) => {
938 let fallback = Self::mutation_query_fallback(&request);
939 self.handle_mutation_query(request).unwrap_or_else(|| {
940 log::error!("mutation query branch unexpectedly returned no response");
941 fallback
942 })
943 }
944 QueryRequest::RecallDestinationStamp { dest_hash } => {
945 QueryResponse::RecallDestinationStamp(self.known_destinations.get(&dest_hash).map(
946 |state| crate::event::DestinationStampInfo {
947 stamp_value: state.stamp_value,
948 lr_cost: state.lr_cost,
949 },
950 ))
951 }
952 QueryRequest::RecallIdentity { dest_hash } => {
953 let recalled = self.known_destination_announced(&dest_hash);
954 if recalled.is_some() {
955 let _ = self.mark_known_destination_used(&dest_hash);
956 }
957 QueryResponse::RecallIdentity(recalled)
958 }
959 QueryRequest::DrainStatus => QueryResponse::DrainStatus(self.drain_status()),
960 QueryRequest::SendProbe {
961 dest_hash,
962 payload_size,
963 } => {
964 use crate::event::{SendProbeError, MAX_PROBE_PAYLOAD_SIZE};
965 if payload_size > MAX_PROBE_PAYLOAD_SIZE {
966 log::warn!(
967 "Probe payload of {} bytes exceeds maximum of {} bytes",
968 payload_size,
969 MAX_PROBE_PAYLOAD_SIZE,
970 );
971 return QueryResponse::SendProbe(Err(SendProbeError::PayloadTooLarge {
972 max: MAX_PROBE_PAYLOAD_SIZE,
973 }));
974 }
975 let announced = self.known_destination_announced(&dest_hash);
977 match announced {
978 Some(recalled) => {
979 let _ = self.mark_known_destination_used(&dest_hash);
980 let remote_id =
982 rns_crypto::identity::Identity::from_public_key(&recalled.public_key);
983 let mut payload = vec![0u8; payload_size];
984 self.rng.fill_bytes(&mut payload);
985 match remote_id.and_then(|id| id.encrypt(&payload, &mut self.rng)) {
986 Ok(ciphertext) => {
987 let flags = rns_core::packet::PacketFlags {
989 header_type: rns_core::constants::HEADER_1,
990 context_flag: rns_core::constants::FLAG_UNSET,
991 transport_type: rns_core::constants::TRANSPORT_BROADCAST,
992 destination_type: rns_core::constants::DESTINATION_SINGLE,
993 packet_type: rns_core::constants::PACKET_TYPE_DATA,
994 };
995 match RawPacket::pack(
996 flags,
997 0,
998 &dest_hash,
999 None,
1000 rns_core::constants::CONTEXT_NONE,
1001 &ciphertext,
1002 ) {
1003 Ok(packet) => {
1004 let packet_hash = packet.packet_hash;
1005 let hops = self.engine.hops_to(&dest_hash).unwrap_or(0);
1006 self.sent_packets
1009 .insert(packet_hash, (dest_hash, time::now()));
1010 self.pending_probes.insert(packet_hash);
1011 let actions = self.engine.handle_outbound(
1013 &packet,
1014 rns_core::constants::DESTINATION_SINGLE,
1015 None,
1016 time::now(),
1017 );
1018 self.dispatch_all(actions);
1019 log::debug!(
1020 "Sent probe ({} bytes) to {:02x?}",
1021 payload_size,
1022 &dest_hash[..4],
1023 );
1024 QueryResponse::SendProbe(Ok((packet_hash, hops)))
1025 }
1026 Err(e) => {
1027 log::warn!("Failed to pack probe packet: {:?}", e);
1028 QueryResponse::SendProbe(Err(SendProbeError::PackFailed))
1029 }
1030 }
1031 }
1032 Err(e) => {
1033 log::warn!("Failed to encrypt probe payload: {:?}", e);
1034 QueryResponse::SendProbe(Err(SendProbeError::EncryptFailed))
1035 }
1036 }
1037 }
1038 None => {
1039 log::debug!("No known identity for probe dest {:02x?}", &dest_hash[..4]);
1040 QueryResponse::SendProbe(Err(SendProbeError::UnknownIdentity))
1041 }
1042 }
1043 }
1044 QueryRequest::CheckProof { packet_hash } => {
1045 match self.completed_proofs.remove(&packet_hash) {
1046 Some((rtt, _received)) => QueryResponse::CheckProof(Some(rtt)),
1047 None => QueryResponse::CheckProof(None),
1048 }
1049 }
1050 QueryRequest::SetRuntimeConfig { key, value } => {
1051 let result = match key.as_str() {
1052 "global.tick_interval_ms" => match Self::expect_u64(value, &key) {
1053 Ok(value) => {
1054 let clamped = value.clamp(100, 10_000);
1055 self.tick_interval_ms.store(clamped, Ordering::Relaxed);
1056 Ok(())
1057 }
1058 Err(err) => Err(err),
1059 },
1060 "global.known_destinations_ttl_secs" => match Self::expect_f64(value, &key) {
1061 Ok(value) => {
1062 self.known_destinations_ttl = value;
1063 Ok(())
1064 }
1065 Err(err) => Err(err),
1066 },
1067 "global.rate_limiter_ttl_secs" => match Self::expect_f64(value, &key) {
1068 Ok(value) if value >= 0.0 => {
1069 self.rate_limiter_ttl_secs = value;
1070 Ok(())
1071 }
1072 Ok(_) => Err(RuntimeConfigError {
1073 code: RuntimeConfigErrorCode::InvalidValue,
1074 message: format!("{} must be >= 0", key),
1075 }),
1076 Err(err) => Err(err),
1077 },
1078 "global.known_destinations_cleanup_interval_ticks" => {
1079 match Self::expect_u64(value, &key) {
1080 Ok(value) if value > 0 => {
1081 self.known_destinations_cleanup_interval_ticks = value as u32;
1082 Ok(())
1083 }
1084 Ok(_) => Err(RuntimeConfigError {
1085 code: RuntimeConfigErrorCode::InvalidValue,
1086 message: format!("{} must be >= 1", key),
1087 }),
1088 Err(err) => Err(err),
1089 }
1090 }
1091 "global.announce_cache_cleanup_interval_ticks" => {
1092 match Self::expect_u64(value, &key) {
1093 Ok(value) if value > 0 => {
1094 self.announce_cache_cleanup_interval_ticks = value as u32;
1095 Ok(())
1096 }
1097 Ok(_) => Err(RuntimeConfigError {
1098 code: RuntimeConfigErrorCode::InvalidValue,
1099 message: format!("{} must be >= 1", key),
1100 }),
1101 Err(err) => Err(err),
1102 }
1103 }
1104 "global.announce_cache_cleanup_batch_size" => {
1105 match Self::expect_u64(value, &key) {
1106 Ok(value) if value > 0 => {
1107 self.announce_cache_cleanup_batch_size = value as usize;
1108 Ok(())
1109 }
1110 Ok(_) => Err(RuntimeConfigError {
1111 code: RuntimeConfigErrorCode::InvalidValue,
1112 message: format!("{} must be >= 1", key),
1113 }),
1114 Err(err) => Err(err),
1115 }
1116 }
1117 "global.discovery_cleanup_interval_ticks" => {
1118 match Self::expect_u64(value, &key) {
1119 Ok(value) if value > 0 => {
1120 self.discovery_cleanup_interval_ticks = value as u32;
1121 Ok(())
1122 }
1123 Ok(_) => Err(RuntimeConfigError {
1124 code: RuntimeConfigErrorCode::InvalidValue,
1125 message: format!("{} must be >= 1", key),
1126 }),
1127 Err(err) => Err(err),
1128 }
1129 }
1130 "global.management_announce_interval_secs" => {
1131 match Self::expect_f64(value, &key) {
1132 Ok(value) => {
1133 self.management_announce_interval_secs = value;
1134 Ok(())
1135 }
1136 Err(err) => Err(err),
1137 }
1138 }
1139 "global.stamp_destinations" => match Self::expect_bool(value, &key) {
1140 Ok(value) => {
1141 self.stamp_destinations.store(value, Ordering::Relaxed);
1142 Ok(())
1143 }
1144 Err(err) => Err(err),
1145 },
1146 "global.stamp_path_requests" => match Self::expect_bool(value, &key) {
1147 Ok(value) => {
1148 self.engine.set_stamp_prs(value);
1149 Ok(())
1150 }
1151 Err(err) => Err(err),
1152 },
1153 "global.stamps_enforced" => match Self::expect_bool(value, &key) {
1154 Ok(value) => {
1155 self.set_stamps_enforced(value);
1156 Ok(())
1157 }
1158 Err(err) => Err(err),
1159 },
1160 "global.lr_stamps_enforced" => match Self::expect_bool(value, &key) {
1161 Ok(value) => {
1162 self.link_manager.link_request_costs().set_enforced(value);
1163 Ok(())
1164 }
1165 Err(err) => Err(err),
1166 },
1167 "global.stamp_link_requests" => match Self::expect_bool(value, &key) {
1168 Ok(value) => {
1169 self.stamp_settings.stamp_lrs = value;
1170 Ok(())
1171 }
1172 Err(err) => Err(err),
1173 },
1174 "global.always_stamp_link_requests" => match Self::expect_bool(value, &key) {
1175 Ok(value) => {
1176 self.stamp_settings.always_stamp_lrs = value;
1177 Ok(())
1178 }
1179 Err(err) => Err(err),
1180 },
1181 "global.direct_connect_policy" => {
1182 let policy = match Self::parse_holepunch_policy(&value) {
1183 Some(policy) => policy,
1184 None => {
1185 return QueryResponse::RuntimeConfigSet(Err(RuntimeConfigError {
1186 code: RuntimeConfigErrorCode::InvalidValue,
1187 message: format!(
1188 "{} must be one of: reject, accept_all, identified_only, ask_app",
1189 key
1190 ),
1191 }))
1192 }
1193 };
1194 self.holepunch_manager.set_policy(policy);
1195 Ok(())
1196 }
1197 #[cfg(feature = "hooks")]
1198 "provider.queue_max_events" => match Self::expect_u64(value, &key) {
1199 Ok(v) if v > 0 => {
1200 if let Some(ref bridge) = self.provider_bridge {
1201 bridge.set_queue_max_events(v as usize);
1202 }
1203 Ok(())
1204 }
1205 Ok(_) => Err(RuntimeConfigError {
1206 code: RuntimeConfigErrorCode::InvalidValue,
1207 message: format!("{} must be >= 1", key),
1208 }),
1209 Err(err) => Err(err),
1210 },
1211 #[cfg(feature = "hooks")]
1212 "provider.queue_max_bytes" => match Self::expect_u64(value, &key) {
1213 Ok(v) if v > 0 => {
1214 if let Some(ref bridge) = self.provider_bridge {
1215 bridge.set_queue_max_bytes(v as usize);
1216 }
1217 Ok(())
1218 }
1219 Ok(_) => Err(RuntimeConfigError {
1220 code: RuntimeConfigErrorCode::InvalidValue,
1221 message: format!("{} must be >= 1", key),
1222 }),
1223 Err(err) => Err(err),
1224 },
1225 _ => match Self::runtime_config_family_for_key(&key) {
1226 Some(family) => self.set_runtime_config_family_value(family, &key, value),
1227 None => {
1228 return QueryResponse::RuntimeConfigSet(Err(RuntimeConfigError {
1229 code: RuntimeConfigErrorCode::UnknownKey,
1230 message: format!("unknown runtime-config key '{}'", key),
1231 }))
1232 }
1233 },
1234 };
1235
1236 QueryResponse::RuntimeConfigSet(match result {
1237 Ok(()) => self.runtime_config_entry(&key).ok_or(RuntimeConfigError {
1238 code: RuntimeConfigErrorCode::ApplyFailed,
1239 message: format!("failed to read back runtime-config key '{}'", key),
1240 }),
1241 Err(err) => Err(err),
1242 })
1243 }
1244 QueryRequest::ResetRuntimeConfig { key } => {
1245 let defaults = self.runtime_config_defaults;
1246 let result = match key.as_str() {
1247 "global.tick_interval_ms" => {
1248 self.tick_interval_ms
1249 .store(defaults.tick_interval_ms, Ordering::Relaxed);
1250 Ok(())
1251 }
1252 "global.known_destinations_ttl_secs" => {
1253 self.known_destinations_ttl = defaults.known_destinations_ttl;
1254 Ok(())
1255 }
1256 "global.rate_limiter_ttl_secs" => {
1257 self.rate_limiter_ttl_secs = defaults.rate_limiter_ttl_secs;
1258 Ok(())
1259 }
1260 "global.known_destinations_cleanup_interval_ticks" => {
1261 self.known_destinations_cleanup_interval_ticks =
1262 defaults.known_destinations_cleanup_interval_ticks;
1263 Ok(())
1264 }
1265 "global.announce_cache_cleanup_interval_ticks" => {
1266 self.announce_cache_cleanup_interval_ticks =
1267 defaults.announce_cache_cleanup_interval_ticks;
1268 Ok(())
1269 }
1270 "global.announce_cache_cleanup_batch_size" => {
1271 self.announce_cache_cleanup_batch_size =
1272 defaults.announce_cache_cleanup_batch_size;
1273 Ok(())
1274 }
1275 "global.discovery_cleanup_interval_ticks" => {
1276 self.discovery_cleanup_interval_ticks =
1277 defaults.discovery_cleanup_interval_ticks;
1278 Ok(())
1279 }
1280 "global.management_announce_interval_secs" => {
1281 self.management_announce_interval_secs =
1282 defaults.management_announce_interval_secs;
1283 Ok(())
1284 }
1285 "global.stamp_destinations" => {
1286 self.stamp_destinations
1287 .store(defaults.stamp_destinations, Ordering::Relaxed);
1288 Ok(())
1289 }
1290 "global.stamp_path_requests" => {
1291 self.engine.set_stamp_prs(defaults.stamp_path_requests);
1292 Ok(())
1293 }
1294 "global.stamps_enforced" => {
1295 self.set_stamps_enforced(defaults.stamps_enforced);
1296 Ok(())
1297 }
1298 "global.lr_stamps_enforced" => {
1299 self.link_manager
1300 .link_request_costs()
1301 .set_enforced(defaults.lr_stamps_enforced);
1302 Ok(())
1303 }
1304 "global.stamp_link_requests" => {
1305 self.stamp_settings.stamp_lrs = defaults.stamp_link_requests;
1306 Ok(())
1307 }
1308 "global.always_stamp_link_requests" => {
1309 self.stamp_settings.always_stamp_lrs = defaults.always_stamp_link_requests;
1310 Ok(())
1311 }
1312 "global.direct_connect_policy" => {
1313 self.holepunch_manager
1314 .set_policy(defaults.direct_connect_policy);
1315 Ok(())
1316 }
1317 #[cfg(feature = "hooks")]
1318 "provider.queue_max_events" => {
1319 if let Some(ref bridge) = self.provider_bridge {
1320 bridge.set_queue_max_events(defaults.provider_queue_max_events);
1321 }
1322 Ok(())
1323 }
1324 #[cfg(feature = "hooks")]
1325 "provider.queue_max_bytes" => {
1326 if let Some(ref bridge) = self.provider_bridge {
1327 bridge.set_queue_max_bytes(defaults.provider_queue_max_bytes);
1328 }
1329 Ok(())
1330 }
1331 _ => match Self::runtime_config_family_for_key(&key) {
1332 Some(family) => self.reset_runtime_config_family_value(family, &key),
1333 None => {
1334 return QueryResponse::RuntimeConfigReset(Err(RuntimeConfigError {
1335 code: RuntimeConfigErrorCode::UnknownKey,
1336 message: format!("unknown runtime-config key '{}'", key),
1337 }))
1338 }
1339 },
1340 };
1341
1342 QueryResponse::RuntimeConfigReset(match result {
1343 Ok(()) => self.runtime_config_entry(&key).ok_or(RuntimeConfigError {
1344 code: RuntimeConfigErrorCode::ApplyFailed,
1345 message: format!("failed to read back runtime-config key '{}'", key),
1346 }),
1347 Err(err) => Err(err),
1348 })
1349 }
1350 other => self.handle_query(other),
1351 }
1352 }
1353}