HTTPServer: disconnect after idle timeout (-rpcservertimeout)

This commit is contained in:
Matthew Zipkin
2025-03-10 13:30:52 -04:00
parent e5f242eef3
commit cbb8d1fb33
2 changed files with 44 additions and 4 deletions

View File

@@ -24,6 +24,7 @@
#include <util/thread.h>
#include <util/threadnames.h>
#include <util/threadpool.h>
#include <util/time.h>
#include <util/translation.h>
#include <condition_variable>
@@ -1360,6 +1361,9 @@ void HTTPServer::SocketHandlerConnected(const IOReadiness& io_readiness) const
client->m_id);
client->m_disconnect = true;
} else {
// Reset idle timeout
client->m_idle_since = Now<SteadySeconds>();
// Prevent disconnect until all requests are completely handled.
client->m_connection_busy = true;
@@ -1509,12 +1513,27 @@ void HTTPServer::MaybeDispatchRequestsFromClient(const std::shared_ptr<HTTPRemot
void HTTPServer::DisconnectClients()
{
const auto now{Now<SteadySeconds>()};
size_t erased = std::erase_if(m_connected,
[&](auto& client) {
// Disconnect this client due to error or end of communication.
// First check for idle timeout. We reset the timer when we send and receive data,
// but if the server is busy handling a request we should ignore the timeout until
// the reply is sent. If we did erase the shared_ptr<HTTPRemoteClient> reference in m_connected
// while the server is busy with a request, there would still be a reference in a worker
// thread keeping the socket open even after "disconnecting".
const bool is_idle{m_rpcservertimeout.count() > 0 &&
now - client->m_idle_since.load() > m_rpcservertimeout &&
!client->m_req_busy};
// Disconnect this client due to error, end of communication, or idle timeout.
// May drop unsent data if we are closing due to error.
if (client->m_disconnect) {
;
if (client->m_disconnect || is_idle) {
if (is_idle) {
LogDebug(BCLog::HTTP,
"HTTP client idle timeout %s (id=%llu)",
client->m_origin,
client->m_id);
}
} else {
// Disconnect this client because the server is shutting
// down and we need to disconnect all clients...
@@ -1652,6 +1671,9 @@ bool HTTPRemoteClient::MaybeSendBytesFromBuffer()
m_send_ready = true;
m_connection_busy = true;
}
// Finally, reset idle timeout
m_idle_since = Now<SteadySeconds>();
}
return true;
@@ -1666,6 +1688,8 @@ bool InitHTTPServer()
// Create HTTPServer, using a dummy request handler just for this commit
g_http_server = std::make_unique<HTTPServer>([&](std::unique_ptr<HTTPRequest> req){});
g_http_server->SetServerTimeout(std::chrono::seconds(gArgs.GetIntArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT)));
// Bind HTTP server to specified addresses
std::vector<std::pair<std::string, uint16_t>> endpoints{GetBindAddresses()};
bool bind_success{false};