#include <boost/iostreams/stream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
- #include <boost/asio/ssl.hpp>
+ #include <boost/asio/ssl.hpp>
#include <boost/filesystem/fstream.hpp>
-typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
+#include <boost/shared_ptr.hpp>
+#include <list>
#define printf OutputDebugStringF
// MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
}
- loop
+ // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets
+ const bool loopback = !mapArgs.count("-rpcallowip");
+ asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any();
+ ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
+
+ std::list< boost::shared_ptr<ip::tcp::acceptor> > acceptors;
+ try
{
- // Accept connection
- AcceptedConnection *conn =
- new AcceptedConnection(io_service, context, fUseSSL);
+ acceptors.push_back(boost::shared_ptr<ip::tcp::acceptor>(new ip::tcp::acceptor(io_service)));
+ acceptors.back()->open(endpoint.protocol());
+ acceptors.back()->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
- vnThreadsRunning[THREAD_RPCLISTENER]--;
- acceptor.accept(conn->sslStream.lowest_layer(), conn->peer);
- vnThreadsRunning[THREAD_RPCLISTENER]++;
+ // Try making the socket dual IPv6/IPv4 (if listening on the "any" address)
+ boost::system::error_code v6_only_error;
+ acceptors.back()->set_option(boost::asio::ip::v6_only(loopback), v6_only_error);
- if (fShutdown)
- {
- delete conn;
- return;
- }
+ acceptors.back()->bind(endpoint);
+ acceptors.back()->listen(socket_base::max_connections);
- // Restrict callers by IP. It is important to
- // do this before starting client thread, to filter out
- // certain DoS and misbehaving clients.
- if (!ClientAllowed(conn->peer.address().to_string()))
+ RPCListen(acceptors.back(), context, fUseSSL);
+
+ // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately
+ if (loopback || v6_only_error)
{
- // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
- if (!fUseSSL)
- conn->stream << HTTPReply(403, "", false) << std::flush;
- delete conn;
- }
+ bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any();
+ endpoint.address(bindAddress);
- // start HTTP client thread
- else if (!CreateThread(ThreadRPCServer3, conn)) {
- printf("Failed to create RPC server client thread\n");
- delete conn;
+ acceptors.push_back(boost::shared_ptr<ip::tcp::acceptor>(new ip::tcp::acceptor(io_service)));
+ acceptors.back()->open(endpoint.protocol());
+ acceptors.back()->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ acceptors.back()->bind(endpoint);
+ acceptors.back()->listen(socket_base::max_connections);
+
+ RPCListen(acceptors.back(), context, fUseSSL);
}
}
- uiInterface.QueueShutdown();
+ catch(boost::system::system_error &e)
+ {
+ uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
+ _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
- io_service.run();
++ StartShutdown();
+ return;
+ }
+
+ vnThreadsRunning[THREAD_RPCLISTENER]--;
++ while (!fShutdown)
++ io_service.run_one();
+ vnThreadsRunning[THREAD_RPCLISTENER]++;
+
+ // Terminate all outstanding accept-requests
+ BOOST_FOREACH(boost::shared_ptr<ip::tcp::acceptor>& acceptor, acceptors)
+ {
+ acceptor->cancel();
+ acceptor->close();
+ }
+ acceptors.clear();
}
void ThreadRPCServer3(void* parg)