Skip to main content

netstack_smoltcp/
tcp.rs

1use std::{
2    collections::HashMap,
3    net::SocketAddr,
4    pin::Pin,
5    sync::{
6        atomic::{AtomicBool, Ordering},
7        Arc,
8    },
9    task::{Context, Poll, Waker},
10};
11
12use futures::Stream;
13use smoltcp::{
14    iface::{Config as InterfaceConfig, Interface, SocketHandle, SocketSet},
15    phy::Device,
16    socket::tcp::{Socket as TcpSocket, SocketBuffer as TcpSocketBuffer, State as TcpState},
17    storage::RingBuffer,
18    time::{Duration, Instant},
19    wire::{HardwareAddress, IpAddress, IpCidr, IpProtocol, Ipv4Address, Ipv6Address, TcpPacket},
20};
21use spin::Mutex as SpinMutex;
22use tokio::{
23    io::{AsyncRead, AsyncWrite, ReadBuf},
24    sync::{
25        mpsc::{unbounded_channel, Receiver, Sender, UnboundedReceiver, UnboundedSender},
26        Notify,
27    },
28};
29use tracing::{error, trace};
30
31use crate::{
32    device::VirtualDevice,
33    packet::{AnyIpPktFrame, IpPacket},
34    Runner,
35};
36
37#[derive(Debug, Clone, Copy, Eq, PartialEq)]
38enum TcpSocketState {
39    Normal,
40    Close,
41    Closing,
42    Closed,
43}
44
45struct TcpSocketControl {
46    send_buffer: RingBuffer<'static, u8>,
47    send_waker: Option<Waker>,
48    recv_buffer: RingBuffer<'static, u8>,
49    recv_waker: Option<Waker>,
50    recv_state: TcpSocketState,
51    send_state: TcpSocketState,
52}
53
54struct TcpSocketCreation {
55    control: SharedControl,
56    socket: TcpSocket<'static>,
57}
58
59type SharedNotify = Arc<Notify>;
60type SharedControl = Arc<SpinMutex<TcpSocketControl>>;
61
62struct TcpListenerRunner;
63
64impl TcpListenerRunner {
65    #[allow(clippy::too_many_arguments)]
66    fn create(
67        device: VirtualDevice,
68        iface: Interface,
69        iface_ingress_tx: UnboundedSender<Vec<u8>>,
70        iface_ingress_tx_avail: Arc<AtomicBool>,
71        tcp_rx: Receiver<AnyIpPktFrame>,
72        stream_tx: UnboundedSender<TcpStream>,
73        sockets: HashMap<SocketHandle, SharedControl>,
74        tcp_recv_buffer_size: u32,
75        tcp_send_buffer_size: u32,
76    ) -> Runner {
77        Runner::new(async move {
78            let notify = Arc::new(Notify::new());
79            let (socket_tx, socket_rx) = unbounded_channel::<TcpSocketCreation>();
80            let res = tokio::select! {
81                v = Self::handle_packet(notify.clone(), iface_ingress_tx, iface_ingress_tx_avail.clone(), tcp_rx, stream_tx, socket_tx, tcp_recv_buffer_size, tcp_send_buffer_size) => v,
82                v = Self::handle_socket(notify, device, iface, iface_ingress_tx_avail, sockets, socket_rx) => v,
83            };
84            res?;
85            trace!("VirtDevice::poll thread exited");
86            Ok(())
87        })
88    }
89
90    #[allow(clippy::too_many_arguments)]
91    async fn handle_packet(
92        notify: SharedNotify,
93        iface_ingress_tx: UnboundedSender<Vec<u8>>,
94        iface_ingress_tx_avail: Arc<AtomicBool>,
95        mut tcp_rx: Receiver<AnyIpPktFrame>,
96        stream_tx: UnboundedSender<TcpStream>,
97        socket_tx: UnboundedSender<TcpSocketCreation>,
98        tcp_recv_buffer_size: u32,
99        tcp_send_buffer_size: u32,
100    ) -> std::io::Result<()> {
101        while let Some(frame) = tcp_rx.recv().await {
102            let packet = match IpPacket::new_checked(frame.as_slice()) {
103                Ok(p) => p,
104                Err(err) => {
105                    error!("invalid TCP IP packet: {:?}", err,);
106                    continue;
107                }
108            };
109
110            // Specially handle icmp packet by TCP interface.
111            if matches!(packet.protocol(), IpProtocol::Icmp | IpProtocol::Icmpv6) {
112                iface_ingress_tx
113                    .send(frame)
114                    .map_err(|e| std::io::Error::new(std::io::ErrorKind::BrokenPipe, e))?;
115                iface_ingress_tx_avail.store(true, Ordering::Release);
116                notify.notify_one();
117                continue;
118            }
119
120            let src_ip = packet.src_addr();
121            let dst_ip = packet.dst_addr();
122            let payload = packet.payload();
123
124            let packet = match TcpPacket::new_checked(payload) {
125                Ok(p) => p,
126                Err(err) => {
127                    error!("invalid TCP err: {err}, src_ip: {src_ip}, dst_ip: {dst_ip}, payload: {payload:?}");
128                    continue;
129                }
130            };
131            let src_port = packet.src_port();
132            let dst_port = packet.dst_port();
133
134            let src_addr = SocketAddr::new(src_ip, src_port);
135            let dst_addr = SocketAddr::new(dst_ip, dst_port);
136
137            // TCP first handshake packet, create a new Connection
138            if packet.syn() && !packet.ack() {
139                let mut socket = TcpSocket::new(
140                    TcpSocketBuffer::new(vec![0u8; tcp_recv_buffer_size as usize]),
141                    TcpSocketBuffer::new(vec![0u8; tcp_send_buffer_size as usize]),
142                );
143                socket.set_keep_alive(Some(Duration::from_secs(28)));
144                // FIXME: It should follow system's setting. 7200 is Linux's default.
145                socket.set_timeout(Some(Duration::from_secs(7200)));
146                // NO ACK delay
147                // socket.set_ack_delay(None);
148
149                if let Err(err) = socket.listen(dst_addr) {
150                    error!("listen error: {:?}", err);
151                    continue;
152                }
153
154                trace!("created TCP connection for {} <-> {}", src_addr, dst_addr);
155
156                let control = Arc::new(SpinMutex::new(TcpSocketControl {
157                    send_buffer: RingBuffer::new(vec![0u8; tcp_send_buffer_size as usize]),
158                    send_waker: None,
159                    recv_buffer: RingBuffer::new(vec![0u8; tcp_recv_buffer_size as usize]),
160                    recv_waker: None,
161                    recv_state: TcpSocketState::Normal,
162                    send_state: TcpSocketState::Normal,
163                }));
164
165                stream_tx
166                    .send(TcpStream {
167                        src_addr,
168                        dst_addr,
169                        notify: notify.clone(),
170                        control: control.clone(),
171                    })
172                    .map_err(|e| std::io::Error::new(std::io::ErrorKind::BrokenPipe, e))?;
173                socket_tx
174                    .send(TcpSocketCreation { control, socket })
175                    .map_err(|e| std::io::Error::new(std::io::ErrorKind::BrokenPipe, e))?;
176            }
177
178            // Pipeline tcp stream packet
179            iface_ingress_tx
180                .send(frame)
181                .map_err(|e| std::io::Error::new(std::io::ErrorKind::BrokenPipe, e))?;
182            iface_ingress_tx_avail.store(true, Ordering::Release);
183            notify.notify_one();
184        }
185        Ok(())
186    }
187
188    async fn handle_socket(
189        notify: SharedNotify,
190        mut device: VirtualDevice,
191        mut iface: Interface,
192        iface_ingress_tx_avail: Arc<AtomicBool>,
193        mut sockets: HashMap<SocketHandle, SharedControl>,
194        mut socket_rx: UnboundedReceiver<TcpSocketCreation>,
195    ) -> std::io::Result<()> {
196        let mut socket_set = SocketSet::new(vec![]);
197        loop {
198            while let Ok(TcpSocketCreation { control, socket }) = socket_rx.try_recv() {
199                let handle = socket_set.add(socket);
200                sockets.insert(handle, control);
201            }
202
203            let before_poll = Instant::now();
204            let updated_sockets = iface.poll(before_poll, &mut device, &mut socket_set);
205            if matches!(
206                updated_sockets,
207                smoltcp::iface::PollResult::SocketStateChanged
208            ) {
209                trace!("VirtDevice::poll costed {}", Instant::now() - before_poll);
210            }
211
212            // Check all the sockets' status
213            let mut sockets_to_remove = Vec::new();
214
215            for (socket_handle, control) in sockets.iter() {
216                let socket_handle = *socket_handle;
217                let socket = socket_set.get_mut::<TcpSocket>(socket_handle);
218                let mut control = control.lock();
219
220                // Remove the socket only when it is in the closed state.
221                if socket.state() == TcpState::Closed {
222                    sockets_to_remove.push(socket_handle);
223
224                    control.send_state = TcpSocketState::Closed;
225                    control.recv_state = TcpSocketState::Closed;
226
227                    if let Some(waker) = control.send_waker.take() {
228                        waker.wake();
229                    }
230                    if let Some(waker) = control.recv_waker.take() {
231                        waker.wake();
232                    }
233
234                    trace!("closed TCP connection");
235                    continue;
236                }
237
238                // SHUT_WR — only close once the send_buffer has been fully
239                // drained into the smoltcp socket.  Closing earlier transitions
240                // the socket to FIN_WAIT_1, making can_send() return false, so
241                // the send loop below never runs and the remaining data is lost.
242                if matches!(control.send_state, TcpSocketState::Close)
243                    && control.send_buffer.is_empty()
244                {
245                    trace!("closing TCP Write Half, {:?}", socket.state());
246
247                    socket.close();
248                    control.send_state = TcpSocketState::Closing;
249                }
250
251                // Check if readable
252                let mut wake_receiver = false;
253                while socket.can_recv() && !control.recv_buffer.is_full() {
254                    let result = socket.recv(|buffer| {
255                        let n = control.recv_buffer.enqueue_slice(buffer);
256                        (n, ())
257                    });
258
259                    match result {
260                        Ok(..) => wake_receiver = true,
261                        Err(err) => {
262                            error!("socket recv error: {:?}, {:?}", err, socket.state());
263
264                            // Don't know why. Abort the connection.
265                            socket.abort();
266
267                            if matches!(control.recv_state, TcpSocketState::Normal) {
268                                control.recv_state = TcpSocketState::Closed;
269                            }
270                            wake_receiver = true;
271
272                            // The socket will be recycled in the next poll.
273                            break;
274                        }
275                    }
276                }
277
278                // If socket is not in ESTABLISH, FIN-WAIT-1, FIN-WAIT-2,
279                // the local client have closed our receiver.
280                let states = [
281                    TcpState::Listen,
282                    TcpState::SynReceived,
283                    TcpState::Established,
284                    TcpState::FinWait1,
285                    TcpState::FinWait2,
286                ];
287                if matches!(control.recv_state, TcpSocketState::Normal)
288                    && !socket.may_recv()
289                    && !states.contains(&socket.state())
290                {
291                    trace!("closed TCP Read Half, {:?}", socket.state());
292
293                    // Let TcpStream::poll_read returns EOF.
294                    control.recv_state = TcpSocketState::Closed;
295                    wake_receiver = true;
296                }
297
298                if wake_receiver && control.recv_waker.is_some() {
299                    if let Some(waker) = control.recv_waker.take() {
300                        waker.wake();
301                    }
302                }
303
304                // Check if writable
305                let mut wake_sender = false;
306                while socket.can_send() && !control.send_buffer.is_empty() {
307                    let result = socket.send(|buffer| {
308                        let n = control.send_buffer.dequeue_slice(buffer);
309                        (n, ())
310                    });
311
312                    match result {
313                        Ok(..) => wake_sender = true,
314                        Err(err) => {
315                            error!("socket send error: {:?}, {:?}", err, socket.state());
316
317                            // Don't know why. Abort the connection.
318                            socket.abort();
319
320                            if matches!(control.send_state, TcpSocketState::Normal) {
321                                control.send_state = TcpSocketState::Closed;
322                            }
323                            wake_sender = true;
324
325                            // The socket will be recycled in the next poll.
326                            break;
327                        }
328                    }
329                }
330
331                if wake_sender && control.send_waker.is_some() {
332                    if let Some(waker) = control.send_waker.take() {
333                        waker.wake();
334                    }
335                }
336            }
337
338            for socket_handle in sockets_to_remove {
339                sockets.remove(&socket_handle);
340                socket_set.remove(socket_handle);
341            }
342
343            // Ensure every loop iteration yields to the runtime. When egress
344            // capacity is available OR when `poll_delay` returns ZERO ("re-poll
345            // now"), this loop otherwise takes no `.await`, so under an active
346            // flow it busy-spins. Because `handle_socket` and `handle_packet`
347            // are arms of one `tokio::select!` future, a never-yielding
348            // `handle_socket` never returns control to the sibling SYN-accept
349            // arm: one core pins flat at 100% and new inbound connections are
350            // starved (observed as connect timeouts with no SYN-ACK). A
351            // cooperative `yield_now()` keeps the re-poll just as prompt while
352            // letting `handle_packet` make progress. The timed-park path and the
353            // 5 ms idle fallback are unchanged, so there is no missed-wake risk.
354            if iface_ingress_tx_avail.load(Ordering::Acquire) {
355                tokio::task::yield_now().await;
356            } else {
357                let next_duration = iface
358                    .poll_delay(before_poll, &socket_set)
359                    .unwrap_or(Duration::from_millis(5));
360                if next_duration != Duration::ZERO {
361                    let _ = tokio::time::timeout(
362                        tokio::time::Duration::from(next_duration),
363                        notify.notified(),
364                    )
365                    .await;
366                } else {
367                    tokio::task::yield_now().await;
368                }
369            }
370        }
371    }
372}
373
374pub struct TcpListener {
375    stream_rx: UnboundedReceiver<TcpStream>,
376}
377
378impl TcpListener {
379    pub(super) fn new(
380        tcp_rx: Receiver<AnyIpPktFrame>,
381        stack_tx: Sender<AnyIpPktFrame>,
382        mtu: usize,
383        tcp_recv_buffer_size: u32,
384        tcp_send_buffer_size: u32,
385    ) -> std::io::Result<(Runner, Self)> {
386        let (mut device, iface_ingress_tx, iface_ingress_tx_avail) =
387            VirtualDevice::new(stack_tx, mtu);
388        let iface = Self::create_interface(&mut device)?;
389
390        let (stream_tx, stream_rx) = unbounded_channel();
391
392        let runner = TcpListenerRunner::create(
393            device,
394            iface,
395            iface_ingress_tx,
396            iface_ingress_tx_avail,
397            tcp_rx,
398            stream_tx,
399            HashMap::new(),
400            tcp_recv_buffer_size,
401            tcp_send_buffer_size,
402        );
403
404        Ok((runner, Self { stream_rx }))
405    }
406
407    fn create_interface<D>(device: &mut D) -> std::io::Result<Interface>
408    where
409        D: Device + ?Sized,
410    {
411        let mut iface_config = InterfaceConfig::new(HardwareAddress::Ip);
412        iface_config.random_seed = rand::random();
413        let mut iface = Interface::new(iface_config, device, Instant::now());
414        iface.update_ip_addrs(|ip_addrs| {
415            ip_addrs
416                .push(IpCidr::new(IpAddress::v4(0, 0, 0, 1), 0))
417                .expect("iface IPv4");
418            ip_addrs
419                .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 0))
420                .expect("iface IPv6");
421        });
422        iface
423            .routes_mut()
424            .add_default_ipv4_route(Ipv4Address::new(0, 0, 0, 1))
425            .map_err(|e| std::io::Error::new(std::io::ErrorKind::AddrNotAvailable, e))?;
426        iface
427            .routes_mut()
428            .add_default_ipv6_route(Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 1))
429            .map_err(|e| std::io::Error::new(std::io::ErrorKind::AddrNotAvailable, e))?;
430        iface.set_any_ip(true);
431        Ok(iface)
432    }
433}
434
435impl Stream for TcpListener {
436    type Item = (TcpStream, SocketAddr, SocketAddr);
437
438    fn poll_next(
439        mut self: std::pin::Pin<&mut Self>,
440        cx: &mut std::task::Context<'_>,
441    ) -> std::task::Poll<Option<Self::Item>> {
442        self.stream_rx.poll_recv(cx).map(|stream| {
443            stream.map(|stream| {
444                let local_addr = *stream.local_addr();
445                let remote_addr: SocketAddr = *stream.remote_addr();
446                (stream, local_addr, remote_addr)
447            })
448        })
449    }
450}
451
452pub struct TcpStream {
453    src_addr: SocketAddr,
454    dst_addr: SocketAddr,
455    notify: SharedNotify,
456    control: SharedControl,
457}
458
459impl Drop for TcpStream {
460    fn drop(&mut self) {
461        let mut control = self.control.lock();
462
463        if matches!(control.recv_state, TcpSocketState::Normal) {
464            control.recv_state = TcpSocketState::Close;
465        }
466
467        if matches!(control.send_state, TcpSocketState::Normal) {
468            control.send_state = TcpSocketState::Close;
469        }
470
471        self.notify.notify_one();
472    }
473}
474
475impl TcpStream {
476    pub fn local_addr(&self) -> &SocketAddr {
477        &self.src_addr
478    }
479
480    pub fn remote_addr(&self) -> &SocketAddr {
481        &self.dst_addr
482    }
483}
484
485impl AsyncRead for TcpStream {
486    fn poll_read(
487        self: Pin<&mut Self>,
488        cx: &mut Context<'_>,
489        buf: &mut ReadBuf<'_>,
490    ) -> Poll<std::io::Result<()>> {
491        let mut control = self.control.lock();
492
493        // Read from buffer
494        if control.recv_buffer.is_empty() {
495            // If socket is already closed / half closed, just return EOF directly.
496            if matches!(control.recv_state, TcpSocketState::Closed) {
497                return Ok(()).into();
498            }
499
500            // Nothing could be read. Wait for notify.
501            if let Some(old_waker) = control.recv_waker.replace(cx.waker().clone()) {
502                if !old_waker.will_wake(cx.waker()) {
503                    old_waker.wake();
504                }
505            }
506
507            return Poll::Pending;
508        }
509
510        let recv_buf = buf.initialize_unfilled();
511        let n = control.recv_buffer.dequeue_slice(recv_buf);
512        buf.advance(n);
513
514        if n > 0 {
515            self.notify.notify_one();
516        }
517
518        Ok(()).into()
519    }
520}
521
522impl AsyncWrite for TcpStream {
523    fn poll_write(
524        self: Pin<&mut Self>,
525        cx: &mut Context<'_>,
526        buf: &[u8],
527    ) -> Poll<std::io::Result<usize>> {
528        let mut control = self.control.lock();
529
530        // If state == Close | Closing | Closed, the TCP stream WR half is closed.
531        if !matches!(control.send_state, TcpSocketState::Normal) {
532            return Err(std::io::ErrorKind::BrokenPipe.into()).into();
533        }
534
535        // Write to buffer
536
537        if control.send_buffer.is_full() {
538            if let Some(old_waker) = control.send_waker.replace(cx.waker().clone()) {
539                if !old_waker.will_wake(cx.waker()) {
540                    old_waker.wake();
541                }
542            }
543
544            return Poll::Pending;
545        }
546
547        let n = control.send_buffer.enqueue_slice(buf);
548
549        if n > 0 {
550            self.notify.notify_one();
551        }
552
553        Ok(n).into()
554    }
555
556    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
557        Ok(()).into()
558    }
559
560    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
561        let mut control = self.control.lock();
562
563        if matches!(control.send_state, TcpSocketState::Closed) {
564            return Ok(()).into();
565        }
566
567        // SHUT_WR
568        if matches!(control.send_state, TcpSocketState::Normal) {
569            control.send_state = TcpSocketState::Close;
570        }
571
572        if let Some(old_waker) = control.send_waker.replace(cx.waker().clone()) {
573            if !old_waker.will_wake(cx.waker()) {
574                old_waker.wake();
575            }
576        }
577
578        self.notify.notify_one();
579
580        Poll::Pending
581    }
582}