rns-core 0.7.0

Wire protocol, transport routing, and link/resource engine for the Reticulum Network Stack
Documentation
use super::*;

impl TransportEngine {
    /// Route an outbound packet.
    pub fn handle_outbound<B: crate::packet::PacketStorage>(
        &mut self,
        packet: &RawPacket<B>,
        dest_type: u8,
        attached_interface: Option<InterfaceId>,
        now: f64,
    ) -> Vec<TransportAction> {
        let mut actions = Vec::new();
        self.handle_outbound_into(packet, dest_type, attached_interface, now, &mut actions);
        actions
    }

    /// [`Self::handle_outbound`], appending the actions to `actions` so a
    /// caller can reuse one buffer across packets.
    pub fn handle_outbound_into<B: crate::packet::PacketStorage>(
        &mut self,
        packet: &RawPacket<B>,
        dest_type: u8,
        attached_interface: Option<InterfaceId>,
        now: f64,
        actions: &mut Vec<TransportAction>,
    ) {
        if packet.hops >= constants::PATHFINDER_M {
            return;
        }

        let uses_path = packet.flags.packet_type != constants::PACKET_TYPE_ANNOUNCE
            && dest_type != constants::DESTINATION_PLAIN
            && dest_type != constants::DESTINATION_GROUP
            && !(dest_type == constants::DESTINATION_LINK && attached_interface.is_some());
        if uses_path {
            if let Some(path_set) = self.path_table.get_mut(&packet.destination_hash) {
                if let Some(entry) = path_set.primary_mut() {
                    entry.used = now;
                }
            }
        }

        let start = actions.len();
        route_outbound_into(
            &self.path_table,
            &self.interfaces,
            &self.local_destinations,
            packet,
            dest_type,
            attached_interface,
            OutboundRouteOptions {
                identity_hash: self.config.identity_hash,
                local_hops_delta: self.config.local_hops_delta,
            },
            actions,
        );

        // Add to packet hashlist for outbound packets. A link resource part,
        // part request or proof is not hashed: its context bypasses
        // deduplication.
        if !packet.is_unhashed_link_resource() {
            self.packet_hashlist.add(packet.packet_hash);
        }

        // Gate announces with hops > 0 through the bandwidth queue
        if packet.flags.packet_type == constants::PACKET_TYPE_ANNOUNCE && packet.hops > 0 {
            let routed: Vec<TransportAction> = actions.drain(start..).collect();
            let gated =
                self.gate_announce_actions(routed, &packet.destination_hash, packet.hops, now);
            actions.extend(gated);
        }
    }

    /// Gate announce SendOnInterface actions through per-interface bandwidth queues.
    fn gate_announce_actions(
        &mut self,
        actions: Vec<TransportAction>,
        dest_hash: &[u8; 16],
        hops: u8,
        now: f64,
    ) -> Vec<TransportAction> {
        let mut result = Vec::new();
        for action in actions {
            match action {
                TransportAction::SendOnInterface { interface, raw } => {
                    let (bitrate, airtime_profile, announce_cap) =
                        if let Some(info) = self.interfaces.get(&interface) {
                            (info.bitrate, info.airtime_profile, info.announce_cap)
                        } else {
                            (None, None, constants::ANNOUNCE_CAP)
                        };
                    if let Some(send_action) = self.announce_queues.gate_announce(
                        interface,
                        raw,
                        *dest_hash,
                        hops,
                        now,
                        now,
                        bitrate,
                        airtime_profile,
                        announce_cap,
                    ) {
                        result.push(send_action);
                    }
                    // If None, it was queued — no action emitted now
                }
                other => result.push(other),
            }
        }
        result
    }
}