From 20f27507fd155926e4d6baf17a26cd7109e86663 Mon Sep 17 00:00:00 2001 From: Kevin Abramczyk Date: Tue, 10 Nov 2026 21:52:29 -0500 Subject: [PATCH 1/2] Detect a peer reset in half_closed (bsd). On freebsd a peer reset drops the connection, so the TCP_INFO query fails with ECONNRESET (an unconnected socket succeeds with TCPS_CLOSED). The failure is now reported as a reset. The peer reset test now also runs on bsd (verified on freebsd 15.1). --- include/bitcoin/network/io/socket.hpp | 2 +- src/io/socket.cpp | 4 ++++ test/io/socket.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/bitcoin/network/io/socket.hpp b/include/bitcoin/network/io/socket.hpp index 5184c4282..998a3a771 100644 --- a/include/bitcoin/network/io/socket.hpp +++ b/include/bitcoin/network/io/socket.hpp @@ -115,7 +115,7 @@ class BCT_API socket size_t available(code& ec) const NOEXCEPT; /// The peer has closed its side of the connection (FIN received), - /// or reset it (RST received, linux, macos and windows). + /// or reset it (RST received, linux, macos, windows and bsd). bool half_closed() const NOEXCEPT; endpoint local_endpoint(code& ec) const NOEXCEPT; diff --git a/src/io/socket.cpp b/src/io/socket.cpp index 167d09281..ecdca13d2 100644 --- a/src/io/socket.cpp +++ b/src/io/socket.cpp @@ -405,6 +405,10 @@ bool socket::half_closed() const NOEXCEPT if (is_zero(::getsockopt(descriptor_->handle, IPPROTO_TCP, TCP_INFO, &info, &size))) return info.tcpi_state == TCPS_CLOSE_WAIT; + + // A reset connection is dropped, so the query fails. + if (last_error() == ECONNRESET) + return true; #endif return false; } diff --git a/test/io/socket.cpp b/test/io/socket.cpp index 0c5d14a60..fd4bc08e0 100644 --- a/test/io/socket.cpp +++ b/test/io/socket.cpp @@ -459,7 +459,7 @@ BC_AUTO_TEST_CASE(io_socket__half_closed__peer_shutdown_with_unread_data__true) BC_REQUIRE(!ec); } -#if defined(HAVE_LINUX) || defined(HAVE_APPLE) || defined(HAVE_WINDOWS) +#if defined(HAVE_LINUX) || defined(HAVE_APPLE) || defined(HAVE_WINDOWS) || defined(HAVE_BSD) BC_AUTO_TEST_CASE(io_socket__half_closed__peer_reset__true) { connected_pair connection{}; From f8fca44c9d13b40ef6746e3fe54a21f1efae7567 Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Fri, 13 Nov 2026 22:17:27 -0500 Subject: [PATCH 2/2] Drop platform list from peer reset detection. --- include/bitcoin/network/io/socket.hpp | 2 +- src/io/socket.cpp | 1 - test/io/socket.cpp | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/bitcoin/network/io/socket.hpp b/include/bitcoin/network/io/socket.hpp index 998a3a771..5bea556a1 100644 --- a/include/bitcoin/network/io/socket.hpp +++ b/include/bitcoin/network/io/socket.hpp @@ -115,7 +115,7 @@ class BCT_API socket size_t available(code& ec) const NOEXCEPT; /// The peer has closed its side of the connection (FIN received), - /// or reset it (RST received, linux, macos, windows and bsd). + /// or reset it (RST received). bool half_closed() const NOEXCEPT; endpoint local_endpoint(code& ec) const NOEXCEPT; diff --git a/src/io/socket.cpp b/src/io/socket.cpp index ecdca13d2..2c59740c3 100644 --- a/src/io/socket.cpp +++ b/src/io/socket.cpp @@ -406,7 +406,6 @@ bool socket::half_closed() const NOEXCEPT &info, &size))) return info.tcpi_state == TCPS_CLOSE_WAIT; - // A reset connection is dropped, so the query fails. if (last_error() == ECONNRESET) return true; #endif diff --git a/test/io/socket.cpp b/test/io/socket.cpp index fd4bc08e0..11b769b7c 100644 --- a/test/io/socket.cpp +++ b/test/io/socket.cpp @@ -459,7 +459,6 @@ BC_AUTO_TEST_CASE(io_socket__half_closed__peer_shutdown_with_unread_data__true) BC_REQUIRE(!ec); } -#if defined(HAVE_LINUX) || defined(HAVE_APPLE) || defined(HAVE_WINDOWS) || defined(HAVE_BSD) BC_AUTO_TEST_CASE(io_socket__half_closed__peer_reset__true) { connected_pair connection{}; @@ -474,7 +473,6 @@ BC_AUTO_TEST_CASE(io_socket__half_closed__peer_reset__true) BC_REQUIRE(half_closed_within(connection.accepted, 1000)); } -#endif BC_AUTO_TEST_CASE(io_socket__half_closed__opened_unconnected__false) {