1use std::io::{self, Read, Write};
8use std::net::{TcpListener, TcpStream};
9use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
10use std::sync::{Arc, Mutex};
11use std::thread;
12
13use rns_core::constants;
14use rns_core::transport::types::{IngressControlConfig, InterfaceId, InterfaceInfo};
15
16use crate::event::{Event, EventSender};
17use crate::hdlc;
18use crate::interface::{lock_or_recover, ListenerControl, Writer};
19
20#[derive(Debug, Clone)]
22pub struct TcpServerConfig {
23 pub name: String,
24 pub listen_ip: String,
25 pub listen_port: u16,
26 pub interface_id: InterfaceId,
27 pub max_connections: Option<usize>,
28 pub ingress_control: IngressControlConfig,
29 pub runtime: Arc<Mutex<TcpServerRuntime>>,
30}
31
32#[derive(Debug, Clone)]
33pub struct TcpServerRuntime {
34 pub max_connections: Option<usize>,
35}
36
37impl TcpServerRuntime {
38 pub fn from_config(config: &TcpServerConfig) -> Self {
39 Self {
40 max_connections: config.max_connections,
41 }
42 }
43}
44
45#[derive(Debug, Clone)]
46pub struct TcpServerRuntimeConfigHandle {
47 pub interface_name: String,
48 pub runtime: Arc<Mutex<TcpServerRuntime>>,
49 pub startup: TcpServerRuntime,
50}
51
52impl Default for TcpServerConfig {
53 fn default() -> Self {
54 let mut config = TcpServerConfig {
55 name: String::new(),
56 listen_ip: "0.0.0.0".into(),
57 listen_port: 4242,
58 interface_id: InterfaceId(0),
59 max_connections: None,
60 ingress_control: IngressControlConfig::enabled(),
61 runtime: Arc::new(Mutex::new(TcpServerRuntime {
62 max_connections: None,
63 })),
64 };
65 let startup = TcpServerRuntime::from_config(&config);
66 config.runtime = Arc::new(Mutex::new(startup));
67 config
68 }
69}
70
71struct TcpServerWriter {
73 stream: TcpStream,
74}
75
76impl Writer for TcpServerWriter {
77 fn send_frame(&mut self, data: &[u8]) -> io::Result<()> {
78 self.stream.write_all(&hdlc::frame(data))
79 }
80}
81
82pub fn start(
88 config: TcpServerConfig,
89 tx: EventSender,
90 next_id: Arc<AtomicU64>,
91) -> io::Result<ListenerControl> {
92 let addr = format!("{}:{}", config.listen_ip, config.listen_port);
93 let listener = TcpListener::bind(&addr)?;
94 listener.set_nonblocking(true)?;
95
96 log::info!("[{}] TCP server listening on {}", config.name, addr);
97
98 let name = config.name.clone();
99 let runtime = Arc::clone(&config.runtime);
100 let ingress_control = config.ingress_control;
101 let active_connections = Arc::new(AtomicUsize::new(0));
102 let control = ListenerControl::new();
103 let listener_control = control.clone();
104 thread::Builder::new()
105 .name(format!("tcp-server-{}", config.interface_id.0))
106 .spawn(move || {
107 listener_loop(
108 listener,
109 name,
110 tx,
111 next_id,
112 runtime,
113 ingress_control,
114 active_connections,
115 listener_control,
116 );
117 })?;
118
119 Ok(control)
120}
121
122fn listener_loop(
124 listener: TcpListener,
125 name: String,
126 tx: EventSender,
127 next_id: Arc<AtomicU64>,
128 runtime: Arc<Mutex<TcpServerRuntime>>,
129 ingress_control: IngressControlConfig,
130 active_connections: Arc<AtomicUsize>,
131 control: ListenerControl,
132) {
133 loop {
134 if control.should_stop() {
135 log::info!("[{}] listener stopping", name);
136 return;
137 }
138
139 let stream_result = listener.accept().map(|(stream, _)| stream);
140 let stream = match stream_result {
141 Ok(s) => s,
142 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
143 thread::sleep(std::time::Duration::from_millis(50));
144 continue;
145 }
146 Err(e) => {
147 log::warn!("[{}] accept failed: {}", name, e);
148 continue;
149 }
150 };
151
152 let max_connections = lock_or_recover(&runtime, "tcp server runtime").max_connections;
153 if let Some(max) = max_connections {
154 if active_connections.load(Ordering::Relaxed) >= max {
155 let peer = stream.peer_addr().ok();
156 log::warn!(
157 "[{}] max connections ({}) reached, rejecting {:?}",
158 name,
159 max,
160 peer
161 );
162 drop(stream);
163 continue;
164 }
165 }
166
167 active_connections.fetch_add(1, Ordering::Relaxed);
168
169 let client_id = InterfaceId(next_id.fetch_add(1, Ordering::Relaxed));
170 let peer_addr = stream.peer_addr().ok();
171
172 log::info!(
173 "[{}] client connected: {:?} → id {}",
174 name,
175 peer_addr,
176 client_id.0
177 );
178
179 if let Err(e) = stream.set_nodelay(true) {
181 log::warn!("[{}] set_nodelay failed: {}", name, e);
182 }
183
184 let writer_stream = match stream.try_clone() {
186 Ok(s) => s,
187 Err(e) => {
188 log::warn!("[{}] failed to clone stream: {}", name, e);
189 continue;
190 }
191 };
192
193 let writer: Box<dyn Writer> = Box::new(TcpServerWriter {
194 stream: writer_stream,
195 });
196
197 let info = InterfaceInfo {
198 id: client_id,
199 name: format!("TCPServerInterface/Client-{}", client_id.0),
200 mode: constants::MODE_FULL,
201 recursive_prs: false,
202 announces_from_internal: true,
203 out_capable: true,
204 in_capable: true,
205 bitrate: None,
206 airtime_profile: None,
207 announce_rate_target: None,
208 announce_rate_grace: 0,
209 announce_rate_penalty: 0.0,
210 announce_cap: constants::ANNOUNCE_CAP,
211 is_local_client: false,
212 wants_tunnel: false,
213 tunnel_id: None,
214 mtu: 65535,
215 ia_freq: 0.0,
216 ip_freq: 0.0,
217 op_freq: 0.0,
218 op_samples: 0,
219 started: 0.0,
220 ingress_control,
221 };
222
223 if tx
225 .send(Event::InterfaceUp(client_id, Some(writer), Some(info)))
226 .is_err()
227 {
228 return;
230 }
231
232 let client_tx = tx.clone();
234 let client_name = name.clone();
235 let client_active = active_connections.clone();
236 thread::Builder::new()
237 .name(format!("tcp-server-reader-{}", client_id.0))
238 .spawn(move || {
239 client_reader_loop(stream, client_id, client_name, client_tx, client_active);
240 })
241 .ok();
242 }
243}
244
245fn client_reader_loop(
247 mut stream: TcpStream,
248 id: InterfaceId,
249 name: String,
250 tx: EventSender,
251 active_connections: Arc<AtomicUsize>,
252) {
253 let mut decoder = hdlc::Decoder::new();
254 let mut buf = [0u8; 4096];
255
256 loop {
257 match stream.read(&mut buf) {
258 Ok(0) => {
259 log::info!("[{}] client {} disconnected", name, id.0);
260 active_connections.fetch_sub(1, Ordering::Relaxed);
261 let _ = tx.send(Event::InterfaceDown(id));
262 return;
263 }
264 Ok(n) => {
265 for frame in decoder.feed(&buf[..n]) {
266 if tx
267 .send(Event::Frame {
268 interface_id: id,
269 data: frame,
270 rssi: None,
271 snr: None,
272 })
273 .is_err()
274 {
275 active_connections.fetch_sub(1, Ordering::Relaxed);
277 return;
278 }
279 }
280 }
281 Err(e) => {
282 log::warn!("[{}] client {} read error: {}", name, id.0, e);
283 active_connections.fetch_sub(1, Ordering::Relaxed);
284 let _ = tx.send(Event::InterfaceDown(id));
285 return;
286 }
287 }
288 }
289}
290
291use super::{InterfaceConfigData, InterfaceFactory, StartContext, StartResult};
294use std::collections::HashMap;
295
296pub struct TcpServerFactory;
298
299impl InterfaceFactory for TcpServerFactory {
300 fn type_name(&self) -> &str {
301 "TCPServerInterface"
302 }
303
304 fn parse_config(
305 &self,
306 name: &str,
307 id: InterfaceId,
308 params: &HashMap<String, String>,
309 ) -> Result<Box<dyn InterfaceConfigData>, String> {
310 let listen_ip = params
311 .get("listen_ip")
312 .cloned()
313 .unwrap_or_else(|| "0.0.0.0".into());
314 let listen_port = params
315 .get("listen_port")
316 .and_then(|v| v.parse().ok())
317 .unwrap_or(4242);
318 let max_connections = params.get("max_connections").and_then(|v| v.parse().ok());
319 let mut config = TcpServerConfig {
320 name: name.to_string(),
321 listen_ip,
322 listen_port,
323 interface_id: id,
324 max_connections,
325 ingress_control: IngressControlConfig::enabled(),
326 runtime: Arc::new(Mutex::new(TcpServerRuntime {
327 max_connections: None,
328 })),
329 };
330 let startup = TcpServerRuntime::from_config(&config);
331 config.runtime = Arc::new(Mutex::new(startup));
332 Ok(Box::new(config))
333 }
334
335 fn start(
336 &self,
337 config: Box<dyn InterfaceConfigData>,
338 ctx: StartContext,
339 ) -> io::Result<StartResult> {
340 let mut cfg = *config
341 .into_any()
342 .downcast::<TcpServerConfig>()
343 .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "wrong config type"))?;
344 cfg.ingress_control = ctx.ingress_control;
345 let control = start(cfg, ctx.tx, ctx.next_dynamic_id)?;
346 Ok(StartResult::Listener {
347 control: Some(control),
348 })
349 }
350}
351
352pub(crate) fn runtime_handle_from_config(config: &TcpServerConfig) -> TcpServerRuntimeConfigHandle {
353 TcpServerRuntimeConfigHandle {
354 interface_name: config.name.clone(),
355 runtime: Arc::clone(&config.runtime),
356 startup: TcpServerRuntime::from_config(config),
357 }
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363 use std::net::TcpStream;
364 use std::sync::mpsc::RecvTimeoutError;
365 use std::time::Duration;
366
367 fn find_free_port() -> u16 {
368 TcpListener::bind("127.0.0.1:0")
369 .unwrap()
370 .local_addr()
371 .unwrap()
372 .port()
373 }
374
375 fn make_server_config(
376 port: u16,
377 interface_id: u64,
378 max_connections: Option<usize>,
379 ) -> TcpServerConfig {
380 let mut config = TcpServerConfig {
381 name: "test-server".into(),
382 listen_ip: "127.0.0.1".into(),
383 listen_port: port,
384 interface_id: InterfaceId(interface_id),
385 max_connections,
386 ingress_control: IngressControlConfig::enabled(),
387 runtime: Arc::new(Mutex::new(TcpServerRuntime {
388 max_connections: None,
389 })),
390 };
391 let startup = TcpServerRuntime::from_config(&config);
392 config.runtime = Arc::new(Mutex::new(startup));
393 config
394 }
395
396 #[test]
397 fn accept_connection() {
398 let port = find_free_port();
399 let (tx, rx) = crate::event::channel();
400 let next_id = Arc::new(AtomicU64::new(1000));
401
402 let config = make_server_config(port, 1, None);
403
404 start(config, tx, next_id).unwrap();
405
406 thread::sleep(Duration::from_millis(50));
408
409 let _client = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
411
412 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
414 match event {
415 Event::InterfaceUp(id, writer, info) => {
416 assert_eq!(id, InterfaceId(1000));
417 assert!(writer.is_some());
418 assert!(info.is_some());
419 }
420 other => panic!("expected InterfaceUp, got {:?}", other),
421 }
422 }
423
424 #[test]
425 fn spawned_client_inherits_ingress_control_config() {
426 let port = find_free_port();
427 let (tx, rx) = crate::event::channel();
428 let next_id = Arc::new(AtomicU64::new(1100));
429
430 let mut config = make_server_config(port, 11, None);
431 config.ingress_control = IngressControlConfig::disabled();
432 config.ingress_control.max_held_announces = 17;
433 config.ingress_control.burst_hold = 1.5;
434 config.ingress_control.burst_freq_new = 2.5;
435 config.ingress_control.burst_freq = 3.5;
436 config.ingress_control.new_time = 4.5;
437 config.ingress_control.burst_penalty = 5.5;
438 config.ingress_control.held_release_interval = 6.5;
439
440 start(config, tx, next_id).unwrap();
441 thread::sleep(Duration::from_millis(50));
442
443 let _client = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
444
445 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
446 match event {
447 Event::InterfaceUp(_, _, Some(info)) => {
448 assert!(!info.ingress_control.enabled);
449 assert_eq!(info.ingress_control.max_held_announces, 17);
450 assert_eq!(info.ingress_control.burst_hold, 1.5);
451 assert_eq!(info.ingress_control.burst_freq_new, 2.5);
452 assert_eq!(info.ingress_control.burst_freq, 3.5);
453 assert_eq!(info.ingress_control.new_time, 4.5);
454 assert_eq!(info.ingress_control.burst_penalty, 5.5);
455 assert_eq!(info.ingress_control.held_release_interval, 6.5);
456 }
457 other => panic!("expected InterfaceUp with InterfaceInfo, got {:?}", other),
458 }
459 }
460
461 #[test]
462 fn listener_stop_prevents_new_accepts() {
463 let port = find_free_port();
464 let (tx, rx) = crate::event::channel();
465 let next_id = Arc::new(AtomicU64::new(1500));
466
467 let config = make_server_config(port, 15, None);
468 let control = start(config, tx, next_id).unwrap();
469
470 thread::sleep(Duration::from_millis(50));
471 control.request_stop();
472 thread::sleep(Duration::from_millis(120));
473
474 let connect_result = TcpStream::connect(format!("127.0.0.1:{}", port));
475 if let Ok(stream) = connect_result {
476 drop(stream);
477 }
478
479 match rx.recv_timeout(Duration::from_millis(200)) {
480 Err(RecvTimeoutError::Timeout) | Err(RecvTimeoutError::Disconnected) => {}
481 other => panic!(
482 "expected no InterfaceUp after listener stop, got {:?}",
483 other
484 ),
485 }
486 }
487
488 #[test]
489 fn receive_frame_from_client() {
490 let port = find_free_port();
491 let (tx, rx) = crate::event::channel();
492 let next_id = Arc::new(AtomicU64::new(2000));
493
494 let config = make_server_config(port, 2, None);
495
496 start(config, tx, next_id).unwrap();
497 thread::sleep(Duration::from_millis(50));
498
499 let mut client = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
500
501 let _ = rx.recv_timeout(Duration::from_secs(1)).unwrap();
503
504 let payload: Vec<u8> = (0..32).collect();
506 let framed = hdlc::frame(&payload);
507 client.write_all(&framed).unwrap();
508
509 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
511 match event {
512 Event::Frame {
513 interface_id,
514 data,
515 rssi: _,
516 snr: _,
517 } => {
518 assert_eq!(interface_id, InterfaceId(2000));
519 assert_eq!(data, payload);
520 }
521 other => panic!("expected Frame, got {:?}", other),
522 }
523 }
524
525 #[test]
526 fn send_frame_to_client() {
527 let port = find_free_port();
528 let (tx, rx) = crate::event::channel();
529 let next_id = Arc::new(AtomicU64::new(3000));
530
531 let config = make_server_config(port, 3, None);
532
533 start(config, tx, next_id).unwrap();
534 thread::sleep(Duration::from_millis(50));
535
536 let mut client = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
537 client
538 .set_read_timeout(Some(Duration::from_secs(2)))
539 .unwrap();
540
541 let event = rx.recv_timeout(Duration::from_secs(1)).unwrap();
543 let mut writer = match event {
544 Event::InterfaceUp(_, Some(w), _) => w,
545 other => panic!("expected InterfaceUp with writer, got {:?}", other),
546 };
547
548 let payload: Vec<u8> = (0..24).collect();
550 writer.send_frame(&payload).unwrap();
551
552 let mut buf = [0u8; 256];
554 let n = client.read(&mut buf).unwrap();
555 let expected = hdlc::frame(&payload);
556 assert_eq!(&buf[..n], &expected[..]);
557 }
558
559 #[test]
560 fn multiple_clients() {
561 let port = find_free_port();
562 let (tx, rx) = crate::event::channel();
563 let next_id = Arc::new(AtomicU64::new(4000));
564
565 let config = make_server_config(port, 4, None);
566
567 start(config, tx, next_id).unwrap();
568 thread::sleep(Duration::from_millis(50));
569
570 let _client1 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
572 let _client2 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
573
574 let mut ids = Vec::new();
576 for _ in 0..2 {
577 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
578 match event {
579 Event::InterfaceUp(id, _, _) => ids.push(id),
580 other => panic!("expected InterfaceUp, got {:?}", other),
581 }
582 }
583
584 assert_eq!(ids.len(), 2);
586 assert_ne!(ids[0], ids[1]);
587 }
588
589 #[test]
590 fn client_disconnect() {
591 let port = find_free_port();
592 let (tx, rx) = crate::event::channel();
593 let next_id = Arc::new(AtomicU64::new(5000));
594
595 let config = make_server_config(port, 5, None);
596
597 start(config, tx, next_id).unwrap();
598 thread::sleep(Duration::from_millis(50));
599
600 let client = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
601
602 let _ = rx.recv_timeout(Duration::from_secs(1)).unwrap();
604
605 drop(client);
607
608 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
610 assert!(
611 matches!(event, Event::InterfaceDown(InterfaceId(5000))),
612 "expected InterfaceDown(5000), got {:?}",
613 event
614 );
615 }
616
617 #[test]
618 fn server_bind_port() {
619 let port = find_free_port();
620 let (tx, _rx) = crate::event::channel();
621 let next_id = Arc::new(AtomicU64::new(6000));
622
623 let config = make_server_config(port, 6, None);
624
625 start(config, tx, next_id).unwrap();
627 }
628
629 #[test]
630 fn max_connections_rejects_excess() {
631 let port = find_free_port();
632 let (tx, rx) = crate::event::channel();
633 let next_id = Arc::new(AtomicU64::new(7000));
634
635 let config = make_server_config(port, 7, Some(2));
636
637 start(config, tx, next_id).unwrap();
638 thread::sleep(Duration::from_millis(50));
639
640 let _client1 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
642 let _client2 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
643
644 for _ in 0..2 {
646 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
647 assert!(matches!(event, Event::InterfaceUp(_, _, _)));
648 }
649
650 let client3 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
652 client3
653 .set_read_timeout(Some(Duration::from_millis(500)))
654 .unwrap();
655
656 thread::sleep(Duration::from_millis(100));
658
659 let result = rx.recv_timeout(Duration::from_millis(500));
661 assert!(
662 result.is_err(),
663 "expected no InterfaceUp for rejected connection, got {:?}",
664 result
665 );
666 }
667
668 #[test]
669 fn max_connections_allows_after_disconnect() {
670 let port = find_free_port();
671 let (tx, rx) = crate::event::channel();
672 let next_id = Arc::new(AtomicU64::new(7100));
673
674 let config = make_server_config(port, 71, Some(1));
675
676 start(config, tx, next_id).unwrap();
677 thread::sleep(Duration::from_millis(50));
678
679 let client1 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
681 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
682 assert!(matches!(event, Event::InterfaceUp(_, _, _)));
683
684 drop(client1);
686
687 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
689 assert!(matches!(event, Event::InterfaceDown(_)));
690
691 let _client2 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
693 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
694 assert!(
695 matches!(event, Event::InterfaceUp(_, _, _)),
696 "expected InterfaceUp after slot freed, got {:?}",
697 event
698 );
699 }
700
701 #[test]
702 fn runtime_max_connections_updates_live() {
703 let port = find_free_port();
704 let (tx, rx) = crate::event::channel();
705 let next_id = Arc::new(AtomicU64::new(7200));
706
707 let config = make_server_config(port, 72, None);
708 let runtime = Arc::clone(&config.runtime);
709
710 start(config, tx, next_id).unwrap();
711 thread::sleep(Duration::from_millis(50));
712
713 let _client1 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
714 let event = rx.recv_timeout(Duration::from_secs(2)).unwrap();
715 assert!(matches!(event, Event::InterfaceUp(_, _, _)));
716
717 {
718 let mut runtime = runtime.lock().unwrap();
719 runtime.max_connections = Some(1);
720 }
721
722 let _client2 = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap();
723 let result = rx.recv_timeout(Duration::from_millis(400));
724 assert!(
725 result.is_err(),
726 "expected no InterfaceUp after lowering max_connections, got {:?}",
727 result
728 );
729 }
730}