From 943069b2a3eb6fb78dd91ed9bd0cfadd572626fb Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 3 Jun 2025 10:24:44 +0300 Subject: [PATCH] Kernel: Socket EPIPE and send SIGPIPE on write after hang up --- kernel/kernel/Networking/TCPSocket.cpp | 8 ++++++++ kernel/kernel/OpenFileDescriptorSet.cpp | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/kernel/kernel/Networking/TCPSocket.cpp b/kernel/kernel/Networking/TCPSocket.cpp index 0ca588c1..1514b82f 100644 --- a/kernel/kernel/Networking/TCPSocket.cpp +++ b/kernel/kernel/Networking/TCPSocket.cpp @@ -439,6 +439,8 @@ namespace Kernel LockGuard _(m_mutex); + const bool hungup_before = has_hungup_impl(); + auto& header = buffer.as(); dprintln_if(DEBUG_TCP, "receiving {} {8b}", (uint8_t)m_state, header.flags); dprintln_if(DEBUG_TCP, " {}", (uint32_t)header.ack_number); @@ -609,6 +611,9 @@ namespace Kernel } } + if (!hungup_before && has_hungup_impl()) + epoll_notify(EPOLLHUP); + m_thread_blocker.unblock(); } @@ -690,9 +695,12 @@ namespace Kernel auto target_address_len = m_connection_info->address_len; if (auto ret = m_network_layer.sendto(*this, {}, target_address, target_address_len); ret.is_error()) dwarnln("{}", ret.error()); + const bool hungup_before = has_hungup_impl(); m_state = m_next_state; if (m_state == State::Established) m_has_connected = true; + if (!hungup_before && has_hungup_impl()) + epoll_notify(EPOLLHUP); continue; } diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index fd71238a..309f69f7 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -476,14 +476,25 @@ namespace Kernel LockGuard _(inode->m_mutex); - if (is_nonblock && !inode->can_write()) - return BAN::Error::from_errno(EWOULDBLOCK); + const auto check_errors = + [&inode, is_nonblock]() -> BAN::ErrorOr + { + if (inode->has_hungup()) + { + Thread::current().add_signal(SIGPIPE); + return BAN::Error::from_errno(EPIPE); + } + if (is_nonblock && !inode->can_write()) + return BAN::Error::from_errno(EWOULDBLOCK); + return {}; + }; + + TRY(check_errors()); size_t total_sent = 0; while (total_sent < buffer.size()) { - if (is_nonblock && !inode->can_write()) - return total_sent; + TRY(check_errors()); const size_t nsend = TRY(inode->sendto(buffer.slice(total_sent), address, address_len)); if (nsend == 0) return 0;