@ -39,6 +39,7 @@ static ssl::context* rpc_ssl_context = NULL;
static boost : : thread_group * rpc_worker_group = NULL ;
static boost : : thread_group * rpc_worker_group = NULL ;
static boost : : asio : : io_service : : work * rpc_dummy_work = NULL ;
static boost : : asio : : io_service : : work * rpc_dummy_work = NULL ;
static std : : vector < CSubNet > rpc_allow_subnets ; //!< List of subnets to allow RPC connections from
static std : : vector < CSubNet > rpc_allow_subnets ; //!< List of subnets to allow RPC connections from
static std : : vector < boost : : shared_ptr < ip : : tcp : : acceptor > > rpc_acceptors ;
void RPCTypeCheck ( const Array & params ,
void RPCTypeCheck ( const Array & params ,
const list < Value_type > & typesExpected ,
const list < Value_type > & typesExpected ,
@ -444,7 +445,7 @@ template <typename Protocol, typename SocketAcceptorService>
static void RPCAcceptHandler ( boost : : shared_ptr < basic_socket_acceptor < Protocol , SocketAcceptorService > > acceptor ,
static void RPCAcceptHandler ( boost : : shared_ptr < basic_socket_acceptor < Protocol , SocketAcceptorService > > acceptor ,
ssl : : context & context ,
ssl : : context & context ,
bool fUseSSL ,
bool fUseSSL ,
AcceptedConnection * conn ,
boost : : shared_ptr < AcceptedConnection > conn ,
const boost : : system : : error_code & error ) ;
const boost : : system : : error_code & error ) ;
/**
/**
@ -456,7 +457,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketA
const bool fUseSSL )
const bool fUseSSL )
{
{
// Accept connection
// Accept connection
AcceptedConnectionImpl < Protocol > * conn = new AcceptedConnectionImpl < Protocol > ( acceptor - > get_io_service ( ) , context , fUseSSL ) ;
boost : : shared_ptr < AcceptedConnectionImpl < Protocol > > conn ( new AcceptedConnectionImpl < Protocol > ( acceptor - > get_io_service ( ) , context , fUseSSL ) ) ;
acceptor - > async_accept (
acceptor - > async_accept (
conn - > sslStream . lowest_layer ( ) ,
conn - > sslStream . lowest_layer ( ) ,
@ -466,7 +467,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketA
boost : : ref ( context ) ,
boost : : ref ( context ) ,
fUseSSL ,
fUseSSL ,
conn ,
conn ,
boost : : asio : : placeholders : : error ) ) ;
_1 ) ) ;
}
}
@ -477,21 +478,20 @@ template <typename Protocol, typename SocketAcceptorService>
static void RPCAcceptHandler ( boost : : shared_ptr < basic_socket_acceptor < Protocol , SocketAcceptorService > > acceptor ,
static void RPCAcceptHandler ( boost : : shared_ptr < basic_socket_acceptor < Protocol , SocketAcceptorService > > acceptor ,
ssl : : context & context ,
ssl : : context & context ,
const bool fUseSSL ,
const bool fUseSSL ,
AcceptedConnection * conn ,
boost : : shared_ptr < AcceptedConnection > conn ,
const boost : : system : : error_code & error )
const boost : : system : : error_code & error )
{
{
// Immediately start accepting new connections, except when we're cancelled or our socket is closed.
// Immediately start accepting new connections, except when we're cancelled or our socket is closed.
if ( error ! = asio : : error : : operation_aborted & & acceptor - > is_open ( ) )
if ( error ! = asio : : error : : operation_aborted & & acceptor - > is_open ( ) )
RPCListen ( acceptor , context , fUseSSL ) ;
RPCListen ( acceptor , context , fUseSSL ) ;
AcceptedConnectionImpl < ip : : tcp > * tcp_conn = dynamic_cast < AcceptedConnectionImpl < ip : : tcp > * > ( conn ) ;
AcceptedConnectionImpl < ip : : tcp > * tcp_conn = dynamic_cast < AcceptedConnectionImpl < ip : : tcp > * > ( conn . get ( ) ) ;
// TODO: Actually handle errors
if ( error )
if ( error )
{
{
delete conn ;
// TODO: Actually handle errors
LogPrintf ( " %s: Error: %s \n " , __func__ , error . message ( ) ) ;
}
}
// Restrict callers by IP. It is important to
// Restrict callers by IP. It is important to
// do this before starting client thread, to filter out
// do this before starting client thread, to filter out
// certain DoS and misbehaving clients.
// certain DoS and misbehaving clients.
@ -500,12 +500,11 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
if ( ! fUseSSL )
if ( ! fUseSSL )
conn - > stream ( ) < < HTTPReply ( HTTP_FORBIDDEN , " " , false ) < < std : : flush ;
conn - > stream ( ) < < HTTPReply ( HTTP_FORBIDDEN , " " , false ) < < std : : flush ;
delete conn ;
conn - > close ( ) ;
}
}
else {
else {
ServiceConnection ( conn ) ;
ServiceConnection ( conn . get ( ) ) ;
conn - > close ( ) ;
conn - > close ( ) ;
delete conn ;
}
}
}
}
@ -595,12 +594,13 @@ void StartRPCThreads()
asio : : ip : : address bindAddress = loopback ? asio : : ip : : address_v6 : : loopback ( ) : asio : : ip : : address_v6 : : any ( ) ;
asio : : ip : : address bindAddress = loopback ? asio : : ip : : address_v6 : : loopback ( ) : asio : : ip : : address_v6 : : any ( ) ;
ip : : tcp : : endpoint endpoint ( bindAddress , GetArg ( " -rpcport " , Params ( ) . RPCPort ( ) ) ) ;
ip : : tcp : : endpoint endpoint ( bindAddress , GetArg ( " -rpcport " , Params ( ) . RPCPort ( ) ) ) ;
boost : : system : : error_code v6_only_error ;
boost : : system : : error_code v6_only_error ;
boost : : shared_ptr < ip : : tcp : : acceptor > acceptor ( new ip : : tcp : : acceptor ( * rpc_io_service ) ) ;
bool fListening = false ;
bool fListening = false ;
std : : string strerr ;
std : : string strerr ;
try
try
{
{
boost : : shared_ptr < ip : : tcp : : acceptor > acceptor ( new ip : : tcp : : acceptor ( * rpc_io_service ) ) ;
rpc_acceptors . push_back ( acceptor ) ;
acceptor - > open ( endpoint . protocol ( ) ) ;
acceptor - > open ( endpoint . protocol ( ) ) ;
acceptor - > set_option ( boost : : asio : : ip : : tcp : : acceptor : : reuse_address ( true ) ) ;
acceptor - > set_option ( boost : : asio : : ip : : tcp : : acceptor : : reuse_address ( true ) ) ;
@ -618,7 +618,6 @@ void StartRPCThreads()
{
{
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 ( ) ) ;
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 ( ) ) ;
}
}
try {
try {
// If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately
// If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately
if ( ! fListening | | loopback | | v6_only_error )
if ( ! fListening | | loopback | | v6_only_error )
@ -626,7 +625,8 @@ void StartRPCThreads()
bindAddress = loopback ? asio : : ip : : address_v4 : : loopback ( ) : asio : : ip : : address_v4 : : any ( ) ;
bindAddress = loopback ? asio : : ip : : address_v4 : : loopback ( ) : asio : : ip : : address_v4 : : any ( ) ;
endpoint . address ( bindAddress ) ;
endpoint . address ( bindAddress ) ;
acceptor . reset ( new ip : : tcp : : acceptor ( * rpc_io_service ) ) ;
boost : : shared_ptr < ip : : tcp : : acceptor > acceptor ( new ip : : tcp : : acceptor ( * rpc_io_service ) ) ;
rpc_acceptors . push_back ( acceptor ) ;
acceptor - > open ( endpoint . protocol ( ) ) ;
acceptor - > open ( endpoint . protocol ( ) ) ;
acceptor - > set_option ( boost : : asio : : ip : : tcp : : acceptor : : reuse_address ( true ) ) ;
acceptor - > set_option ( boost : : asio : : ip : : tcp : : acceptor : : reuse_address ( true ) ) ;
acceptor - > bind ( endpoint ) ;
acceptor - > bind ( endpoint ) ;
@ -670,7 +670,16 @@ void StopRPCThreads()
{
{
if ( rpc_io_service = = NULL ) return ;
if ( rpc_io_service = = NULL ) return ;
// First, cancel all timers and acceptors
// This is not done automatically by ->stop(), and in some cases the destructor of
// asio::io_service can hang if this is skipped.
BOOST_FOREACH ( const boost : : shared_ptr < ip : : tcp : : acceptor > & acceptor , rpc_acceptors )
acceptor - > cancel ( ) ;
rpc_acceptors . clear ( ) ;
BOOST_FOREACH ( const PAIRTYPE ( std : : string , boost : : shared_ptr < deadline_timer > ) & timer , deadlineTimers )
timer . second - > cancel ( ) ;
deadlineTimers . clear ( ) ;
deadlineTimers . clear ( ) ;
rpc_io_service - > stop ( ) ;
rpc_io_service - > stop ( ) ;
if ( rpc_worker_group ! = NULL )
if ( rpc_worker_group ! = NULL )
rpc_worker_group - > join_all ( ) ;
rpc_worker_group - > join_all ( ) ;