Fix refused Windows TCP connections with a timeout (#3683)

This commit is contained in:
Aurantium🍊 authored and GitHub committed 2026-10-24 15:08:08 +03:00
1 parent bfa795e5aa
commit 9af9f48d3d
2 files changed
+56 -2

No files matched your search

+3 -2
View File
@@ -97,12 +97,13 @@ public:
return SOCKET_ERROR;
}
// Wait until socket is writable or timeout expires
// Wait until the connection succeeds, fails, or times out.
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(sockfd, &wfds);
fd_set efds = wfds;
rv = ::select(0, nullptr, &wfds, nullptr, const_cast<timeval *>(&tv));
rv = ::select(0, nullptr, &wfds, &efds, const_cast<timeval *>(&tv));
// Restore blocking mode regardless of select result
mode = 0UL;
+53
View File
@@ -63,4 +63,57 @@ TEST_CASE("tcp_client timeout supports high file descriptors", "[tcp_sink]") {
REQUIRE(client.connect_socket_with_timeout(
high_fd.fd, reinterpret_cast<sockaddr *>(&addr), addr_len, 1000) == 0);
}
#else
#include <spdlog/details/tcp_client-windows.h>
struct socket_guard {
explicit socket_guard(SOCKET value)
: fd(value) {}
~socket_guard() {
if (fd != INVALID_SOCKET) ::closesocket(fd);
}
SOCKET fd;
};
TEST_CASE("tcp_client timeout reports refused Windows connections", "[tcp_sink]") {
spdlog::details::tcp_client client;
socket_guard bound(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
REQUIRE(bound.fd != INVALID_SOCKET);
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
REQUIRE(::bind(bound.fd, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) == 0);
int addr_len = sizeof(addr);
REQUIRE(::getsockname(bound.fd, reinterpret_cast<sockaddr *>(&addr), &addr_len) == 0);
socket_guard outbound(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
REQUIRE(outbound.fd != INVALID_SOCKET);
timeval timeout{3, 0};
auto result = client.connect_socket_with_timeout(
outbound.fd, reinterpret_cast<sockaddr *>(&addr), addr_len, timeout);
auto error = ::WSAGetLastError();
REQUIRE(result == SOCKET_ERROR);
REQUIRE(error == WSAECONNREFUSED);
}
TEST_CASE("tcp_client timeout connects to Windows listeners", "[tcp_sink]") {
spdlog::details::tcp_client client;
socket_guard listener(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
REQUIRE(listener.fd != INVALID_SOCKET);
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
REQUIRE(::bind(listener.fd, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) == 0);
REQUIRE(::listen(listener.fd, 1) == 0);
int addr_len = sizeof(addr);
REQUIRE(::getsockname(listener.fd, reinterpret_cast<sockaddr *>(&addr), &addr_len) == 0);
socket_guard outbound(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
REQUIRE(outbound.fd != INVALID_SOCKET);
timeval timeout{3, 0};
REQUIRE(client.connect_socket_with_timeout(outbound.fd, reinterpret_cast<sockaddr *>(&addr),
addr_len, timeout) == 0);
}
#endif