refactor: split HTTPBindAddresses into config parse and libevent setup

The original function was already naturally split into two chunks:
First, we parse and validate the users' RPC configuration for IPs and
ports. Next we bind libevent's http server to the appropriate
endpoints.

This commit splits these chunks into two separate functions, leaving
the argument parsing in the common space of the module and moving the
libevent-specific binding into the http_libevent namespace.

A future commit will implement http_bitcoin::HTTPBindAddresses to
bind the validate list of endpoints by the new HTTP server.
This commit is contained in:
Matthew Zipkin
2025-01-15 14:26:36 -05:00
parent fec6b6bca8
commit 2ca645c2e4

View File

@@ -322,8 +322,7 @@ static void ThreadHTTP(struct event_base* base)
LogDebug(BCLog::HTTP, "Exited http event loop\n");
}
/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp* http)
static std::vector<std::pair<std::string, uint16_t>> GetBindAddresses()
{
uint16_t http_port{static_cast<uint16_t>(gArgs.GetIntArg("-rpcport", BaseParams().RPCPort()))};
std::vector<std::pair<std::string, uint16_t>> endpoints;
@@ -348,33 +347,12 @@ static bool HTTPBindAddresses(struct evhttp* http)
std::string host;
if (!SplitHostPort(strRPCBind, port, host)) {
LogError("%s\n", InvalidPortErrMsg("-rpcbind", strRPCBind).original);
return false;
return {}; // empty
}
endpoints.emplace_back(host, port);
}
}
// Bind addresses
for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
LogInfo("Binding RPC on address %s port %i", i->first, i->second);
evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second);
if (bind_handle) {
const std::optional<CNetAddr> addr{LookupHost(i->first, false)};
if (i->first.empty() || (addr.has_value() && addr->IsBindAny())) {
LogWarning("The RPC server is not safe to expose to untrusted networks such as the public internet");
}
// Set the no-delay option (disable Nagle's algorithm) on the TCP socket.
evutil_socket_t fd = evhttp_bound_socket_get_fd(bind_handle);
int one = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&one), sizeof(one)) == SOCKET_ERROR) {
LogInfo("WARNING: Unable to set TCP_NODELAY on RPC server socket, continuing anyway\n");
}
boundSockets.push_back(bind_handle);
} else {
LogWarning("Binding RPC on address %s port %i failed.", i->first, i->second);
}
}
return !boundSockets.empty();
return endpoints;
}
/** libevent event log callback */
@@ -397,6 +375,32 @@ static void libevent_log_cb(int severity, const char *msg)
}
namespace http_libevent {
/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp* http)
{
std::vector<std::pair<std::string, uint16_t>> endpoints{GetBindAddresses()};
for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
LogInfo("Binding RPC on address %s port %i", i->first, i->second);
evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second);
if (bind_handle) {
const std::optional<CNetAddr> addr{LookupHost(i->first, false)};
if (i->first.empty() || (addr.has_value() && addr->IsBindAny())) {
LogWarning("The RPC server is not safe to expose to untrusted networks such as the public internet");
}
// Set the no-delay option (disable Nagle's algorithm) on the TCP socket.
evutil_socket_t fd = evhttp_bound_socket_get_fd(bind_handle);
int one = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&one), sizeof(one)) == SOCKET_ERROR) {
LogInfo("WARNING: Unable to set TCP_NODELAY on RPC server socket, continuing anyway");
}
boundSockets.push_back(bind_handle);
} else {
LogWarning("Binding RPC on address %s port %i failed.", i->first, i->second);
}
}
return !boundSockets.empty();
}
bool InitHTTPServer(const util::SignalInterrupt& interrupt)
{
if (!InitHTTPAllowList())