1pub 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#[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
47pub trait Writer: Send {
51 fn send_frame(&mut self, data: &[u8]) -> io::Result<()>;
52}
53
54const ANNOUNCE_SAMPLE_MAX: usize = 6;
56
57#[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 pub ia_timestamps: Vec<f64>,
67 pub oa_timestamps: Vec<f64>,
69}
70
71impl InterfaceStats {
72 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 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 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 pub fn incoming_announce_freq(&self) -> f64 {
102 Self::compute_frequency(&self.ia_timestamps)
103 }
104
105 pub fn outgoing_announce_freq(&self) -> f64 {
107 Self::compute_frequency(&self.oa_timestamps)
108 }
109}
110
111pub struct InterfaceEntry {
113 pub id: InterfaceId,
114 pub info: InterfaceInfo,
115 pub writer: Box<dyn Writer>,
116 pub online: bool,
117 pub dynamic: bool,
120 pub ifac: Option<IfacState>,
122 pub stats: InterfaceStats,
124 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}