From 2777bf4046487a40444b5fb101857700181fac6b Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 7 Apr 2026 16:47:36 -0700 Subject: [PATCH 1/3] Check liveness before returning socket --- libstuff/SSocketPool.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/libstuff/SSocketPool.cpp b/libstuff/SSocketPool.cpp index 1fae5ebfc..4518db4a9 100644 --- a/libstuff/SSocketPool.cpp +++ b/libstuff/SSocketPool.cpp @@ -51,16 +51,26 @@ void SSocketPool::_timeoutThreadFunc() unique_ptr SSocketPool::getSocket() { { - // If there's an existing socket, return it. lock_guard lock(_poolMutex); - if (_sockets.size()) { - pair> s = move(_sockets.front()); + while (_sockets.size()) { + auto s = move(_sockets.front()); _sockets.pop_front(); - return move(s.second); + + // Verify the socket is still alive before returning it. + if (s.second->state.load() == STCPManager::Socket::CONNECTED) { + struct pollfd pfd = {s.second->s, POLLIN | POLLOUT, 0}; + int ret = poll(&pfd, 1, 0); + if (ret >= 0 && !(pfd.revents & (POLLERR | POLLHUP | POLLNVAL))) { + return move(s.second); + } + } + + // Socket is dead, discard it (destructor closes fd). + SINFO("[SOCKET] Discarding stale socket from pool for host '" << host << "'."); } } - // If we get here, we need to create a socket to return. No need to hold the lock, so it goes out of scope. + // No live pooled socket available, create a new one. No need to hold the lock, so it goes out of scope. try { // TODO: Allow S_socket to take a parsed address instead of redoing all the parsing each time. return unique_ptr(new STCPManager::Socket(host)); From 191a544bb862b50a87f782ada96073a6a1ced6e8 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 7 Apr 2026 16:48:34 -0700 Subject: [PATCH 2/3] Only hold lock around popping socket --- libstuff/SSocketPool.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/libstuff/SSocketPool.cpp b/libstuff/SSocketPool.cpp index 4518db4a9..3e385d7b7 100644 --- a/libstuff/SSocketPool.cpp +++ b/libstuff/SSocketPool.cpp @@ -50,24 +50,28 @@ void SSocketPool::_timeoutThreadFunc() unique_ptr SSocketPool::getSocket() { - { - lock_guard lock(_poolMutex); - while (_sockets.size()) { - auto s = move(_sockets.front()); + while (true) { + unique_ptr socket; + { + lock_guard lock(_poolMutex); + if (_sockets.empty()) { + break; + } + socket = move(_sockets.front().second); _sockets.pop_front(); + } - // Verify the socket is still alive before returning it. - if (s.second->state.load() == STCPManager::Socket::CONNECTED) { - struct pollfd pfd = {s.second->s, POLLIN | POLLOUT, 0}; - int ret = poll(&pfd, 1, 0); - if (ret >= 0 && !(pfd.revents & (POLLERR | POLLHUP | POLLNVAL))) { - return move(s.second); - } + // Verify the socket is still alive before returning it. + if (socket->state.load() == STCPManager::Socket::CONNECTED) { + struct pollfd pfd = {socket->s, POLLIN | POLLOUT, 0}; + int ret = poll(&pfd, 1, 0); + if (ret >= 0 && !(pfd.revents & (POLLERR | POLLHUP | POLLNVAL))) { + return socket; } - - // Socket is dead, discard it (destructor closes fd). - SINFO("[SOCKET] Discarding stale socket from pool for host '" << host << "'."); } + + // Socket is dead, discard it (destructor closes fd). + SINFO("[SOCKET] Discarding stale socket from pool for host '" << host << "'."); } // No live pooled socket available, create a new one. No need to hold the lock, so it goes out of scope. From 81ca7fc939162c9a6ea893493de8402b6944c897 Mon Sep 17 00:00:00 2001 From: Tyler Karaszewski Date: Tue, 7 Apr 2026 16:59:11 -0700 Subject: [PATCH 3/3] Dont' skip verification on connecting sockets --- libstuff/SSocketPool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libstuff/SSocketPool.cpp b/libstuff/SSocketPool.cpp index 3e385d7b7..114a2ae2c 100644 --- a/libstuff/SSocketPool.cpp +++ b/libstuff/SSocketPool.cpp @@ -62,7 +62,7 @@ unique_ptr SSocketPool::getSocket() } // Verify the socket is still alive before returning it. - if (socket->state.load() == STCPManager::Socket::CONNECTED) { + if (socket->state.load() != STCPManager::Socket::CLOSED) { struct pollfd pfd = {socket->s, POLLIN | POLLOUT, 0}; int ret = poll(&pfd, 1, 0); if (ret >= 0 && !(pfd.revents & (POLLERR | POLLHUP | POLLNVAL))) {