mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Universal Port (RIPD-160):
This changes the behavior and configuration specification of the listening ports that rippled uses to accept incoming connections for the supported protocols: peer (Peer Protocol), http (JSON-RPC over HTTP), https (JSON-RPC) over HTTPS, ws (Websockets Clients), and wss (Secure Websockets Clients). Each listening port is now capable of handshaking in multiple protocols specified in the configuration file (subject to some restrictions). Each port can be configured to provide its own SSL certificate, or to use a self-signed certificate. Ports can be configured to share settings, this allows multiple ports to use the same certificate or values. The list of ports is dynamic, administrators can open as few or as many ports as they like. Authentication settings such as user/password or admin user/admin password (for administrative commands on RPC or Websockets interfaces) can also be specified per-port. As the configuration file has changed significantly, administrators will need to update their ripple.cfg files and carefully review the documentation and new settings. Changes: * rippled-example.cfg updated with documentation and new example settings: All obsolete websocket, rpc, and peer configuration sections have been removed, the documentation updated, and a new documented set of example settings added. * HTTP::Writer abstraction for sending HTTP server requests and responses * HTTP::Handler handler improvements to support Universal Port * HTTP::Handler handler supports legacy Peer protocol handshakes * HTTP::Port uses shared_ptr<boost::asio::ssl::context> * HTTP::PeerImp and Overlay use ssl_bundle to support Universal Port * New JsonWriter to stream message and body through HTTP server * ServerHandler refactored to support Universal Port and legacy peers * ServerHandler Setup struct updated for Universal Port * Refactor some PeerFinder members * WSDoor and Websocket code stores and uses the HTTP::Port configuration * Websocket autotls class receives the current secure/plain SSL setting * Remove PeerDoor and obsolete Overlay peer accept code * Remove obsolete RPCDoor and synchronous RPC handling code * Remove other obsolete classes, types, and files * Command line tool uses ServerHandler Setup for port and authorization info * Fix handling of admin_user, admin_password in administrative commands * Fix adminRole to check credentials for Universal Port * Updated Overlay README.md * Overlay sends IP:port redirects on HTTP Upgrade peer connection requests: Incoming peers who handshake using the HTTP Upgrade mechanism don't get a slot, and always get HTTP Status 503 redirect containing a JSON content-body with a set of alternate IP and port addresses to try, learned from PeerFinder. A future commit related to the Hub and Spoke feature will change the response to grant the peer a slot when there are peer slots available. * HTTP responses to outgoing Peer connect requests parse redirect IP:ports: When the [overlay] configuration section (which is experimental) has http_handshake = 1, HTTP redirect responses will have the JSON content-body parsed to obtain the redirect IP:port addresses. * Use a single io_service for HTTP::Server and Overlay: This is necessary to allow HTTP::Server to pass sockets to and from Overlay and eventually Websockets. Unfortunately Websockets is not so easily changed to use an externally provided io_service. This will be addressed in a future commit, and is one step necessary ease the restriction on ports configured to offer Websocket protocols in the .cfg file.
This commit is contained in:
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/common/RippleSSLContext.h>
|
||||
#include <ripple/common/make_SSLContext.h>
|
||||
#include <ripple/server/JsonWriter.h>
|
||||
#include <ripple/overlay/impl/OverlayImpl.h>
|
||||
#include <ripple/overlay/impl/PeerDoor.h>
|
||||
#include <ripple/overlay/impl/PeerImp.h>
|
||||
#include <ripple/peerfinder/make_Manager.h>
|
||||
#include <beast/ByteOrder.h>
|
||||
@@ -100,8 +100,8 @@ OverlayImpl::Timer::on_timer (error_code ec)
|
||||
}
|
||||
|
||||
overlay_.m_peerFinder->once_per_second();
|
||||
overlay_.sendpeers();
|
||||
overlay_.autoconnect();
|
||||
overlay_.sendEndpoints();
|
||||
overlay_.autoConnect();
|
||||
|
||||
timer_.expires_from_now (std::chrono::seconds(1));
|
||||
timer_.async_wait(overlay_.strand_.wrap(std::bind(
|
||||
@@ -114,8 +114,8 @@ OverlayImpl::Timer::on_timer (error_code ec)
|
||||
OverlayImpl::OverlayImpl (
|
||||
Setup const& setup,
|
||||
Stoppable& parent,
|
||||
ServerHandler& serverHandler,
|
||||
Resource::Manager& resourceManager,
|
||||
SiteFiles::Manager& siteFiles,
|
||||
beast::File const& pathToDbFileOrDirectory,
|
||||
Resolver& resolver,
|
||||
boost::asio::io_service& io_service)
|
||||
@@ -125,6 +125,7 @@ OverlayImpl::OverlayImpl (
|
||||
, strand_ (io_service_)
|
||||
, setup_(setup)
|
||||
, journal_ (deprecatedLogs().journal("Overlay"))
|
||||
, serverHandler_(serverHandler)
|
||||
, m_resourceManager (resourceManager)
|
||||
, m_peerFinder (PeerFinder::make_Manager (*this, io_service,
|
||||
pathToDbFileOrDirectory, get_seconds_clock(),
|
||||
@@ -146,50 +147,113 @@ OverlayImpl::~OverlayImpl ()
|
||||
cond_.wait (lock, [this] { return list_.empty(); });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
OverlayImpl::accept (socket_type&& socket)
|
||||
OverlayImpl::onLegacyPeerHello (
|
||||
std::unique_ptr<beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
boost::asio::const_buffer buffer,
|
||||
boost::asio::ip::tcp::endpoint remote_address)
|
||||
{
|
||||
// An error getting an endpoint means the connection closed.
|
||||
// Just do nothing and the socket will be closed by the caller.
|
||||
boost::system::error_code ec;
|
||||
auto const local_endpoint_native (socket.local_endpoint (ec));
|
||||
if (ec)
|
||||
return;
|
||||
auto const remote_endpoint_native (socket.remote_endpoint (ec));
|
||||
error_code ec;
|
||||
auto const local_endpoint (ssl_bundle->socket.local_endpoint(ec));
|
||||
if (ec)
|
||||
return;
|
||||
|
||||
auto const local_endpoint (
|
||||
beast::IPAddressConversion::from_asio (local_endpoint_native));
|
||||
auto const remote_endpoint (
|
||||
beast::IPAddressConversion::from_asio (remote_endpoint_native));
|
||||
auto const slot = m_peerFinder->new_inbound_slot (
|
||||
beast::IPAddressConversion::from_asio(local_endpoint),
|
||||
beast::IPAddressConversion::from_asio(remote_address));
|
||||
|
||||
PeerFinder::Slot::ptr const slot (m_peerFinder->new_inbound_slot (
|
||||
local_endpoint, remote_endpoint));
|
||||
|
||||
if (slot == nullptr)
|
||||
return;
|
||||
|
||||
PeerImp::ptr const peer (std::make_shared <PeerImp> (
|
||||
std::move (socket), remote_endpoint, *this, m_resourceManager,
|
||||
*m_peerFinder, slot, setup_.context));
|
||||
|
||||
{
|
||||
std::lock_guard <decltype(mutex_)> lock (mutex_);
|
||||
{
|
||||
std::pair <PeersBySlot::iterator, bool> const result (
|
||||
m_peers.emplace (slot, peer));
|
||||
assert (result.second);
|
||||
(void) result.second;
|
||||
}
|
||||
list_.emplace(peer.get(), peer);
|
||||
|
||||
// This has to happen while holding the lock,
|
||||
// otherwise the socket might not be canceled during a stop.
|
||||
peer->start();
|
||||
}
|
||||
addpeer (std::make_shared<PeerImp>(std::move(ssl_bundle),
|
||||
boost::asio::const_buffers_1(buffer),
|
||||
beast::IPAddressConversion::from_asio(remote_address),
|
||||
*this, m_resourceManager, *m_peerFinder, slot));
|
||||
}
|
||||
|
||||
Handoff
|
||||
OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
|
||||
beast::http::message&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address)
|
||||
{
|
||||
Handoff handoff;
|
||||
if (! isPeerUpgrade(request))
|
||||
return handoff;
|
||||
|
||||
error_code ec;
|
||||
auto const local_endpoint (ssl_bundle->socket.local_endpoint(ec));
|
||||
if (ec)
|
||||
{
|
||||
// log?
|
||||
// Since we don't call std::move the socket will be closed.
|
||||
handoff.moved = false;
|
||||
return handoff;
|
||||
}
|
||||
|
||||
// TODO Validate HTTP request
|
||||
|
||||
auto const slot = m_peerFinder->new_inbound_slot (
|
||||
beast::IPAddressConversion::from_asio(local_endpoint),
|
||||
beast::IPAddressConversion::from_asio(remote_address));
|
||||
|
||||
#if 0
|
||||
if (slot == nullptr)
|
||||
#else
|
||||
// For now, always redirect.
|
||||
if (true)
|
||||
#endif
|
||||
{
|
||||
// Full, give them some addresses
|
||||
handoff.response = makeRedirectResponse(slot, request);
|
||||
handoff.keep_alive = request.keep_alive();
|
||||
return handoff;
|
||||
}
|
||||
|
||||
addpeer (std::make_shared<PeerImp>(std::move(ssl_bundle),
|
||||
std::move(request), beast::IPAddressConversion::from_asio(remote_address),
|
||||
*this, m_resourceManager, *m_peerFinder, slot));
|
||||
handoff.moved = true;
|
||||
return handoff;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
OverlayImpl::isPeerUpgrade(beast::http::message const& request)
|
||||
{
|
||||
if (! request.upgrade())
|
||||
return false;
|
||||
if (request.headers["Upgrade"] != "Ripple/1.2")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<HTTP::Writer>
|
||||
OverlayImpl::makeRedirectResponse (PeerFinder::Slot::ptr const& slot,
|
||||
beast::http::message const& request)
|
||||
{
|
||||
Json::Value json(Json::objectValue);
|
||||
{
|
||||
auto const result = m_peerFinder->redirect(slot);
|
||||
Json::Value& ips = (json["peer-ips"] = Json::arrayValue);
|
||||
for (auto const& _ : m_peerFinder->redirect(slot))
|
||||
ips.append(_.address.to_string());
|
||||
}
|
||||
|
||||
beast::http::message m;
|
||||
m.request(false);
|
||||
m.status(503);
|
||||
m.reason("Service Unavailable");
|
||||
m.version(request.version());
|
||||
if (request.version() == std::make_pair(1, 0))
|
||||
{
|
||||
//?
|
||||
}
|
||||
auto const response = HTTP::make_JsonWriter (m, json);
|
||||
return response;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
OverlayImpl::connect (beast::IP::Endpoint const& remote_endpoint)
|
||||
{
|
||||
@@ -201,24 +265,8 @@ OverlayImpl::connect (beast::IP::Endpoint const& remote_endpoint)
|
||||
if (slot == nullptr)
|
||||
return;
|
||||
|
||||
PeerImp::ptr const peer (std::make_shared <PeerImp> (
|
||||
remote_endpoint, io_service_, *this, m_resourceManager,
|
||||
*m_peerFinder, slot, setup_.context));
|
||||
|
||||
{
|
||||
std::lock_guard <decltype(mutex_)> lock (mutex_);
|
||||
{
|
||||
std::pair <PeersBySlot::iterator, bool> const result (
|
||||
m_peers.emplace (slot, peer));
|
||||
assert (result.second);
|
||||
(void) result.second;
|
||||
}
|
||||
list_.emplace(peer.get(), peer);
|
||||
|
||||
// This has to happen while holding the lock,
|
||||
// otherwise the socket might not be canceled during a stop.
|
||||
peer->start ();
|
||||
}
|
||||
addpeer (std::make_shared <PeerImp> (remote_endpoint, io_service_, *this,
|
||||
m_resourceManager, *m_peerFinder, slot, setup_.context));
|
||||
}
|
||||
|
||||
Peer::ShortId
|
||||
@@ -245,7 +293,7 @@ OverlayImpl::remove (PeerFinder::Slot::ptr const& slot)
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
OverlayImpl::onPrepare ()
|
||||
OverlayImpl::onPrepare()
|
||||
{
|
||||
PeerFinder::Config config;
|
||||
|
||||
@@ -254,22 +302,20 @@ OverlayImpl::onPrepare ()
|
||||
|
||||
config.outPeers = config.calcOutPeers();
|
||||
|
||||
config.wantIncoming =
|
||||
(! getConfig ().PEER_PRIVATE) &&
|
||||
(getConfig().peerListeningPort != 0);
|
||||
auto const port = serverHandler_.setup().overlay.port;
|
||||
|
||||
config.wantIncoming =
|
||||
(! getConfig ().PEER_PRIVATE) && (port != 0);
|
||||
// if it's a private peer or we are running as standalone
|
||||
// automatic connections would defeat the purpose.
|
||||
config.autoConnect =
|
||||
!getConfig().RUN_STANDALONE &&
|
||||
!getConfig().PEER_PRIVATE;
|
||||
|
||||
config.listeningPort = getConfig().peerListeningPort;
|
||||
|
||||
config.listeningPort = port;
|
||||
config.features = "";
|
||||
|
||||
// Enforce business rules
|
||||
config.applyTuning ();
|
||||
config.applyTuning();
|
||||
|
||||
m_peerFinder->setConfig (config);
|
||||
|
||||
@@ -311,14 +357,6 @@ OverlayImpl::onPrepare ()
|
||||
m_peerFinder->addFixedPeer (name, addresses);
|
||||
});
|
||||
}
|
||||
|
||||
// Configure the peer doors, which allow the server to accept incoming
|
||||
// peer connections:
|
||||
if (! getConfig ().RUN_STANDALONE)
|
||||
{
|
||||
m_doorDirect = make_PeerDoor (*this, getConfig ().PEER_IP,
|
||||
getConfig ().peerListeningPort, io_service_);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -334,11 +372,6 @@ OverlayImpl::onStart ()
|
||||
void
|
||||
OverlayImpl::onStop ()
|
||||
{
|
||||
if (m_doorDirect)
|
||||
m_doorDirect->stop();
|
||||
if (m_doorProxy)
|
||||
m_doorProxy->stop();
|
||||
|
||||
strand_.dispatch(std::bind(&OverlayImpl::close, this));
|
||||
}
|
||||
|
||||
@@ -470,6 +503,14 @@ OverlayImpl::remove (Child& child)
|
||||
checkStopped();
|
||||
}
|
||||
|
||||
// Caller must hold the mutex
|
||||
void
|
||||
OverlayImpl::checkStopped ()
|
||||
{
|
||||
if (isStopping() && areChildrenStopped () && list_.empty())
|
||||
stopped();
|
||||
}
|
||||
|
||||
void
|
||||
OverlayImpl::close()
|
||||
{
|
||||
@@ -487,19 +528,35 @@ OverlayImpl::close()
|
||||
}
|
||||
}
|
||||
|
||||
// Check for the stopped condition
|
||||
// Caller must hold the mutex
|
||||
void
|
||||
OverlayImpl::checkStopped ()
|
||||
OverlayImpl::addpeer (std::shared_ptr<PeerImp> const& peer)
|
||||
{
|
||||
if (isStopping() && areChildrenStopped () && list_.empty())
|
||||
stopped();
|
||||
std::lock_guard <decltype(mutex_)> lock (mutex_);
|
||||
{
|
||||
std::pair <PeersBySlot::iterator, bool> const result (
|
||||
m_peers.emplace (peer->slot(), peer));
|
||||
assert (result.second);
|
||||
(void) result.second;
|
||||
}
|
||||
list_.emplace(peer.get(), peer);
|
||||
|
||||
// This has to happen while holding the lock,
|
||||
// otherwise the socket might not be canceled during a stop.
|
||||
peer->start();
|
||||
}
|
||||
|
||||
void
|
||||
OverlayImpl::sendpeers()
|
||||
OverlayImpl::autoConnect()
|
||||
{
|
||||
auto const result = m_peerFinder->sendpeers();
|
||||
auto const result = m_peerFinder->autoconnect();
|
||||
for (auto addr : result)
|
||||
connect (addr);
|
||||
}
|
||||
|
||||
void
|
||||
OverlayImpl::sendEndpoints()
|
||||
{
|
||||
auto const result = m_peerFinder->buildEndpointsForPeers();
|
||||
for (auto const& e : result)
|
||||
{
|
||||
// VFALCO TODO Make sure this doesn't race with closing the peer
|
||||
@@ -515,13 +572,6 @@ OverlayImpl::sendpeers()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OverlayImpl::autoconnect()
|
||||
{
|
||||
auto const result = m_peerFinder->autoconnect();
|
||||
for (auto addr : result)
|
||||
connect (addr);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -540,7 +590,7 @@ setup_Overlay (BasicConfig const& config)
|
||||
setup.promote = Overlay::Promote::always;
|
||||
else
|
||||
setup.promote = Overlay::Promote::automatic;
|
||||
setup.context = make_ssl_context();
|
||||
setup.context = make_SSLContext();
|
||||
return setup;
|
||||
}
|
||||
|
||||
@@ -548,14 +598,14 @@ std::unique_ptr <Overlay>
|
||||
make_Overlay (
|
||||
Overlay::Setup const& setup,
|
||||
beast::Stoppable& parent,
|
||||
ServerHandler& serverHandler,
|
||||
Resource::Manager& resourceManager,
|
||||
SiteFiles::Manager& siteFiles,
|
||||
beast::File const& pathToDbFileOrDirectory,
|
||||
Resolver& resolver,
|
||||
boost::asio::io_service& io_service)
|
||||
{
|
||||
return std::make_unique <OverlayImpl> (setup, parent, resourceManager,
|
||||
siteFiles, pathToDbFileOrDirectory, resolver, io_service);
|
||||
return std::make_unique <OverlayImpl> (setup, parent, serverHandler,
|
||||
resourceManager, pathToDbFileOrDirectory, resolver, io_service);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user