rns_core/transport/
path_requests.rs1use super::*;
2
3impl TransportEngine {
4 pub fn handle_path_request(
5 &mut self,
6 data: &[u8],
7 interface_id: InterfaceId,
8 now: f64,
9 ) -> Vec<TransportAction> {
10 let Some(ctx) = self.parse_path_request(data, interface_id, now) else {
11 return Vec::new();
12 };
13 if self.local_destinations.contains_key(&ctx.destination_hash) {
14 return Vec::new();
15 }
16 if self.config.transport_enabled && self.has_path(&ctx.destination_hash) {
17 self.handle_known_path_request(&ctx);
18 return Vec::new();
19 }
20 if self.config.transport_enabled {
21 return self.handle_discovery_path_request(&ctx);
22 }
23 Vec::new()
24 }
25
26 fn parse_path_request<'a>(
27 &mut self,
28 data: &'a [u8],
29 interface_id: InterfaceId,
30 now: f64,
31 ) -> Option<PathRequestCtx<'a>> {
32 if data.len() < 16 {
33 return None;
34 }
35
36 let mut destination_hash = [0u8; 16];
37 destination_hash.copy_from_slice(&data[..16]);
38
39 let tag_bytes = if data.len() > 32 {
40 Some(&data[32..])
41 } else if data.len() > 16 {
42 Some(&data[16..])
43 } else {
44 None
45 }?;
46
47 let tag_len = tag_bytes.len().min(16);
48 let mut unique_tag = [0u8; 32];
49 unique_tag[..16].copy_from_slice(&destination_hash);
50 unique_tag[16..16 + tag_len].copy_from_slice(&tag_bytes[..tag_len]);
51 if !self.insert_discovery_pr_tag(unique_tag) {
52 return None;
53 }
54
55 Some(PathRequestCtx {
56 data,
57 interface_id,
58 now,
59 destination_hash,
60 })
61 }
62
63 fn handle_known_path_request(&mut self, ctx: &PathRequestCtx<'_>) {
64 let Some(path) = self
65 .path_table
66 .get(&ctx.destination_hash)
67 .and_then(|ps| ps.primary())
68 .cloned()
69 else {
70 return;
71 };
72
73 if let Some(recv_info) = self.interfaces.get(&ctx.interface_id) {
74 if recv_info.mode == constants::MODE_ROAMING
75 && path.receiving_interface == ctx.interface_id
76 {
77 return;
78 }
79 }
80
81 let Some(raw) = path.announce_raw.as_ref() else {
82 return;
83 };
84 if let Some(existing) = self.announce_table.remove(&ctx.destination_hash) {
85 self.insert_held_announce(ctx.destination_hash, existing, ctx.now);
86 }
87 let retransmit_timeout = if let Some(iface_info) = self.interfaces.get(&ctx.interface_id) {
88 let base = ctx.now + constants::PATH_REQUEST_GRACE;
89 if iface_info.mode == constants::MODE_ROAMING {
90 base + constants::PATH_REQUEST_RG
91 } else {
92 base
93 }
94 } else {
95 ctx.now + constants::PATH_REQUEST_GRACE
96 };
97
98 let Ok(parsed) = RawPacket::unpack(raw) else {
99 return;
100 };
101
102 let entry = AnnounceEntry {
103 timestamp: ctx.now,
104 retransmit_timeout,
105 retries: constants::PATHFINDER_R,
106 received_from: path.next_hop,
107 hops: path.hops,
108 packet_raw: raw.clone(),
109 packet_data: parsed.data,
110 destination_hash: ctx.destination_hash,
111 context_flag: parsed.flags.context_flag,
112 local_rebroadcasts: 0,
113 block_rebroadcasts: true,
114 attached_interface: Some(ctx.interface_id),
115 };
116
117 self.insert_announce_entry(ctx.destination_hash, entry, ctx.now);
118 }
119
120 fn handle_discovery_path_request(&mut self, ctx: &PathRequestCtx<'_>) -> Vec<TransportAction> {
121 let should_discover = self
122 .interfaces
123 .get(&ctx.interface_id)
124 .map(|info| constants::DISCOVER_PATHS_FOR.contains(&info.mode))
125 .unwrap_or(false);
126 if !should_discover {
127 return Vec::new();
128 }
129
130 self.discovery_path_requests.insert(
131 ctx.destination_hash,
132 DiscoveryPathRequest {
133 timestamp: ctx.now,
134 requesting_interface: ctx.interface_id,
135 },
136 );
137
138 self.interfaces
139 .values()
140 .filter(|iface_info| iface_info.id != ctx.interface_id && iface_info.out_capable)
141 .map(|iface_info| TransportAction::SendOnInterface {
142 interface: iface_info.id,
143 raw: ctx.data.to_vec().into(),
144 })
145 .collect()
146 }
147}