http: disconnect after idle timeout (-rpcservertimeout)

This commit is contained in:
Matthew Zipkin 2025-03-10 13:30:52 -04:00
parent 84e1818563
commit b90f808e30
No known key found for this signature in database
GPG key ID: E7E2984B6289C93A
2 changed files with 19 additions and 1 deletions

View file

@ -19,6 +19,7 @@
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/threadnames.h>
#include <util/time.h>
#include <util/translation.h>
#include <condition_variable>
@ -1204,8 +1205,11 @@ void HTTPServer::CloseConnectionInternal(std::shared_ptr<HTTPClient>& client)
void HTTPServer::DisconnectClients()
{
const auto now{Now<SteadySeconds>()};
for (auto it = m_connected_clients.begin(); it != m_connected_clients.end();) {
if ((it->second->m_disconnect || m_disconnect_all_clients) && !it->second->m_prevent_disconnect) {
bool timeout{now - it->second->m_idle_since > m_rpcservertimeout};
if (((it->second->m_disconnect || m_disconnect_all_clients) && !it->second->m_prevent_disconnect)
|| timeout) {
CloseConnectionInternal(it->second);
it = m_connected_clients.erase(it);
} else {
@ -1222,6 +1226,8 @@ bool HTTPServer::EventNewConnectionAccepted(NodeId node_id,
auto client = std::make_shared<HTTPClient>(node_id, them);
// Point back to the server
client->m_server = this;
// Set timeout
client->m_idle_since = Now<SteadySeconds>();
LogDebug(BCLog::HTTP, "HTTP Connection accepted from %s (id=%d)\n", client->m_origin, client->m_node_id);
m_connected_clients.emplace(client->m_node_id, std::move(client));
m_no_clients = false;
@ -1253,6 +1259,9 @@ void HTTPServer::EventGotData(NodeId node_id, std::span<const uint8_t> data)
return;
}
// Reset idle timeout
client->m_idle_since = Now<SteadySeconds>();
// Prevent disconnect until all requests are completely handled.
client->m_prevent_disconnect = true;
@ -1385,6 +1394,8 @@ bool InitHTTPServer(const util::SignalInterrupt& interrupt)
// 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->m_rpcservertimeout = 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};

View file

@ -15,6 +15,7 @@
#include <common/sockman.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
namespace util {
class SignalInterrupt;
@ -339,6 +340,9 @@ public:
// Checked at the end of every Sockman I/O loop, may be set a worker thread.
std::atomic_bool m_disconnect{false};
// Timestamp of last receive activity, used for -rpcservertimeout
SteadySeconds m_idle_since;
explicit HTTPClient(NodeId node_id, CService addr) : m_node_id(node_id), m_addr(addr)
{
m_origin = addr.ToStringAddrPort();
@ -383,6 +387,9 @@ public:
// Set by main thread and read by Sockman I/O thread
std::atomic_bool m_disconnect_all_clients{false};
// Idle timeout after which clients are disconnected
std::chrono::seconds m_rpcservertimeout{DEFAULT_HTTP_SERVER_TIMEOUT};
/**
* Be notified when a new connection has been accepted.
* @param[in] node_id Id of the newly accepted connection.