grafos_net/listener.rs
1//! Fabric-aware TCP listener on a leased network interface.
2
3use std::io;
4use std::net::{SocketAddr, TcpListener, TcpStream};
5
6use grafos_std::net::NetLease;
7
8/// A TCP listener bound to a leased fabric network interface.
9///
10/// Accepts connections on a specific port, with the bandwidth guarantee
11/// from the underlying [`NetLease`]. On native targets, delegates to
12/// `std::net::TcpListener`.
13///
14/// # Example
15///
16/// ```rust
17/// use grafos_net::FabricListener;
18/// use grafos_std::net::NetBuilder;
19///
20/// # grafos_std::host::reset_mock();
21/// # grafos_std::host::mock_set_net_interface("lo", 1_000_000_000);
22/// let lease = NetBuilder::new().acquire()?;
23/// let listener = FabricListener::bind(lease, 0)?;
24/// let addr = listener.local_addr()?;
25/// println!("listening on {}", addr);
26/// # Ok::<(), Box<dyn std::error::Error>>(())
27/// ```
28pub struct FabricListener {
29 inner: TcpListener,
30 _lease: NetLease,
31}
32
33impl FabricListener {
34 /// Bind a listener to the given port on the leased interface.
35 ///
36 /// On native targets, binds to `0.0.0.0:port`.
37 ///
38 /// # Errors
39 ///
40 /// Returns an I/O error if the bind fails.
41 pub fn bind(lease: NetLease, port: u16) -> io::Result<Self> {
42 let addr = SocketAddr::from(([0, 0, 0, 0], port));
43 let inner = TcpListener::bind(addr)?;
44 Ok(FabricListener {
45 inner,
46 _lease: lease,
47 })
48 }
49
50 /// Accept a new incoming connection.
51 ///
52 /// Returns the connected stream and the peer's address.
53 ///
54 /// # Errors
55 ///
56 /// Returns an I/O error if the accept fails.
57 pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
58 self.inner.accept()
59 }
60
61 /// Returns the local address this listener is bound to.
62 ///
63 /// # Errors
64 ///
65 /// Returns an I/O error if the address cannot be retrieved.
66 pub fn local_addr(&self) -> io::Result<SocketAddr> {
67 self.inner.local_addr()
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use grafos_std::host;
75 use grafos_std::net::NetBuilder;
76 use std::io::{Read, Write};
77
78 #[test]
79 fn listener_bind_and_accept() {
80 host::reset_mock();
81 host::mock_set_net_interface("lo", 1_000_000_000);
82
83 let lease = NetBuilder::new().acquire().expect("acquire");
84 let listener = FabricListener::bind(lease, 0).expect("bind");
85 let addr = listener.local_addr().expect("local_addr");
86
87 let handle = std::thread::spawn(move || {
88 let mut stream = std::net::TcpStream::connect(addr).expect("connect");
89 stream.write_all(b"fabric hello").expect("write");
90 });
91
92 let (mut conn, _peer) = listener.accept().expect("accept");
93 let mut buf = vec![0u8; 64];
94 let n = conn.read(&mut buf).expect("read");
95 assert_eq!(&buf[..n], b"fabric hello");
96
97 handle.join().expect("join");
98 }
99}