Skip to main content

rns_core/transport/
outbound_engine.rs

1use super::*;
2
3impl TransportEngine {
4    /// Route an outbound packet.
5    pub fn handle_outbound<B: crate::packet::PacketStorage>(
6        &mut self,
7        packet: &RawPacket<B>,
8        dest_type: u8,
9        attached_interface: Option<InterfaceId>,
10        now: f64,
11    ) -> Vec<TransportAction> {
12        let mut actions = Vec::new();
13        self.handle_outbound_into(packet, dest_type, attached_interface, now, &mut actions);
14        actions
15    }
16
17    /// [`Self::handle_outbound`], appending the actions to `actions` so a
18    /// caller can reuse one buffer across packets.
19    pub fn handle_outbound_into<B: crate::packet::PacketStorage>(
20        &mut self,
21        packet: &RawPacket<B>,
22        dest_type: u8,
23        attached_interface: Option<InterfaceId>,
24        now: f64,
25        actions: &mut Vec<TransportAction>,
26    ) {
27        if packet.hops >= constants::PATHFINDER_M {
28            return;
29        }
30
31        let uses_path = packet.flags.packet_type != constants::PACKET_TYPE_ANNOUNCE
32            && dest_type != constants::DESTINATION_PLAIN
33            && dest_type != constants::DESTINATION_GROUP
34            && !(dest_type == constants::DESTINATION_LINK && attached_interface.is_some());
35        if uses_path {
36            if let Some(path_set) = self.path_table.get_mut(&packet.destination_hash) {
37                if let Some(entry) = path_set.primary_mut() {
38                    entry.used = now;
39                }
40            }
41        }
42
43        let start = actions.len();
44        route_outbound_into(
45            &self.path_table,
46            &self.interfaces,
47            &self.local_destinations,
48            packet,
49            dest_type,
50            attached_interface,
51            OutboundRouteOptions {
52                identity_hash: self.config.identity_hash,
53                local_hops_delta: self.config.local_hops_delta,
54            },
55            actions,
56        );
57
58        // Add to packet hashlist for outbound packets. A link resource part,
59        // part request or proof is not hashed: its context bypasses
60        // deduplication.
61        if !packet.is_unhashed_link_resource() {
62            self.packet_hashlist.add(packet.packet_hash);
63        }
64
65        // Gate announces with hops > 0 through the bandwidth queue
66        if packet.flags.packet_type == constants::PACKET_TYPE_ANNOUNCE && packet.hops > 0 {
67            let routed: Vec<TransportAction> = actions.drain(start..).collect();
68            let gated =
69                self.gate_announce_actions(routed, &packet.destination_hash, packet.hops, now);
70            actions.extend(gated);
71        }
72    }
73
74    /// Gate announce SendOnInterface actions through per-interface bandwidth queues.
75    fn gate_announce_actions(
76        &mut self,
77        actions: Vec<TransportAction>,
78        dest_hash: &[u8; 16],
79        hops: u8,
80        now: f64,
81    ) -> Vec<TransportAction> {
82        let mut result = Vec::new();
83        for action in actions {
84            match action {
85                TransportAction::SendOnInterface { interface, raw } => {
86                    let (bitrate, airtime_profile, announce_cap) =
87                        if let Some(info) = self.interfaces.get(&interface) {
88                            (info.bitrate, info.airtime_profile, info.announce_cap)
89                        } else {
90                            (None, None, constants::ANNOUNCE_CAP)
91                        };
92                    if let Some(send_action) = self.announce_queues.gate_announce(
93                        interface,
94                        raw,
95                        *dest_hash,
96                        hops,
97                        now,
98                        now,
99                        bitrate,
100                        airtime_profile,
101                        announce_cap,
102                    ) {
103                        result.push(send_action);
104                    }
105                    // If None, it was queued — no action emitted now
106                }
107                other => result.push(other),
108            }
109        }
110        result
111    }
112}