diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 647e36adb3..687a5550ea 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -361,11 +361,13 @@ static bool HTTPBindAddresses(struct evhttp* http) { uint16_t http_port{static_cast(gArgs.GetIntArg("-rpcport", BaseParams().RPCPort()))}; std::vector> endpoints; + bool is_default = false; // Determine what addresses to bind to if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs endpoints.emplace_back("::1", http_port); endpoints.emplace_back("127.0.0.1", http_port); + is_default = true; if (gArgs.IsArgSet("-rpcallowip")) { LogPrintf("WARNING: option -rpcallowip was specified without -rpcbind; this doesn't usually make sense\n"); } @@ -382,6 +384,7 @@ static bool HTTPBindAddresses(struct evhttp* http) } // Bind addresses + int num_fail = 0; for (std::vector >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) { LogPrintf("Binding RPC on address %s port %i\n", 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); @@ -392,10 +395,27 @@ static bool HTTPBindAddresses(struct evhttp* http) } boundSockets.push_back(bind_handle); } else { - LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second); + int err = EVUTIL_SOCKET_ERROR(); + if (!is_default || (err != EADDRNOTAVAIL && err != ENOENT)) { + LogPrintf("Binding RPC on address %s port %i failed (Error: %s).\n", i->first, i->second, NetworkErrorString(err)); + num_fail += 1; + } else { + // Don't count failure if binding was not explicitly configured + // (default settings) and the address is not available. + // (for example: Travis without IPv6 localhost will return ENOENT) + LogPrintf("Binding RPC on address %s port %i failed, error ignored because interface was unavailable.\n", i->first, i->second); + } } } - return !boundSockets.empty(); + if (num_fail != 0) { + // In case of an error, clean up listening sockets that succeeded to + // avoid leak + for (evhttp_bound_socket *socket : boundSockets) { + evhttp_del_accept_socket(http, socket); + } + boundSockets.clear(); + } + return num_fail == 0; } /** Simple wrapper to set thread name and run work queue */ @@ -458,7 +478,7 @@ bool InitHTTPServer() evhttp_set_gencb(http, http_request_cb, nullptr); if (!HTTPBindAddresses(http)) { - LogPrintf("Unable to bind any endpoint for RPC server\n"); + LogPrintf("Unable to bind all endpoints for RPC server\n"); return false; } diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index dcea662089..1ca98c2669 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -182,7 +182,6 @@ class ConfArgsTest(BitcoinTestFramework): self.start_node(0, extra_args=[ '-addnode=some.node', '-rpcauth=alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc0', - '-rpcbind=127.1.1.1', '-rpcbind=127.0.0.1', "-rpcallowip=127.0.0.1", '-rpcpassword=',