Skip to content

Commit 53d9709

Browse files
committed
Merge pull request #4142
cef4494 rpc: keep track of acceptors, and cancel them in StopRPCThreads (Wladimir J. van der Laan) 381b25d doc: remove mention of `-rpctimeout` from man page (Wladimir J. van der Laan) 1a44522 rpc: Make sure conn object is always cleaned up (Wladimir J. van der Laan) 0a0cd34 rpc: pass errors from async_accept (Wladimir J. van der Laan)
2 parents c3ad56f + cef4494 commit 53d9709

File tree

2 files changed

+23
-17
lines changed

2 files changed

+23
-17
lines changed

contrib/debian/manpages/bitcoin.conf.5

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ You must set *rpcuser* to secure the JSON-RPC api.
3737
\fBrpcpassword=\fR\fI'password'\fR
3838
You must set *rpcpassword* to secure the JSON-RPC api.
3939
.TP
40-
\fBrpctimeout=\fR\fI'30'\fR
41-
How many seconds *bitcoin* will wait for a complete RPC HTTP request, after the HTTP connection is established.
42-
.TP
4340
\fBrpcallowip=\fR\fI'192.168.1.*'\fR
4441
By default, only RPC connections from localhost are allowed. Specify as many *rpcallowip=* settings as you like to allow connections from other hosts (and you may use * as a wildcard character).
4542
.TP

src/rpcserver.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static ssl::context* rpc_ssl_context = NULL;
3939
static boost::thread_group* rpc_worker_group = NULL;
4040
static boost::asio::io_service::work *rpc_dummy_work = NULL;
4141
static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
42+
static std::vector< boost::shared_ptr<ip::tcp::acceptor> > rpc_acceptors;
4243

4344
void RPCTypeCheck(const Array& params,
4445
const list<Value_type>& typesExpected,
@@ -444,7 +445,7 @@ template <typename Protocol, typename SocketAcceptorService>
444445
static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
445446
ssl::context& context,
446447
bool fUseSSL,
447-
AcceptedConnection* conn,
448+
boost::shared_ptr< AcceptedConnection > conn,
448449
const boost::system::error_code& error);
449450

450451
/**
@@ -456,7 +457,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketA
456457
const bool fUseSSL)
457458
{
458459
// Accept connection
459-
AcceptedConnectionImpl<Protocol>* conn = new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL);
460+
boost::shared_ptr< AcceptedConnectionImpl<Protocol> > conn(new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL));
460461

461462
acceptor->async_accept(
462463
conn->sslStream.lowest_layer(),
@@ -466,7 +467,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketA
466467
boost::ref(context),
467468
fUseSSL,
468469
conn,
469-
boost::asio::placeholders::error));
470+
_1));
470471
}
471472

472473

@@ -477,21 +478,20 @@ template <typename Protocol, typename SocketAcceptorService>
477478
static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
478479
ssl::context& context,
479480
const bool fUseSSL,
480-
AcceptedConnection* conn,
481+
boost::shared_ptr< AcceptedConnection > conn,
481482
const boost::system::error_code& error)
482483
{
483484
// Immediately start accepting new connections, except when we're cancelled or our socket is closed.
484485
if (error != asio::error::operation_aborted && acceptor->is_open())
485486
RPCListen(acceptor, context, fUseSSL);
486487

487-
AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn);
488+
AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn.get());
488489

489-
// TODO: Actually handle errors
490490
if (error)
491491
{
492-
delete conn;
492+
// TODO: Actually handle errors
493+
LogPrintf("%s: Error: %s\n", __func__, error.message());
493494
}
494-
495495
// Restrict callers by IP. It is important to
496496
// do this before starting client thread, to filter out
497497
// certain DoS and misbehaving clients.
@@ -500,12 +500,11 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
500500
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
501501
if (!fUseSSL)
502502
conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
503-
delete conn;
503+
conn->close();
504504
}
505505
else {
506-
ServiceConnection(conn);
506+
ServiceConnection(conn.get());
507507
conn->close();
508-
delete conn;
509508
}
510509
}
511510

@@ -595,12 +594,13 @@ void StartRPCThreads()
595594
asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any();
596595
ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", Params().RPCPort()));
597596
boost::system::error_code v6_only_error;
598-
boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
599597

600598
bool fListening = false;
601599
std::string strerr;
602600
try
603601
{
602+
boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
603+
rpc_acceptors.push_back(acceptor);
604604
acceptor->open(endpoint.protocol());
605605
acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
606606

@@ -618,15 +618,15 @@ void StartRPCThreads()
618618
{
619619
strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what());
620620
}
621-
622621
try {
623622
// If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately
624623
if (!fListening || loopback || v6_only_error)
625624
{
626625
bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any();
627626
endpoint.address(bindAddress);
628627

629-
acceptor.reset(new ip::tcp::acceptor(*rpc_io_service));
628+
boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
629+
rpc_acceptors.push_back(acceptor);
630630
acceptor->open(endpoint.protocol());
631631
acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
632632
acceptor->bind(endpoint);
@@ -670,7 +670,16 @@ void StopRPCThreads()
670670
{
671671
if (rpc_io_service == NULL) return;
672672

673+
// First, cancel all timers and acceptors
674+
// This is not done automatically by ->stop(), and in some cases the destructor of
675+
// asio::io_service can hang if this is skipped.
676+
BOOST_FOREACH(const boost::shared_ptr<ip::tcp::acceptor> &acceptor, rpc_acceptors)
677+
acceptor->cancel();
678+
rpc_acceptors.clear();
679+
BOOST_FOREACH(const PAIRTYPE(std::string, boost::shared_ptr<deadline_timer>) &timer, deadlineTimers)
680+
timer.second->cancel();
673681
deadlineTimers.clear();
682+
674683
rpc_io_service->stop();
675684
if (rpc_worker_group != NULL)
676685
rpc_worker_group->join_all();

0 commit comments

Comments
 (0)