From b0b009c639aa332195a5aa8b647f6f003f234d95 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Sat, 2 Sep 2023 09:28:02 +0200 Subject: [PATCH 1/2] return error also in the closing state If smoltcp receives a FIN message, the socket changes the state to the `closing`, but the socket is still active. To close the socket, the kernel returns a error if the socket is in the closing state. The PR should solve issue hermit-os/kernel#880 --- src/fd/socket/tcp.rs | 76 ++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/src/fd/socket/tcp.rs b/src/fd/socket/tcp.rs index eb68974ead..85aa598138 100644 --- a/src/fd/socket/tcp.rs +++ b/src/fd/socket/tcp.rs @@ -71,22 +71,28 @@ impl Socket { #[allow(clippy::needless_pass_by_ref_mut)] async fn async_read(&self, buffer: &mut [u8]) -> Result { future::poll_fn(|cx| { - self.with(|socket| { - if !socket.is_active() { - Poll::Ready(Err(-crate::errno::EIO)) - } else if socket.can_recv() { - Poll::Ready( - socket - .recv(|data| { - let len = core::cmp::min(buffer.len(), data.len()); - buffer[..len].copy_from_slice(&data[..len]); - (len, isize::try_from(len).unwrap()) - }) - .map_err(|_| -crate::errno::EIO), - ) - } else { - socket.register_recv_waker(cx.waker()); - Poll::Pending + self.with(|socket| match socket.state() { + tcp::State::FinWait1 + | tcp::State::FinWait2 + | tcp::State::Closed + | tcp::State::Closing + | tcp::State::CloseWait + | tcp::State::TimeWait => Poll::Ready(Err(-crate::errno::EIO)), + _ => { + if socket.can_recv() { + Poll::Ready( + socket + .recv(|data| { + let len = core::cmp::min(buffer.len(), data.len()); + buffer[..len].copy_from_slice(&data[..len]); + (len, isize::try_from(len).unwrap()) + }) + .map_err(|_| -crate::errno::EIO), + ) + } else { + socket.register_recv_waker(cx.waker()); + Poll::Pending + } } }) }) @@ -99,21 +105,29 @@ impl Socket { while pos < buffer.len() { let n = future::poll_fn(|cx| { self.with(|socket| { - if !socket.is_active() { - Poll::Ready(Err(-crate::errno::EIO)) - } else if socket.can_send() { - Poll::Ready( - socket - .send_slice(&buffer[pos..]) - .map_err(|_| -crate::errno::EIO), - ) - } else if pos > 0 { - // we already send some data => return 0 as signal to stop the - // async write - Poll::Ready(Ok(0)) - } else { - socket.register_send_waker(cx.waker()); - Poll::Pending + match socket.state() { + tcp::State::FinWait1 + | tcp::State::FinWait2 + | tcp::State::Closed + | tcp::State::Closing + | tcp::State::CloseWait + | tcp::State::TimeWait => Poll::Ready(Err(-crate::errno::EIO)), + _ => { + if socket.can_send() { + Poll::Ready( + socket + .send_slice(&buffer[pos..]) + .map_err(|_| -crate::errno::EIO), + ) + } else if pos > 0 { + // we already send some data => return 0 as signal to stop the + // async write + Poll::Ready(Ok(0)) + } else { + socket.register_send_waker(cx.waker()); + Poll::Pending + } + } } }) }) From 73de27b6df924d2dba20092fbd7fdfcd70e7b0a7 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Sun, 3 Sep 2023 20:34:48 +0200 Subject: [PATCH 2/2] read should return 0 if socket is in state closed/closing --- src/fd/socket/tcp.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/fd/socket/tcp.rs b/src/fd/socket/tcp.rs index 85aa598138..01cb4f9069 100644 --- a/src/fd/socket/tcp.rs +++ b/src/fd/socket/tcp.rs @@ -72,11 +72,12 @@ impl Socket { async fn async_read(&self, buffer: &mut [u8]) -> Result { future::poll_fn(|cx| { self.with(|socket| match socket.state() { + tcp::State::Closed | tcp::State::Closing | tcp::State::CloseWait => { + Poll::Ready(Ok(0)) + } tcp::State::FinWait1 | tcp::State::FinWait2 - | tcp::State::Closed - | tcp::State::Closing - | tcp::State::CloseWait + | tcp::State::Listen | tcp::State::TimeWait => Poll::Ready(Err(-crate::errno::EIO)), _ => { if socket.can_recv() { @@ -106,11 +107,12 @@ impl Socket { let n = future::poll_fn(|cx| { self.with(|socket| { match socket.state() { + tcp::State::Closed | tcp::State::Closing | tcp::State::CloseWait => { + Poll::Ready(Ok(0)) + } tcp::State::FinWait1 | tcp::State::FinWait2 - | tcp::State::Closed - | tcp::State::Closing - | tcp::State::CloseWait + | tcp::State::Listen | tcp::State::TimeWait => Poll::Ready(Err(-crate::errno::EIO)), _ => { if socket.can_send() {