Make PeerDoor implementation private

This commit is contained in:
Vinnie Falco
2013-07-10 09:51:04 -07:00
parent 2db798b38f
commit e4c02aa122
11 changed files with 251 additions and 188 deletions

View File

@@ -148,6 +148,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\modules\ripple_basio\boost\ripple_SslContext.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_basio\ripple_basio.cpp" /> <ClCompile Include="..\..\modules\ripple_basio\ripple_basio.cpp" />
<ClCompile Include="..\..\modules\ripple_client\ripple_client.cpp" /> <ClCompile Include="..\..\modules\ripple_client\ripple_client.cpp" />
<ClCompile Include="..\..\modules\ripple_core\functional\ripple_Config.cpp"> <ClCompile Include="..\..\modules\ripple_core\functional\ripple_Config.cpp">
@@ -1352,6 +1358,7 @@
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_Time.h" /> <ClInclude Include="..\..\modules\ripple_basics\utility\ripple_Time.h" />
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_UptimeTimer.h" /> <ClInclude Include="..\..\modules\ripple_basics\utility\ripple_UptimeTimer.h" />
<ClInclude Include="..\..\modules\ripple_basio\boost\ripple_IoService.h" /> <ClInclude Include="..\..\modules\ripple_basio\boost\ripple_IoService.h" />
<ClInclude Include="..\..\modules\ripple_basio\boost\ripple_SslContext.h" />
<ClInclude Include="..\..\modules\ripple_basio\ripple_basio.h" /> <ClInclude Include="..\..\modules\ripple_basio\ripple_basio.h" />
<ClInclude Include="..\..\modules\ripple_basio\ripple_basio_fwdecl.h" /> <ClInclude Include="..\..\modules\ripple_basio\ripple_basio_fwdecl.h" />
<ClInclude Include="..\..\modules\ripple_basio\ripple_basio_impl.h" /> <ClInclude Include="..\..\modules\ripple_basio\ripple_basio_impl.h" />

View File

@@ -849,6 +849,9 @@
<ClCompile Include="..\..\src\cpp\ripple\ripple_WSHandler.cpp"> <ClCompile Include="..\..\src\cpp\ripple\ripple_WSHandler.cpp">
<Filter>[1] Ripple\ripple_app\_network</Filter> <Filter>[1] Ripple\ripple_app\_network</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\modules\ripple_basio\boost\ripple_SslContext.cpp">
<Filter>[1] Ripple\ripple_basio\boost</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\Subtrees\sqlite\sqlite3.h"> <ClInclude Include="..\..\Subtrees\sqlite\sqlite3.h">
@@ -1584,6 +1587,9 @@
<ClInclude Include="..\..\src\cpp\ripple\ripple_UniqueNodeList.h"> <ClInclude Include="..\..\src\cpp\ripple\ripple_UniqueNodeList.h">
<Filter>[1] Ripple\ripple_app\_peers</Filter> <Filter>[1] Ripple\ripple_app\_peers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\modules\ripple_basio\boost\ripple_SslContext.h">
<Filter>[1] Ripple\ripple_basio\boost</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\..\src\cpp\ripple\ripple.proto" /> <CustomBuild Include="..\..\src\cpp\ripple\ripple.proto" />

View File

@@ -2,6 +2,10 @@
RIPPLE TODO RIPPLE TODO
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
- See if UniqueNodeList is really used, and if its not used remove it. If
only some small part of it is used, then delete the rest. David says
that it is broken anyway.
- Roll a simple wrapper for sqlite relational stuff like loading the UNL - Roll a simple wrapper for sqlite relational stuff like loading the UNL
Completely hide the specifics of SQLite and/or beast::db Completely hide the specifics of SQLite and/or beast::db
@@ -264,3 +268,29 @@ A node is "full below" if we believe we have (either in the database or
The fullBelowCache is a cache of hashes of nodes that are full below. Which means The fullBelowCache is a cache of hashes of nodes that are full below. Which means
there are no missing children there are no missing children
What we want from the unique node list:
- Some number of trusted roots (known by domain)
probably organizations whose job is to provide a list of validators
- We imagine the IRGA for example would establish some group whose job is to
maintain a list of validators. There would be a public list of criteria
that they would use to vet the validator. Things like:
* Not anonymous
* registered business
* Physical location
* Agree not to cease operations without notice / arbitrarily
* Responsive to complaints
- Identifiable jurisdiction
* Homogeneity in the jurisdiction is a business risk
* If all validators are in the same jurisdiction this is a business risk
- OpenCoin sets criteria for the organizations
- Rippled will ship with a list of trusted root "certificates"
In other words this is a list of trusted domains from which the software
can contact each trusted root and retrieve a list of "good" validators
and then do something with that information
- All the validation information would be public, including the broadcast
messages.
- The goal is to easily identify bad actors and assess network health
* Malicious intent
* Or, just hardware problems (faulty drive or memory)

View File

@@ -26,4 +26,85 @@ SslContext::SslContext ()
{ {
} }
// VFALCO TODO Can we call this function from the ctor of PeerDoor as well?
// Or can we move the common code to a new function?
//
void SslContext::initializeFromFile (
boost::asio::ssl::context& context,
std::string key_file,
std::string cert_file,
std::string chain_file)
{
SSL_CTX* sslContext = context.native_handle ();
context.set_options (boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
bool cert_set = false;
if (!cert_file.empty ())
{
boost::system::error_code error;
context.use_certificate_file (cert_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error ("Unable to use certificate file");
cert_set = true;
}
if (!chain_file.empty ())
{
// VFALCO Replace fopen() with RAII
FILE* f = fopen (chain_file.c_str (), "r");
if (!f)
throw std::runtime_error ("Unable to open chain file");
try
{
while (true)
{
X509* x = PEM_read_X509 (f, NULL, NULL, NULL);
if (x == NULL)
break;
if (!cert_set)
{
if (SSL_CTX_use_certificate (sslContext, x) != 1)
throw std::runtime_error ("Unable to get certificate from chain file");
cert_set = true;
}
else if (SSL_CTX_add_extra_chain_cert (sslContext, x) != 1)
{
X509_free (x);
throw std::runtime_error ("Unable to add chain certificate");
}
}
fclose (f);
}
catch (...)
{
fclose (f);
throw;
}
}
if (!key_file.empty ())
{
boost::system::error_code error;
context.use_private_key_file (key_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error ("Unable to use private key file");
}
if (SSL_CTX_check_private_key (sslContext) != 1)
throw std::runtime_error ("Private key not valid");
}
} }

View File

@@ -21,6 +21,12 @@ public:
operator boost::asio::ssl::context& (); operator boost::asio::ssl::context& ();
static void initializeFromFile (
boost::asio::ssl::context& context,
std::string key_file,
std::string cert_file,
std::string chain_file);
private: private:
SslContext (); SslContext ();

View File

@@ -6,150 +6,102 @@
SETUP_LOG (PeerDoor) SETUP_LOG (PeerDoor)
// PEER_IP, PEER_PORT, PEER_SSL_CIPHER_LIST class PeerDoorImp : public PeerDoor, LeakChecked <PeerDoorImp>
PeerDoor::PeerDoor ( {
public:
PeerDoorImp (std::string const& ip,
int port,
std::string const& sslCiphers,
boost::asio::io_service& io_service)
: mAcceptor (
io_service,
boost::asio::ip::tcp::endpoint (boost::asio::ip::address ().from_string (ip.empty () ? "0.0.0.0" : ip),
port))
, mCtx (boost::asio::ssl::context::sslv23)
, mDelayTimer (io_service)
{
mCtx.set_options (
boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
SSL_CTX_set_tmp_dh_callback (mCtx.native_handle (), handleTmpDh);
if (SSL_CTX_set_cipher_list (mCtx.native_handle (), sslCiphers.c_str ()) != 1)
std::runtime_error ("Error setting cipher list (no valid ciphers).");
if (! ip.empty () && port != 0)
{
Log (lsINFO) << "Peer port: " << ip << " " << port;
startListening ();
}
}
//--------------------------------------------------------------------------
boost::asio::ssl::context& getSSLContext ()
{
return mCtx;
}
//--------------------------------------------------------------------------
void startListening ()
{
Peer::pointer new_connection = Peer::New (
mAcceptor.get_io_service (),
mCtx,
getApp().getPeers ().assignPeerId (),
true);
mAcceptor.async_accept (new_connection->getSocket (),
boost::bind (&PeerDoorImp::handleConnect, this, new_connection,
boost::asio::placeholders::error));
}
//--------------------------------------------------------------------------
void handleConnect (Peer::pointer new_connection,
const boost::system::error_code& error)
{
bool delay = false;
if (!error)
{
new_connection->connected (error);
}
else
{
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsERROR, PeerDoor) << error;
}
if (delay)
{
mDelayTimer.expires_from_now (boost::posix_time::milliseconds (500));
mDelayTimer.async_wait (boost::bind (&PeerDoorImp::startListening, this));
}
else
{
startListening ();
}
}
private:
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::ssl::context mCtx;
boost::asio::deadline_timer mDelayTimer;
};
//------------------------------------------------------------------------------
PeerDoor* PeerDoor::New (
std::string const& ip, std::string const& ip,
int port, int port,
std::string const& sslCiphers, std::string const& sslCiphers,
boost::asio::io_service& io_service) boost::asio::io_service& io_service)
: mAcceptor (
io_service,
boost::asio::ip::tcp::endpoint (boost::asio::ip::address ().from_string (ip.empty () ? "0.0.0.0" : ip),
port))
, mCtx (boost::asio::ssl::context::sslv23)
, mDelayTimer (io_service)
{ {
mCtx.set_options ( return new PeerDoorImp (ip, port, sslCiphers, io_service);
boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
SSL_CTX_set_tmp_dh_callback (mCtx.native_handle (), handleTmpDh);
if (SSL_CTX_set_cipher_list (mCtx.native_handle (), sslCiphers.c_str ()) != 1)
std::runtime_error ("Error setting cipher list (no valid ciphers).");
if (! ip.empty () && port != 0)
{
Log (lsINFO) << "Peer port: " << ip << " " << port;
startListening ();
}
} }
void PeerDoor::startListening ()
{
Peer::pointer new_connection = Peer::New (
mAcceptor.get_io_service (),
mCtx,
getApp().getPeers ().assignPeerId (),
true);
mAcceptor.async_accept (new_connection->getSocket (),
boost::bind (&PeerDoor::handleConnect, this, new_connection,
boost::asio::placeholders::error));
}
void PeerDoor::handleConnect (Peer::pointer new_connection,
const boost::system::error_code& error)
{
bool delay = false;
if (!error)
{
new_connection->connected (error);
}
else
{
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsERROR, PeerDoor) << error;
}
if (delay)
{
mDelayTimer.expires_from_now (boost::posix_time::milliseconds (500));
mDelayTimer.async_wait (boost::bind (&PeerDoor::startListening, this));
}
else
{
startListening ();
}
}
void initSSLContext (boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file)
{
SSL_CTX* sslContext = context.native_handle ();
context.set_options (boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
bool cert_set = false;
if (!cert_file.empty ())
{
boost::system::error_code error;
context.use_certificate_file (cert_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error ("Unable to use certificate file");
cert_set = true;
}
if (!chain_file.empty ())
{
// VFALCO Replace fopen() with RAII
FILE* f = fopen (chain_file.c_str (), "r");
if (!f)
throw std::runtime_error ("Unable to open chain file");
try
{
while (true)
{
X509* x = PEM_read_X509 (f, NULL, NULL, NULL);
if (x == NULL)
break;
if (!cert_set)
{
if (SSL_CTX_use_certificate (sslContext, x) != 1)
throw std::runtime_error ("Unable to get certificate from chain file");
cert_set = true;
}
else if (SSL_CTX_add_extra_chain_cert (sslContext, x) != 1)
{
X509_free (x);
throw std::runtime_error ("Unable to add chain certificate");
}
}
fclose (f);
}
catch (...)
{
fclose (f);
throw;
}
}
if (!key_file.empty ())
{
boost::system::error_code error;
context.use_private_key_file (key_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error ("Unable to use private key file");
}
if (SSL_CTX_check_private_key (sslContext) != 1)
throw std::runtime_error ("Private key not valid");
}
// vim:ts=4

View File

@@ -4,35 +4,23 @@
*/ */
//============================================================================== //==============================================================================
#ifndef __PEERDOOR__ #ifndef RIPPLE_PEERDOOR_H_INCLUDED
#define __PEERDOOR__ #define RIPPLE_PEERDOOR_H_INCLUDED
/* /** Handles incoming connections from peers.
Handles incoming connections from other Peers
*/ */
class PeerDoor : LeakChecked <PeerDoor> class PeerDoor : LeakChecked <PeerDoor>
{ {
public: public:
PeerDoor (std::string const& ip, virtual ~PeerDoor () { }
int port,
std::string const& sslCiphers,
boost::asio::io_service& io_service);
boost::asio::ssl::context& getSSLContext () static PeerDoor* New (
{ std::string const& ip,
return mCtx; int port,
} std::string const& sslCiphers,
boost::asio::io_service& io_service);
private: virtual boost::asio::ssl::context& getSSLContext () = 0;
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::ssl::context mCtx;
boost::asio::deadline_timer mDelayTimer;
void startListening ();
void handleConnect (Peer::pointer new_connection, const boost::system::error_code& error);
}; };
#endif #endif
// vim:ts=4

View File

@@ -6,11 +6,6 @@
SETUP_LOG (RPCDoor) SETUP_LOG (RPCDoor)
// VFALCO TODO Clean up this loose extern
//
extern void initSSLContext (boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file);
RPCDoor::RPCDoor (boost::asio::io_service& io_service, RPCServer::Handler& handler) RPCDoor::RPCDoor (boost::asio::io_service& io_service, RPCServer::Handler& handler)
: m_rpcServerHandler (handler) : m_rpcServerHandler (handler)
, mAcceptor (io_service, , mAcceptor (io_service,
@@ -21,7 +16,15 @@ RPCDoor::RPCDoor (boost::asio::io_service& io_service, RPCServer::Handler& handl
WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.getRpcAddress().toRawUTF8() << " allow remote: " << theConfig.RPC_ALLOW_REMOTE; WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.getRpcAddress().toRawUTF8() << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
if (theConfig.RPC_SECURE != 0) if (theConfig.RPC_SECURE != 0)
initSSLContext (mSSLContext, theConfig.RPC_SSL_KEY, theConfig.RPC_SSL_CERT, theConfig.RPC_SSL_CHAIN); {
// VFALCO TODO This could be a method of theConfig
//
basio::SslContext::initializeFromFile (
mSSLContext,
theConfig.RPC_SSL_KEY,
theConfig.RPC_SSL_CERT,
theConfig.RPC_SSL_CHAIN);
}
startListening (); startListening ();
} }

View File

@@ -569,7 +569,7 @@ void Application::setup ()
{ {
try try
{ {
mPeerDoor = new PeerDoor ( mPeerDoor = PeerDoor::New (
theConfig.PEER_IP, theConfig.PEER_IP,
theConfig.PEER_PORT, theConfig.PEER_PORT,
theConfig.PEER_SSL_CIPHER_LIST, theConfig.PEER_SSL_CIPHER_LIST,

View File

@@ -91,8 +91,8 @@ private:
public: public:
UniqueNodeListImp () UniqueNodeListImp ()
: m_scoreTimer (this) : m_scoreTimer (this)
, m_fetchTimer (this)
, mFetchActive (0) , mFetchActive (0)
, m_fetchTimer (this)
{ {
} }
@@ -135,7 +135,7 @@ public:
// This is called when the application is started. // This is called when the application is started.
// Get update times and start fetching and scoring as needed. // Get update times and start fetching and scoring as needed.
void UniqueNodeListImp::start () void start ()
{ {
miscLoad (); miscLoad ();
@@ -414,7 +414,7 @@ public:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
bool UniqueNodeListImp::nodeLoad (boost::filesystem::path pConfig) bool nodeLoad (boost::filesystem::path pConfig)
{ {
if (pConfig.empty ()) if (pConfig.empty ())
{ {
@@ -1084,12 +1084,7 @@ private:
+ boost::posix_time::seconds (secondsFromNow); + boost::posix_time::seconds (secondsFromNow);
// WriteLog (lsTRACE, UniqueNodeList) << str(boost::format("scoreNext: @%s") % mtpScoreNext); // WriteLog (lsTRACE, UniqueNodeList) << str(boost::format("scoreNext: @%s") % mtpScoreNext);
#if 1
m_scoreTimer.setExpiration (secondsFromNow); m_scoreTimer.setExpiration (secondsFromNow);
#else
mdtScoreTimer.expires_at (mtpScoreNext);
mdtScoreTimer.async_wait (BIND_TYPE (&UniqueNodeListImp::scoreTimerHandler, this, P_1));
#endif
} }
} }
@@ -1281,14 +1276,9 @@ private:
// Fetch needs to happen in the future. Set a timer to wake us. // Fetch needs to happen in the future. Set a timer to wake us.
mtpFetchNext = tpNext; mtpFetchNext = tpNext;
#if 1
double const seconds = (tpNext - tpNow).seconds (); double const seconds = (tpNext - tpNow).seconds ();
m_fetchTimer.setExpiration (seconds); m_fetchTimer.setExpiration (seconds);
#else
mdtFetchTimer.expires_at (mtpFetchNext);
mdtFetchTimer.async_wait (BIND_TYPE (&UniqueNodeListImp::fetchTimerHandler, this, P_1));
#endif
} }
else else
{ {

View File

@@ -7,9 +7,6 @@
#ifndef RIPPLE_WSHANDLER_H_INCLUDED #ifndef RIPPLE_WSHANDLER_H_INCLUDED
#define RIPPLE_WSHANDLER_H_INCLUDED #define RIPPLE_WSHANDLER_H_INCLUDED
extern void initSSLContext (boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file);
extern bool serverOkay (std::string& reason); extern bool serverOkay (std::string& reason);
template <typename endpoint_type> template <typename endpoint_type>
@@ -52,8 +49,11 @@ public:
{ {
if (theConfig.WEBSOCKET_SECURE != 0) if (theConfig.WEBSOCKET_SECURE != 0)
{ {
initSSLContext (*mCtx, theConfig.WEBSOCKET_SSL_KEY, basio::SslContext::initializeFromFile (
theConfig.WEBSOCKET_SSL_CERT, theConfig.WEBSOCKET_SSL_CHAIN); *mCtx,
theConfig.WEBSOCKET_SSL_KEY,
theConfig.WEBSOCKET_SSL_CERT,
theConfig.WEBSOCKET_SSL_CHAIN);
} }
} }