Skip to main content

rns_core/transport/
path_requests.rs

1use 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.handle_known_path_request(&ctx) {
17            return Vec::new();
18        }
19        if self.config.transport_enabled {
20            return self.handle_discovery_path_request(&ctx);
21        }
22        Vec::new()
23    }
24
25    fn parse_path_request<'a>(
26        &mut self,
27        data: &'a [u8],
28        interface_id: InterfaceId,
29        now: f64,
30    ) -> Option<PathRequestCtx<'a>> {
31        if data.len() < 16 {
32            return None;
33        }
34
35        let mut destination_hash = [0u8; 16];
36        destination_hash.copy_from_slice(&data[..16]);
37
38        let tag_bytes = if data.len() > 32 {
39            Some(&data[32..])
40        } else if data.len() > 16 {
41            Some(&data[16..])
42        } else {
43            None
44        }?;
45
46        let tag_len = tag_bytes.len().min(16);
47        let mut unique_tag = [0u8; 32];
48        unique_tag[..16].copy_from_slice(&destination_hash);
49        unique_tag[16..16 + tag_len].copy_from_slice(&tag_bytes[..tag_len]);
50        if !self.insert_discovery_pr_tag(unique_tag) {
51            return None;
52        }
53
54        Some(PathRequestCtx {
55            tag: &tag_bytes[..tag_len],
56            interface_id,
57            now,
58            destination_hash,
59        })
60    }
61
62    fn handle_known_path_request(&mut self, ctx: &PathRequestCtx<'_>) -> bool {
63        let Some(path) = self
64            .path_table
65            .get(&ctx.destination_hash)
66            .and_then(|ps| ps.primary())
67            .cloned()
68        else {
69            return false;
70        };
71
72        if let Some(recv_info) = self.interfaces.get(&ctx.interface_id) {
73            if recv_info.mode == constants::MODE_ROAMING
74                && path.receiving_interface == ctx.interface_id
75            {
76                return true;
77            }
78        }
79
80        let Some(raw) = path.announce_raw.as_ref() else {
81            return false;
82        };
83        if let Some(existing) = self.announce_table.remove(&ctx.destination_hash) {
84            self.insert_held_announce(ctx.destination_hash, existing, ctx.now);
85        }
86        let retransmit_timeout = if let Some(iface_info) = self.interfaces.get(&ctx.interface_id) {
87            let base = ctx.now + constants::PATH_REQUEST_GRACE;
88            if iface_info.mode == constants::MODE_ROAMING {
89                base + constants::PATH_REQUEST_RG
90            } else {
91                base
92            }
93        } else {
94            ctx.now + constants::PATH_REQUEST_GRACE
95        };
96
97        let Ok(parsed) = RawPacket::unpack(raw) else {
98            return false;
99        };
100
101        let entry = AnnounceEntry {
102            timestamp: ctx.now,
103            retransmit_timeout,
104            retries: constants::PATHFINDER_R,
105            received_from: path.next_hop,
106            hops: path.hops,
107            packet_raw: raw.clone(),
108            packet_data: parsed.data,
109            destination_hash: ctx.destination_hash,
110            context_flag: parsed.flags.context_flag,
111            local_rebroadcasts: 0,
112            block_rebroadcasts: true,
113            attached_interface: Some(ctx.interface_id),
114        };
115
116        self.insert_announce_entry(ctx.destination_hash, entry, ctx.now);
117        true
118    }
119
120    fn handle_discovery_path_request(&mut self, ctx: &PathRequestCtx<'_>) -> Vec<TransportAction> {
121        let Some((mode, ingress_control, ip_freq, started)) = self
122            .interfaces
123            .get(&ctx.interface_id)
124            .map(|info| (info.mode, info.ingress_control, info.ip_freq, info.started))
125        else {
126            return Vec::new();
127        };
128
129        let should_discover = constants::DISCOVER_PATHS_FOR.contains(&mode);
130        if !should_discover {
131            return Vec::new();
132        }
133
134        if self.ingress_control.should_ingress_limit_pr(
135            ctx.interface_id,
136            &ingress_control,
137            ip_freq,
138            started,
139            ctx.now,
140        ) {
141            return Vec::new();
142        }
143
144        let egress_candidates: Vec<_> = self
145            .interfaces
146            .values()
147            .filter(|info| info.id != ctx.interface_id && info.out_capable)
148            .map(|info| {
149                (
150                    info.id,
151                    info.ingress_control,
152                    info.op_freq,
153                    info.op_samples,
154                    info.bitrate,
155                    info.airtime_profile,
156                    info.announce_cap,
157                )
158            })
159            .collect();
160
161        let Some((path_request_raw, path_request_len)) = build_path_request_packet(
162            &ctx.destination_hash,
163            self.config.identity_hash.as_ref(),
164            ctx.tag,
165        ) else {
166            return Vec::new();
167        };
168
169        let mut actions = Vec::new();
170        for (id, ingress_control, op_freq, op_samples, bitrate, airtime_profile, announce_cap) in
171            egress_candidates
172        {
173            if self.ingress_control.should_egress_limit_pr(
174                id,
175                &ingress_control,
176                op_freq,
177                op_samples,
178            ) || self
179                .announce_queues
180                .blocks_recursive_path_request(id, ctx.now)
181            {
182                continue;
183            }
184
185            self.announce_queues.reserve_recursive_path_request(
186                id,
187                path_request_len + constants::HEADER_MINSIZE,
188                ctx.now,
189                bitrate,
190                airtime_profile,
191                announce_cap,
192            );
193            actions.push(TransportAction::SendOnInterface {
194                interface: id,
195                raw: path_request_raw.clone().into(),
196            });
197        }
198
199        if !actions.is_empty() {
200            self.discovery_path_requests.insert(
201                ctx.destination_hash,
202                DiscoveryPathRequest {
203                    timestamp: ctx.now,
204                    requesting_interface: ctx.interface_id,
205                },
206            );
207        }
208
209        actions
210    }
211}
212
213fn build_path_request_packet(
214    destination_hash: &[u8; 16],
215    transport_identity_hash: Option<&[u8; 16]>,
216    tag: &[u8],
217) -> Option<(Vec<u8>, usize)> {
218    let mut data = Vec::with_capacity(16 + transport_identity_hash.map_or(0, |_| 16) + tag.len());
219    data.extend_from_slice(destination_hash);
220    if let Some(identity_hash) = transport_identity_hash {
221        data.extend_from_slice(identity_hash);
222    }
223    data.extend_from_slice(tag);
224
225    let flags = crate::packet::PacketFlags {
226        header_type: constants::HEADER_1,
227        context_flag: constants::FLAG_UNSET,
228        transport_type: constants::TRANSPORT_BROADCAST,
229        destination_type: constants::DESTINATION_PLAIN,
230        packet_type: constants::PACKET_TYPE_DATA,
231    };
232    let path_request_dest =
233        crate::destination::destination_hash("rnstransport", &["path", "request"], None);
234
235    let data_len = data.len();
236    RawPacket::pack(
237        flags,
238        0,
239        &path_request_dest,
240        None,
241        constants::CONTEXT_NONE,
242        &data,
243    )
244    .ok()
245    .map(|packet| (packet.raw, data_len))
246}