Skip to main content

rns_net/interface/
mod.rs

1//! Network interface abstractions.
2
3pub mod tcp;
4pub mod tcp_server;
5pub mod udp;
6pub mod local;
7pub mod serial_iface;
8pub mod kiss_iface;
9pub mod pipe;
10pub mod rnode;
11pub mod backbone;
12pub mod auto;
13pub mod i2p;
14
15use std::io;
16
17use rns_core::transport::types::{InterfaceId, InterfaceInfo};
18use crate::ifac::IfacState;
19
20/// Bind a socket to a specific network interface using `SO_BINDTODEVICE`.
21///
22/// Requires `CAP_NET_RAW` or root on Linux.
23#[cfg(target_os = "linux")]
24pub fn bind_to_device(fd: std::os::unix::io::RawFd, device: &str) -> io::Result<()> {
25    let dev_bytes = device.as_bytes();
26    if dev_bytes.len() >= libc::IFNAMSIZ {
27        return Err(io::Error::new(
28            io::ErrorKind::InvalidInput,
29            format!("device name too long: {}", device),
30        ));
31    }
32    let ret = unsafe {
33        libc::setsockopt(
34            fd,
35            libc::SOL_SOCKET,
36            libc::SO_BINDTODEVICE,
37            dev_bytes.as_ptr() as *const libc::c_void,
38            dev_bytes.len() as libc::socklen_t,
39        )
40    };
41    if ret != 0 {
42        return Err(io::Error::last_os_error());
43    }
44    Ok(())
45}
46
47/// Writable end of an interface. Held by the driver.
48///
49/// Each implementation wraps a socket + framing.
50pub trait Writer: Send {
51    fn send_frame(&mut self, data: &[u8]) -> io::Result<()>;
52}
53
54/// Maximum number of announce timestamps to keep per direction.
55const ANNOUNCE_SAMPLE_MAX: usize = 6;
56
57/// Traffic statistics for an interface.
58#[derive(Debug, Clone, Default)]
59pub struct InterfaceStats {
60    pub rxb: u64,
61    pub txb: u64,
62    pub rx_packets: u64,
63    pub tx_packets: u64,
64    pub started: f64,
65    /// Recent incoming announce timestamps (bounded).
66    pub ia_timestamps: Vec<f64>,
67    /// Recent outgoing announce timestamps (bounded).
68    pub oa_timestamps: Vec<f64>,
69}
70
71impl InterfaceStats {
72    /// Record an incoming announce timestamp.
73    pub fn record_incoming_announce(&mut self, now: f64) {
74        self.ia_timestamps.push(now);
75        if self.ia_timestamps.len() > ANNOUNCE_SAMPLE_MAX {
76            self.ia_timestamps.remove(0);
77        }
78    }
79
80    /// Record an outgoing announce timestamp.
81    pub fn record_outgoing_announce(&mut self, now: f64) {
82        self.oa_timestamps.push(now);
83        if self.oa_timestamps.len() > ANNOUNCE_SAMPLE_MAX {
84            self.oa_timestamps.remove(0);
85        }
86    }
87
88    /// Compute announce frequency (per second) from timestamps.
89    fn compute_frequency(timestamps: &[f64]) -> f64 {
90        if timestamps.len() < 2 {
91            return 0.0;
92        }
93        let span = timestamps[timestamps.len() - 1] - timestamps[0];
94        if span <= 0.0 {
95            return 0.0;
96        }
97        (timestamps.len() - 1) as f64 / span
98    }
99
100    /// Incoming announce frequency (per second).
101    pub fn incoming_announce_freq(&self) -> f64 {
102        Self::compute_frequency(&self.ia_timestamps)
103    }
104
105    /// Outgoing announce frequency (per second).
106    pub fn outgoing_announce_freq(&self) -> f64 {
107        Self::compute_frequency(&self.oa_timestamps)
108    }
109}
110
111/// Everything the driver tracks per interface.
112pub struct InterfaceEntry {
113    pub id: InterfaceId,
114    pub info: InterfaceInfo,
115    pub writer: Box<dyn Writer>,
116    pub online: bool,
117    /// True for dynamically spawned interfaces (e.g. TCP server clients).
118    /// These are fully removed on InterfaceDown rather than just marked offline.
119    pub dynamic: bool,
120    /// IFAC state for this interface, if access codes are enabled.
121    pub ifac: Option<IfacState>,
122    /// Traffic statistics.
123    pub stats: InterfaceStats,
124    /// Human-readable interface type string (e.g. "TCPClientInterface").
125    pub interface_type: String,
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use rns_core::constants;
132
133    struct MockWriter {
134        sent: Vec<Vec<u8>>,
135    }
136
137    impl MockWriter {
138        fn new() -> Self {
139            MockWriter { sent: Vec::new() }
140        }
141    }
142
143    impl Writer for MockWriter {
144        fn send_frame(&mut self, data: &[u8]) -> io::Result<()> {
145            self.sent.push(data.to_vec());
146            Ok(())
147        }
148    }
149
150    #[test]
151    fn interface_entry_construction() {
152        let entry = InterfaceEntry {
153            id: InterfaceId(1),
154            info: InterfaceInfo {
155                id: InterfaceId(1),
156                name: String::new(),
157                mode: constants::MODE_FULL,
158                out_capable: true,
159                in_capable: true,
160                bitrate: None,
161                announce_rate_target: None,
162                announce_rate_grace: 0,
163                announce_rate_penalty: 0.0,
164                announce_cap: constants::ANNOUNCE_CAP,
165                is_local_client: false,
166                wants_tunnel: false,
167                tunnel_id: None,
168                mtu: constants::MTU as u32,
169                ia_freq: 0.0,
170                started: 0.0,
171                ingress_control: false,
172            },
173            writer: Box::new(MockWriter::new()),
174            online: false,
175            dynamic: false,
176            ifac: None,
177            stats: InterfaceStats::default(),
178            interface_type: String::new(),
179        };
180        assert_eq!(entry.id, InterfaceId(1));
181        assert!(!entry.online);
182        assert!(!entry.dynamic);
183    }
184
185    #[test]
186    fn mock_writer_captures_bytes() {
187        let mut writer = MockWriter::new();
188        writer.send_frame(b"hello").unwrap();
189        writer.send_frame(b"world").unwrap();
190        assert_eq!(writer.sent.len(), 2);
191        assert_eq!(writer.sent[0], b"hello");
192        assert_eq!(writer.sent[1], b"world");
193    }
194
195    #[test]
196    fn writer_send_frame_produces_output() {
197        let mut writer = MockWriter::new();
198        let data = vec![0x01, 0x02, 0x03];
199        writer.send_frame(&data).unwrap();
200        assert_eq!(writer.sent[0], data);
201    }
202}