tokio_smoltcp/
lib.rs

1//! An asynchronous wrapper for smoltcp.
2
3use std::{
4    io,
5    net::{Ipv4Addr, Ipv6Addr, SocketAddr},
6    sync::{
7        Arc,
8        atomic::{AtomicU16, Ordering},
9    },
10};
11
12use device::BufferDevice;
13use futures::Future;
14use reactor::Reactor;
15pub use smoltcp;
16use smoltcp::{
17    iface::{Config, Interface, Routes},
18    time::{Duration, Instant},
19    wire::{HardwareAddress, IpAddress, IpCidr, IpProtocol, IpVersion},
20};
21pub use socket::{RawSocket, TcpListener, TcpStream, UdpSocket};
22pub use socket_allocator::BufferSize;
23use tokio::sync::Notify;
24
25/// The async devices.
26pub mod device;
27mod reactor;
28mod socket;
29mod socket_allocator;
30
31/// Can be used to create a forever timestamp in neighbor.
32// The 60_000 is the same as NeighborCache::ENTRY_LIFETIME.
33pub const FOREVER: Instant =
34    Instant::from_micros_const(i64::max_value() - Duration::from_millis(60_000).micros() as i64);
35
36pub struct Neighbor {
37    pub protocol_addr: IpAddress,
38    pub hardware_addr: HardwareAddress,
39    pub timestamp: Instant,
40}
41
42/// A config for a `Net`.
43///
44/// This is used to configure the `Net`.
45#[non_exhaustive]
46pub struct NetConfig {
47    pub interface_config: Config,
48    pub ip_addr: IpCidr,
49    pub gateway: Vec<IpAddress>,
50    pub buffer_size: BufferSize,
51}
52
53impl NetConfig {
54    pub fn new(interface_config: Config, ip_addr: IpCidr, gateway: Vec<IpAddress>) -> Self {
55        Self {
56            interface_config,
57            ip_addr,
58            gateway,
59            buffer_size: Default::default(),
60        }
61    }
62}
63
64/// `Net` is the main interface to the network stack.
65/// Socket creation and configuration is done through the `Net` interface.
66///
67/// When `Net` is dropped, all sockets are closed and the network stack is stopped.
68pub struct Net {
69    reactor: Arc<Reactor>,
70    ip_addr: IpCidr,
71    from_port: AtomicU16,
72    stopper: Arc<Notify>,
73}
74
75impl Net {
76    /// Creates a new `Net` instance. It panics if the medium is not supported.
77    pub fn new<D: device::AsyncDevice + 'static>(device: D, config: NetConfig) -> Net {
78        let (net, fut) = Self::new2(device, config);
79        tokio::spawn(fut);
80        net
81    }
82
83    fn new2<D: device::AsyncDevice + 'static>(
84        device: D,
85        config: NetConfig,
86    ) -> (Net, impl Future<Output = io::Result<()>> + Send) {
87        let mut buffer_device = BufferDevice::new(device.capabilities().clone());
88        let mut iface = Interface::new(config.interface_config, &mut buffer_device, Instant::now());
89        let ip_addr = config.ip_addr;
90        iface.update_ip_addrs(|ip_addrs| {
91            ip_addrs.push(ip_addr).unwrap();
92        });
93        for gateway in config.gateway {
94            match gateway {
95                IpAddress::Ipv4(v4) => {
96                    iface.routes_mut().add_default_ipv4_route(v4).unwrap();
97                }
98                IpAddress::Ipv6(v6) => {
99                    iface.routes_mut().add_default_ipv6_route(v6).unwrap();
100                }
101                #[allow(unreachable_patterns)]
102                _ => panic!("Unsupported address"),
103            };
104        }
105
106        let stopper = Arc::new(Notify::new());
107        let (reactor, fut) = Reactor::new(
108            device,
109            iface,
110            buffer_device,
111            config.buffer_size,
112            stopper.clone(),
113        );
114
115        (
116            Net {
117                reactor: Arc::new(reactor),
118                ip_addr: config.ip_addr,
119                from_port: AtomicU16::new(10001),
120                stopper,
121            },
122            fut,
123        )
124    }
125    fn get_port(&self) -> u16 {
126        self.from_port
127            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
128                Some(if x > 60000 { 10000 } else { x + 1 })
129            })
130            .unwrap()
131    }
132    /// Creates a new TcpListener, which will be bound to the specified address.
133    pub async fn tcp_bind(&self, addr: SocketAddr) -> io::Result<TcpListener> {
134        let addr = self.set_address(addr);
135        TcpListener::new(self.reactor.clone(), addr.into()).await
136    }
137    /// Opens a TCP connection to a remote host.
138    pub async fn tcp_connect(&self, addr: SocketAddr) -> io::Result<TcpStream> {
139        TcpStream::connect(
140            self.reactor.clone(),
141            (self.ip_addr.address(), self.get_port()).into(),
142            addr.into(),
143        )
144        .await
145    }
146    pub fn tcp_connect_lazy(
147        &self,
148        addr: SocketAddr,
149    ) -> (
150        SocketAddr,
151        impl Future<Output = Result<TcpStream, std::io::Error>>,
152    ) {
153        let local_endpoint: SocketAddr = (self.ip_addr.address(), self.get_port()).into();
154        let future = TcpStream::connect(self.reactor.clone(), local_endpoint.into(), addr.into());
155        (local_endpoint, future)
156    }
157    /// This function will create a new UDP socket and attempt to bind it to the `addr` provided.
158    pub async fn udp_bind(&self, addr: SocketAddr) -> io::Result<UdpSocket> {
159        let addr = self.set_address(addr);
160        UdpSocket::new(self.reactor.clone(), addr.into()).await
161    }
162    /// Creates a new raw socket.
163    pub async fn raw_socket(
164        &self,
165        ip_version: IpVersion,
166        ip_protocol: IpProtocol,
167    ) -> io::Result<RawSocket> {
168        RawSocket::new(self.reactor.clone(), ip_version, ip_protocol).await
169    }
170    fn set_address(&self, mut addr: SocketAddr) -> SocketAddr {
171        if addr.ip().is_unspecified() {
172            addr.set_ip(match self.ip_addr.address() {
173                IpAddress::Ipv4(ip) => Ipv4Addr::from(ip).into(),
174                IpAddress::Ipv6(ip) => Ipv6Addr::from(ip).into(),
175                #[allow(unreachable_patterns)]
176                _ => panic!("address must not be unspecified"),
177            });
178        }
179        if addr.port() == 0 {
180            addr.set_port(self.get_port());
181        }
182        addr
183    }
184
185    /// Enable or disable the AnyIP capability.
186    pub fn set_any_ip(&self, any_ip: bool) {
187        let iface = self.reactor.iface().clone();
188        let mut iface: parking_lot::lock_api::MutexGuard<'_, parking_lot::RawMutex, Interface> =
189            iface.lock();
190        iface.set_any_ip(any_ip);
191    }
192
193    /// Get whether AnyIP is enabled.
194    pub fn any_ip(&self) -> bool {
195        let iface = self.reactor.iface().clone();
196        let iface = iface.lock();
197        iface.any_ip()
198    }
199
200    pub fn routes<F: FnOnce(&Routes)>(&self, f: F) {
201        let iface = self.reactor.iface().clone();
202        let iface = iface.lock();
203        let routes = iface.routes();
204        f(routes)
205    }
206
207    pub fn routes_mut<F: FnOnce(&mut Routes)>(&self, f: F) {
208        let iface = self.reactor.iface().clone();
209        let mut iface = iface.lock();
210        let routes = iface.routes_mut();
211        f(routes)
212    }
213}
214
215impl Drop for Net {
216    fn drop(&mut self) {
217        self.stopper.notify_waiters()
218    }
219}