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.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}