mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Add PeerFinder peer discovery logic and unit test
This commit is contained in:
@@ -784,13 +784,19 @@
|
|||||||
<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="..\..\src\ripple_core\ripple_core.cpp" />
|
<ClCompile Include="..\..\modules\ripple_core\test\TestOverlay.cpp">
|
||||||
<ClCompile Include="..\..\src\ripple_core\test\TestOverlay.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
<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="..\..\src\ripple_core\peerfinder\ripple_PeerFinder.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="..\..\src\ripple_core\ripple_core.cpp" />
|
||||||
<ClCompile Include="..\..\src\ripple_core\validator\ValidatorSourceFile.cpp">
|
<ClCompile Include="..\..\src\ripple_core\validator\ValidatorSourceFile.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
@@ -1512,6 +1518,7 @@
|
|||||||
<ClInclude Include="..\..\src\ripple_core\node\NodeObject.h" />
|
<ClInclude Include="..\..\src\ripple_core\node\NodeObject.h" />
|
||||||
<ClInclude Include="..\..\src\ripple_core\node\NodeStore.h" />
|
<ClInclude Include="..\..\src\ripple_core\node\NodeStore.h" />
|
||||||
<ClInclude Include="..\..\src\ripple_core\node\NullBackendFactory.h" />
|
<ClInclude Include="..\..\src\ripple_core\node\NullBackendFactory.h" />
|
||||||
|
<ClInclude Include="..\..\src\ripple_core\peerfinder\ripple_PeerFinder.h" />
|
||||||
<ClInclude Include="..\..\src\ripple_core\ripple_core.h" />
|
<ClInclude Include="..\..\src\ripple_core\ripple_core.h" />
|
||||||
<ClInclude Include="..\..\src\ripple_core\test\ConnectionType.h" />
|
<ClInclude Include="..\..\src\ripple_core\test\ConnectionType.h" />
|
||||||
<ClInclude Include="..\..\src\ripple_core\test\InitPolicy.h" />
|
<ClInclude Include="..\..\src\ripple_core\test\InitPolicy.h" />
|
||||||
|
|||||||
@@ -154,6 +154,9 @@
|
|||||||
<Filter Include="[2] doc">
|
<Filter Include="[2] doc">
|
||||||
<UniqueIdentifier>{c69b07a2-44e5-4b06-99a9-81f5d137ea15}</UniqueIdentifier>
|
<UniqueIdentifier>{c69b07a2-44e5-4b06-99a9-81f5d137ea15}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="[1] Ripple\ripple_core\peerfinder">
|
||||||
|
<UniqueIdentifier>{d1648d3f-7d71-495d-afc9-576ed00d7185}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\ripple_basics\containers\ripple_RangeSet.cpp">
|
<ClCompile Include="..\..\src\ripple_basics\containers\ripple_RangeSet.cpp">
|
||||||
@@ -219,9 +222,6 @@
|
|||||||
<ClCompile Include="..\..\src\ripple_core\functional\ripple_LoadMonitor.cpp">
|
<ClCompile Include="..\..\src\ripple_core\functional\ripple_LoadMonitor.cpp">
|
||||||
<Filter>[1] Ripple\ripple_core\functional</Filter>
|
<Filter>[1] Ripple\ripple_core\functional</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple_core\ripple_core.cpp">
|
|
||||||
<Filter>[1] Ripple\ripple_core</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\ripple_data\crypto\ripple_Base58.cpp">
|
<ClCompile Include="..\..\src\ripple_data\crypto\ripple_Base58.cpp">
|
||||||
<Filter>[1] Ripple\ripple_data\crypto</Filter>
|
<Filter>[1] Ripple\ripple_data\crypto</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -840,9 +840,6 @@
|
|||||||
<ClCompile Include="..\..\src\ripple_core\validator\Validators.cpp">
|
<ClCompile Include="..\..\src\ripple_core\validator\Validators.cpp">
|
||||||
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple_core\test\TestOverlay.cpp">
|
|
||||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\ripple_core\validator\ValidatorsUtilities.cpp">
|
<ClCompile Include="..\..\src\ripple_core\validator\ValidatorsUtilities.cpp">
|
||||||
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -876,6 +873,13 @@
|
|||||||
<ClCompile Include="..\..\src\beast\modules\beast_sqlite\beast_sqlite.c">
|
<ClCompile Include="..\..\src\beast\modules\beast_sqlite\beast_sqlite.c">
|
||||||
<Filter>[0] src\beast</Filter>
|
<Filter>[0] src\beast</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\ripple_core\test\TestOverlay.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\ripple_core\ripple_core.cpp">
|
||||||
|
<Filter>[1] Ripple\ripple_core</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\ripple_core\peerfinder\ripple_PeerFinder.cpp">
|
||||||
|
<Filter>[1] Ripple\ripple_core\peerfinder</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\src\ripple_app\ripple_app.h">
|
<ClInclude Include="..\..\src\ripple_app\ripple_app.h">
|
||||||
@@ -1728,6 +1732,9 @@
|
|||||||
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\BeastConfig.h" />
|
<ClInclude Include="..\..\src\BeastConfig.h" />
|
||||||
|
<ClInclude Include="..\..\src\ripple_core\peerfinder\ripple_PeerFinder.h">
|
||||||
|
<Filter>[1] Ripple\ripple_core\peerfinder</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="..\..\src\ripple_data\protocol\ripple.proto">
|
<CustomBuild Include="..\..\src\ripple_data\protocol\ripple.proto">
|
||||||
|
|||||||
@@ -173,4 +173,12 @@
|
|||||||
#define RIPPLE_APPLICATION_CLEAN_EXIT 0
|
#define RIPPLE_APPLICATION_CLEAN_EXIT 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// This is only here temporarily. Use it to turn off the sending of
|
||||||
|
// "ANNOUNCE" messages if you suspect that you're having problems
|
||||||
|
// because of it.
|
||||||
|
|
||||||
|
#ifndef RIPPLE_USE_MT_ANNOUNCE
|
||||||
|
#define RIPPLE_USE_MT_ANNOUNCE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class ApplicationImp
|
|||||||
, public SharedSingleton <ApplicationImp>
|
, public SharedSingleton <ApplicationImp>
|
||||||
, public NodeStore::Scheduler
|
, public NodeStore::Scheduler
|
||||||
, LeakChecked <ApplicationImp>
|
, LeakChecked <ApplicationImp>
|
||||||
|
, PeerFinder::Callback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// RAII container for a boost::asio::io_service run by beast threads
|
// RAII container for a boost::asio::io_service run by beast threads
|
||||||
@@ -175,6 +176,7 @@ public:
|
|||||||
, mUNL (UniqueNodeList::New ())
|
, mUNL (UniqueNodeList::New ())
|
||||||
, mProofOfWorkFactory (ProofOfWorkFactory::New ())
|
, mProofOfWorkFactory (ProofOfWorkFactory::New ())
|
||||||
, m_loadManager (LoadManager::New ())
|
, m_loadManager (LoadManager::New ())
|
||||||
|
, mPeerFinder (PeerFinder::New (*this))
|
||||||
// VFALCO End new stuff
|
// VFALCO End new stuff
|
||||||
// VFALCO TODO replace all NULL with nullptr
|
// VFALCO TODO replace all NULL with nullptr
|
||||||
, mRpcDB (NULL)
|
, mRpcDB (NULL)
|
||||||
@@ -366,6 +368,11 @@ public:
|
|||||||
return *m_peers;
|
return *m_peers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PeerFinder& getPeerFinder ()
|
||||||
|
{
|
||||||
|
return *mPeerFinder;
|
||||||
|
}
|
||||||
|
|
||||||
// VFALCO TODO Move these to the .cpp
|
// VFALCO TODO Move these to the .cpp
|
||||||
bool running ()
|
bool running ()
|
||||||
{
|
{
|
||||||
@@ -698,6 +705,8 @@ private:
|
|||||||
void startNewLedger ();
|
void startNewLedger ();
|
||||||
bool loadOldLedger (const std::string&, bool);
|
bool loadOldLedger (const std::string&, bool);
|
||||||
|
|
||||||
|
void onAnnounceAddress ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Application::LockType mMasterLock;
|
Application::LockType mMasterLock;
|
||||||
|
|
||||||
@@ -735,6 +744,7 @@ private:
|
|||||||
ScopedPointer <PeerDoor> m_peerProxyDoor;
|
ScopedPointer <PeerDoor> m_peerProxyDoor;
|
||||||
ScopedPointer <WSDoor> m_wsPublicDoor;
|
ScopedPointer <WSDoor> m_wsPublicDoor;
|
||||||
ScopedPointer <WSDoor> m_wsPrivateDoor;
|
ScopedPointer <WSDoor> m_wsPrivateDoor;
|
||||||
|
ScopedPointer <PeerFinder> mPeerFinder;
|
||||||
// VFALCO End Clean stuff
|
// VFALCO End Clean stuff
|
||||||
|
|
||||||
DatabaseCon* mRpcDB;
|
DatabaseCon* mRpcDB;
|
||||||
@@ -1189,6 +1199,11 @@ void ApplicationImp::updateTables ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplicationImp::onAnnounceAddress ()
|
||||||
|
{
|
||||||
|
// NIKB CODEME
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
Application& getApp ()
|
Application& getApp ()
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class SerializedLedgerEntry;
|
|||||||
class TransactionMaster;
|
class TransactionMaster;
|
||||||
class TxQueue;
|
class TxQueue;
|
||||||
class LocalCredentials;
|
class LocalCredentials;
|
||||||
|
class PeerFinder;
|
||||||
|
|
||||||
class DatabaseCon;
|
class DatabaseCon;
|
||||||
|
|
||||||
@@ -95,6 +96,7 @@ public:
|
|||||||
virtual TransactionMaster& getMasterTransaction () = 0;
|
virtual TransactionMaster& getMasterTransaction () = 0;
|
||||||
virtual TxQueue& getTxQueue () = 0;
|
virtual TxQueue& getTxQueue () = 0;
|
||||||
virtual LocalCredentials& getLocalCredentials () = 0;
|
virtual LocalCredentials& getLocalCredentials () = 0;
|
||||||
|
virtual PeerFinder& getPeerFinder () = 0;
|
||||||
|
|
||||||
virtual DatabaseCon* getRpcDB () = 0;
|
virtual DatabaseCon* getRpcDB () = 0;
|
||||||
virtual DatabaseCon* getTxnDB () = 0;
|
virtual DatabaseCon* getTxnDB () = 0;
|
||||||
|
|||||||
@@ -335,6 +335,7 @@ private:
|
|||||||
void sendPacketForce (const PackedMessage::pointer & packet);
|
void sendPacketForce (const PackedMessage::pointer & packet);
|
||||||
|
|
||||||
void sendHello ();
|
void sendHello ();
|
||||||
|
void SendAnnounce ();
|
||||||
|
|
||||||
void recvHello (protocol::TMHello & packet);
|
void recvHello (protocol::TMHello & packet);
|
||||||
void recvCluster (protocol::TMCluster & packet);
|
void recvCluster (protocol::TMCluster & packet);
|
||||||
@@ -345,6 +346,7 @@ private:
|
|||||||
void recvGetContacts (protocol::TMGetContacts & packet);
|
void recvGetContacts (protocol::TMGetContacts & packet);
|
||||||
void recvGetPeers (protocol::TMGetPeers & packet, Application::ScopedLockType& masterLockHolder);
|
void recvGetPeers (protocol::TMGetPeers & packet, Application::ScopedLockType& masterLockHolder);
|
||||||
void recvPeers (protocol::TMPeers & packet);
|
void recvPeers (protocol::TMPeers & packet);
|
||||||
|
void recvAnnounce (protocol::TMAnnounce & packet);
|
||||||
void recvGetObjectByHash (const boost::shared_ptr<protocol::TMGetObjectByHash>& packet);
|
void recvGetObjectByHash (const boost::shared_ptr<protocol::TMGetObjectByHash>& packet);
|
||||||
void recvPing (protocol::TMPing & packet);
|
void recvPing (protocol::TMPing & packet);
|
||||||
void recvErrorMessage (protocol::TMErrorMsg & packet);
|
void recvErrorMessage (protocol::TMErrorMsg & packet);
|
||||||
@@ -834,6 +836,17 @@ void PeerImp::processReadBuffer ()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case protocol::mtANNOUNCE:
|
||||||
|
{
|
||||||
|
event->reName ("PeerImp::announce");
|
||||||
|
protocol::TMAnnounce msg;
|
||||||
|
|
||||||
|
if(msg.ParseFromArray (&mReadbuf[PackedMessage::kHeaderBytes], mReadbuf.size() - PackedMessage::kHeaderBytes))
|
||||||
|
recvAnnounce (msg);
|
||||||
|
else
|
||||||
|
WriteLog (lsWARNING, Peer) << "parse error: " << type;;
|
||||||
|
}
|
||||||
|
|
||||||
case protocol::mtSEARCH_TRANSACTION:
|
case protocol::mtSEARCH_TRANSACTION:
|
||||||
{
|
{
|
||||||
event->reName ("PeerImp::searchtransaction");
|
event->reName ("PeerImp::searchtransaction");
|
||||||
@@ -1606,6 +1619,15 @@ void PeerImp::recvPeers (protocol::TMPeers& packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerImp::recvAnnounce (protocol::TMAnnounce& packet)
|
||||||
|
{
|
||||||
|
// NIKB TODO: First we need to push this announcement to peerfinder
|
||||||
|
// and then this is not a private peer, we need to "adjust" this
|
||||||
|
// announcement (i.e. the hop count) and push it out to all our
|
||||||
|
// other peers. We must be careful to avoid cycles (that is to
|
||||||
|
// never send an ANNOUNCE back to the peer we got it from).
|
||||||
|
}
|
||||||
|
|
||||||
void PeerImp::recvGetObjectByHash (const boost::shared_ptr<protocol::TMGetObjectByHash>& ptr)
|
void PeerImp::recvGetObjectByHash (const boost::shared_ptr<protocol::TMGetObjectByHash>& ptr)
|
||||||
{
|
{
|
||||||
protocol::TMGetObjectByHash& packet = *ptr;
|
protocol::TMGetObjectByHash& packet = *ptr;
|
||||||
@@ -2362,6 +2384,32 @@ void PeerImp::sendHello ()
|
|||||||
sendPacket (packet, true);
|
sendPacket (packet, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerImp::SendAnnounce ()
|
||||||
|
{
|
||||||
|
protocol::TMAnnounce a;
|
||||||
|
|
||||||
|
std::string selfID = getApp().getLocalCredentials ().getNodePublic ().humanNodePublic ();
|
||||||
|
|
||||||
|
a.set_serverid(selfID);
|
||||||
|
|
||||||
|
// Since we are announcing ourselves, the hopcount is one and the "via" peer is us.
|
||||||
|
// If hopcount is anything else, the "via" peer must be different from the "serverid".
|
||||||
|
a.set_viapeerid(selfID);
|
||||||
|
a.set_hopcount(1); // A direct connection
|
||||||
|
|
||||||
|
// Announce whether we're a private peer or not. Should we even send an ANNOUNCE
|
||||||
|
// for private peers?
|
||||||
|
a.set_privatepeer(getConfig ().PEER_PRIVATE);
|
||||||
|
|
||||||
|
protocol::TMIPv4EndPoint *ep = a.add_connectpoints();
|
||||||
|
|
||||||
|
ep->set_ipv4(inet_addr (getNativeSocket ().local_endpoint ().address ().to_string ().c_str()));
|
||||||
|
ep->set_ipv4port(getConfig ().peerListeningPort);
|
||||||
|
|
||||||
|
PackedMessage::pointer packet = boost::make_shared<PackedMessage> (a, protocol::mtANNOUNCE);
|
||||||
|
sendPacket (packet, true);
|
||||||
|
}
|
||||||
|
|
||||||
void PeerImp::sendGetPeers ()
|
void PeerImp::sendGetPeers ()
|
||||||
{
|
{
|
||||||
// Ask peer for known other peers.
|
// Ask peer for known other peers.
|
||||||
|
|||||||
369
src/ripple_core/peerfinder/ripple_PeerFinder.cpp
Normal file
369
src/ripple_core/peerfinder/ripple_PeerFinder.cpp
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
/*
|
||||||
|
|
||||||
|
PeerFinder
|
||||||
|
----------
|
||||||
|
|
||||||
|
Implements the logic for announcing and discovering IP addresses for
|
||||||
|
for connecting into the Ripple network.
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
Each Peer (a computer running rippled) on the Ripple network requires a certain
|
||||||
|
number of connections to other peers. These connections form an "overlay
|
||||||
|
network." When a new peer wants to join the network, they need a robust source
|
||||||
|
of network addresses (IP adresses) in order to establish outgoing connections.
|
||||||
|
Once they have joined the network, they need a method of announcing their
|
||||||
|
availaibility of accepting incoming connections.
|
||||||
|
|
||||||
|
The Ripple network, like all peer to peer networks, defines a "directed graph"
|
||||||
|
where each node represents a computer running the rippled software, and each
|
||||||
|
vertex indicates a network connection. The direction of the connection tells
|
||||||
|
us whether it is an outbound or inbound connection (from the perspective of
|
||||||
|
a particular node).
|
||||||
|
|
||||||
|
Fact #1:
|
||||||
|
The total inbound and outbound connections of any overlay must be equal.
|
||||||
|
|
||||||
|
This follows that for each node that has an established outbound connection,
|
||||||
|
there must exist another node that has received the corresponding inbound
|
||||||
|
connection.
|
||||||
|
|
||||||
|
When a new peer joins the network it may or may not wish to receive inbound
|
||||||
|
connections. Some peers are unable to accept incoming connections for various.
|
||||||
|
For security reasons they may be behind a firewall that blocks accept requests.
|
||||||
|
The administers may decide they don't want the connection traffic. Or they
|
||||||
|
may wish to connect only to specific peers. Or they may simply be misconfigured.
|
||||||
|
|
||||||
|
If a peer decides that it wishes to receive incoming connections, it needs
|
||||||
|
a method to announce its IP address and port number, the features that it
|
||||||
|
offers (for example, that it also services client requests), and the number
|
||||||
|
of available connection slots. This is to handle the case where the peer
|
||||||
|
reaches its desired number of peer connections, but may still want to inform
|
||||||
|
the network that it will service clients. It may also be desired to indicate
|
||||||
|
the number of free client slots.
|
||||||
|
|
||||||
|
Pong
|
||||||
|
----
|
||||||
|
|
||||||
|
Once a peer is connected to the network we need a way both to inform our
|
||||||
|
neighbors of our status with respect to accepting connections, and also to
|
||||||
|
learn about new fresh addresses to connect to. For this we will define the "Pong"
|
||||||
|
message.
|
||||||
|
|
||||||
|
"Connection Strategy"
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
This is the overall strategy a peer uses to maintain its position in the Ripple
|
||||||
|
network graph
|
||||||
|
|
||||||
|
We define these values:
|
||||||
|
|
||||||
|
PeerCount (calculated)
|
||||||
|
The number of currently connected and established peers
|
||||||
|
|
||||||
|
OutCount (calculated)
|
||||||
|
The number of peers in PeerCount that are outbound connections.
|
||||||
|
|
||||||
|
MinOutCount (hard-coded constant)
|
||||||
|
The minimum number of OutCount we want. This also puts a floor
|
||||||
|
on PeerCount. This protects against sybil attacks and makes
|
||||||
|
sure that ledgers can get retrieved reliably.
|
||||||
|
10 is the proposed value.
|
||||||
|
|
||||||
|
MaxPeerCount (a constant set in the rippled.cfg)
|
||||||
|
The maximum number of peer connections, inbound or outbound,
|
||||||
|
that a peer wishes to maintain. Setting MaxPeerCount equal to
|
||||||
|
or below MinOutCount would disallow incoming connections.
|
||||||
|
|
||||||
|
OutDesiredPercent (a baked-in program constant for now)
|
||||||
|
The peer's target value for OutCount. When the value of OutCount
|
||||||
|
is below this number, the peer will employ the Outgoing Strategy
|
||||||
|
to raise its value of OutCount. This value is initially a constant
|
||||||
|
in the program, defined by the developers. However, it
|
||||||
|
may be changed through the consensus process.
|
||||||
|
15% is a proposed value.
|
||||||
|
|
||||||
|
However, lets consider the case where OutDesired is exactly equal to MaxPeerCount / 2.
|
||||||
|
In this case, a stable state will be reached when every peer is full, and
|
||||||
|
has exactly the same number of inbound and outbound connections. The problem
|
||||||
|
here is that there are now no available incoming connection slots. No new
|
||||||
|
peers can enter the network.
|
||||||
|
|
||||||
|
Lets consider the case where OutDesired is exactly equal to (MaxPeerCount / 2) - 1.
|
||||||
|
The stable state for this network (assuming all peers can accept incoming) will
|
||||||
|
leave us with network degree equal to MaxPeerCount - 2, with all peers having two
|
||||||
|
available incoming connection slots. The global number of incoming connection slots
|
||||||
|
will be equal to twice the number of nodes on the network. While this might seem to
|
||||||
|
be a desirable outcome, note that the connectedness (degree of the overlay) plays
|
||||||
|
a large part in determining the levels of traffic and ability to receive validations
|
||||||
|
from desired nodes. Having every node with available incoming connections also
|
||||||
|
means that entries in pong caches will continually fall out with new values and
|
||||||
|
information will become less useful.
|
||||||
|
|
||||||
|
For this reason, we advise that the value of OutDesired be fractional. Upon startup,
|
||||||
|
a node will use its node ID (its 160 bit unique ID) to decide whether to round the
|
||||||
|
value of OutDesired up or down. Using this method, we can precisely control the
|
||||||
|
global number of available incoming connection slots.
|
||||||
|
|
||||||
|
"Outgoing Strategy"
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
This is the method a peer uses to establish outgoing connections into the
|
||||||
|
Ripple network.
|
||||||
|
|
||||||
|
A peer whose PeerCount is zero will use these steps:
|
||||||
|
1. Attempt addresses from a local database of addresses
|
||||||
|
2. Attempt addresses from a set of "well known" domains in rippled.cfg
|
||||||
|
|
||||||
|
|
||||||
|
This is the method used by a peer that is already connected to the Ripple network,
|
||||||
|
to adjust the number of outgoing connections it is maintaining.
|
||||||
|
|
||||||
|
|
||||||
|
"Incoming Strategy"
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
This is the method used by a peer to announce its ability and desire to receive
|
||||||
|
incoming connections both for the purpose of obtaining additional peer connections
|
||||||
|
and also for receiving requests from clients.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Terms
|
||||||
|
|
||||||
|
Overlay Network
|
||||||
|
http://en.wikipedia.org/wiki/Overlay_network
|
||||||
|
|
||||||
|
Directed Graph
|
||||||
|
http://en.wikipedia.org/wiki/Directed_graph
|
||||||
|
|
||||||
|
References:
|
||||||
|
|
||||||
|
Gnutella 0.6 Protocol
|
||||||
|
2.2.2 Ping (0x00)
|
||||||
|
2.2.3 Pong (0x01)
|
||||||
|
2.2.4 Use of Ping and Pong messages
|
||||||
|
2.2.4.1 A simple pong caching scheme
|
||||||
|
2.2.4.2 Other pong caching schemes
|
||||||
|
http://rfc-gnutella.sourceforge.net/src/rfc-0_6-draft.html
|
||||||
|
|
||||||
|
Revised Gnutella Ping Pong Scheme
|
||||||
|
By Christopher Rohrs and Vincent Falco
|
||||||
|
http://rfc-gnutella.sourceforge.net/src/pong-caching.html
|
||||||
|
|
||||||
|
*/
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class PeerFinderImp
|
||||||
|
: public PeerFinder
|
||||||
|
, private ThreadWithCallQueue::EntryPoints
|
||||||
|
, private DeadlineTimer::Listener
|
||||||
|
, LeakChecked <PeerFinderImp>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Tunable constants
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// How often our timer goes off to consult outside sources for IPs
|
||||||
|
secondsPerUpdate = 1 * 60 * 60, // once per hour
|
||||||
|
// How often we announce our IP
|
||||||
|
secondsPerBroadcast = 5 * 60,
|
||||||
|
|
||||||
|
// The minimum number of peers we want
|
||||||
|
numberOfPeersMinimum = 4,
|
||||||
|
numberOfPeersMaximum = 10,
|
||||||
|
|
||||||
|
// The minimum number of seconds a connection ought to be sustained
|
||||||
|
// before we consider it "stable"
|
||||||
|
secondsForStability = 60, // one minute
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** The Logic for maintaining the list of Peer addresses.
|
||||||
|
We keep this in a separate class so it can be instantiated
|
||||||
|
for unit tests.
|
||||||
|
*/
|
||||||
|
class Logic
|
||||||
|
{
|
||||||
|
Callback &m_callback;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Logic (Callback& callback)
|
||||||
|
: m_callback (callback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called on the PeerFinder thread
|
||||||
|
void onUpdateConnectionsStatus (
|
||||||
|
Connections const& connections)
|
||||||
|
{
|
||||||
|
if (connections.numberTotal () < numberOfPeersMinimum)
|
||||||
|
{
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// do something?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPeerConnected (
|
||||||
|
const PeerId& id)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPeerDisconnected (
|
||||||
|
const PeerId& id)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAcceptTimer()
|
||||||
|
{
|
||||||
|
m_callback.onAnnounceAddress ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PeerFinderImp (Callback& callback)
|
||||||
|
: m_logic (callback)
|
||||||
|
, m_thread ("PeerFinder")
|
||||||
|
, m_acceptTimer (this)
|
||||||
|
, m_updateTimer (this)
|
||||||
|
{
|
||||||
|
m_thread.start (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PeerFinderImp ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateConnectionsStatus (Connections& connections)
|
||||||
|
{
|
||||||
|
// Queue the call to the logic
|
||||||
|
m_thread.call (&Logic::onUpdateConnectionsStatus,
|
||||||
|
&m_logic, connections);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPeerConnected(const PeerId& id)
|
||||||
|
{
|
||||||
|
m_thread.call (&Logic::onPeerConnected,
|
||||||
|
&m_logic, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPeerDisconnected(const PeerId& id)
|
||||||
|
{
|
||||||
|
m_thread.call (&Logic::onPeerDisconnected,
|
||||||
|
&m_logic, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
void onAcceptTimer ()
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
static int x = 0;
|
||||||
|
|
||||||
|
if(x == 0)
|
||||||
|
Debug::breakPoint ();
|
||||||
|
|
||||||
|
x++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDeadlineTimer (DeadlineTimer& timer)
|
||||||
|
{
|
||||||
|
// This will make us fall into the idle proc as needed
|
||||||
|
//
|
||||||
|
if (timer == m_updateTimer)
|
||||||
|
m_thread.interrupt ();
|
||||||
|
else if (timer == m_acceptTimer)
|
||||||
|
m_thread.call (&Logic::onAcceptTimer, &m_logic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void threadInit ()
|
||||||
|
{
|
||||||
|
m_updateTimer.setRecurringExpiration (secondsPerUpdate);
|
||||||
|
m_acceptTimer.setRecurringExpiration (secondsPerBroadcast);
|
||||||
|
}
|
||||||
|
|
||||||
|
void threadExit ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool threadIdle ()
|
||||||
|
{
|
||||||
|
bool interrupted = false;
|
||||||
|
|
||||||
|
// This is where you can go into a loop and do stuff
|
||||||
|
// like process the lists, and what not. Just be
|
||||||
|
// sure to call:
|
||||||
|
//
|
||||||
|
// @code
|
||||||
|
// interrupted = interruptionPoint ();
|
||||||
|
// @encode
|
||||||
|
//
|
||||||
|
// From time to time. If it returns true then you
|
||||||
|
// need to exit this function so that Thread can
|
||||||
|
// process its asynchronous call queue and then come
|
||||||
|
// back into threadIdle()
|
||||||
|
|
||||||
|
return interrupted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logic m_logic;
|
||||||
|
ThreadWithCallQueue m_thread;
|
||||||
|
DeadlineTimer m_acceptTimer;
|
||||||
|
DeadlineTimer m_updateTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
PeerFinder* PeerFinder::New (PeerFinder::Callback& callback)
|
||||||
|
{
|
||||||
|
return new PeerFinderImp (callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class PeerFinderTests : public UnitTest,
|
||||||
|
public PeerFinder::Callback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void testValidityChecks ()
|
||||||
|
{
|
||||||
|
beginTestCase ("ip validation");
|
||||||
|
|
||||||
|
fail ("there's no code!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void runTest ()
|
||||||
|
{
|
||||||
|
PeerFinderImp::Logic logic (*this);
|
||||||
|
|
||||||
|
beginTestCase ("logic");
|
||||||
|
logic.onAcceptTimer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAnnounceAddress ()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerFinderTests () : UnitTest ("PeerFinder", "ripple", runManual)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static PeerFinderTests peerFinderTests;
|
||||||
|
|
||||||
145
src/ripple_core/peerfinder/ripple_PeerFinder.h
Normal file
145
src/ripple_core/peerfinder/ripple_PeerFinder.h
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_PEERFINDER_H_INCLUDED
|
||||||
|
#define RIPPLE_PEERFINDER_H_INCLUDED
|
||||||
|
|
||||||
|
/** The identifier we use to track peers in peerfinder
|
||||||
|
*/
|
||||||
|
typedef uint160 PeerId;
|
||||||
|
|
||||||
|
|
||||||
|
/** Maintains a set of IP addresses used for getting into the network.
|
||||||
|
*/
|
||||||
|
class PeerFinder : public Uncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Describes the state of our currently connected peers
|
||||||
|
*/
|
||||||
|
struct Connections
|
||||||
|
{
|
||||||
|
int numberIncoming; // number of inbound Peers
|
||||||
|
int numberOutgoing; // number of outbound Peers
|
||||||
|
|
||||||
|
inline int numberTotal () const noexcept
|
||||||
|
{
|
||||||
|
return numberIncoming + numberOutgoing;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** An abstract address that can be turned into a socket endpoint.
|
||||||
|
*/
|
||||||
|
struct Address
|
||||||
|
{
|
||||||
|
virtual String asString () = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** An IPv4 address.
|
||||||
|
*/
|
||||||
|
struct AddressIPv4 : Address
|
||||||
|
{
|
||||||
|
AddressIPv4 (InputParser::IPv4Address const& address, uint16 port)
|
||||||
|
: m_address (address)
|
||||||
|
, m_port (port)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
String asString ()
|
||||||
|
{
|
||||||
|
return String () +
|
||||||
|
String (m_address.value [0]) + "." +
|
||||||
|
String (m_address.value [1]) + "." +
|
||||||
|
String (m_address.value [2]) + "." +
|
||||||
|
String (m_address.value [3]) + ":" +
|
||||||
|
String (m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputParser::IPv4Address m_address;
|
||||||
|
uint16 m_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** The Callback receives Peerfinder notifications.
|
||||||
|
The notifications are sent on a thread owned by the PeerFinder,
|
||||||
|
so it is best not to do too much work in here. Just post functor
|
||||||
|
to another worker thread or job queue and return.
|
||||||
|
*/
|
||||||
|
struct Callback
|
||||||
|
{
|
||||||
|
/** Announces our listening ip/port combinations to the network.
|
||||||
|
|
||||||
|
@param address The address to broadcast.
|
||||||
|
*/
|
||||||
|
virtual void onAnnounceAddress () = 0;
|
||||||
|
|
||||||
|
/** Indicates whether or not incoming connections should be accepted.
|
||||||
|
When we are full on incoming connections, future incoming
|
||||||
|
connections from valid peers should be politely turned away,
|
||||||
|
after giving them a random sample of other addresses to try
|
||||||
|
from our cache.
|
||||||
|
*/
|
||||||
|
//virtual void onSetAcceptStatus (bool shouldAcceptIncoming) = 0;
|
||||||
|
|
||||||
|
/** Called periodically to update the callback's list of eligible addresses.
|
||||||
|
This is used for making new outgoing connections, for
|
||||||
|
handing out addresses to peers, and for periodically seeding the
|
||||||
|
network wth hop-limited broadcasts of IP addresses.
|
||||||
|
*/
|
||||||
|
//virtual void onNewAddressesAvailable (std::vector <Address> const& list) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Create a new PeerFinder object.
|
||||||
|
*/
|
||||||
|
static PeerFinder* New (Callback& callback);
|
||||||
|
|
||||||
|
/** Destroy the object.
|
||||||
|
|
||||||
|
Any pending source fetch operations are aborted.
|
||||||
|
|
||||||
|
There may be some listener calls made before the
|
||||||
|
destructor returns.
|
||||||
|
*/
|
||||||
|
virtual ~PeerFinder () { }
|
||||||
|
|
||||||
|
/** Inform the PeerFinder of the status of our connections.
|
||||||
|
|
||||||
|
This call queues an asynchronous operation to the PeerFinder's thread
|
||||||
|
and returns immediately. Normally this is called by the Peer code
|
||||||
|
when the counts change.
|
||||||
|
|
||||||
|
Thread-safety:
|
||||||
|
Safe to call from any thread
|
||||||
|
|
||||||
|
@see Peer
|
||||||
|
*/
|
||||||
|
virtual void updateConnectionsStatus (Connections& connections) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/** Called when a new peer connection is established.
|
||||||
|
Internally, we add the peer to our tracking table, validate that
|
||||||
|
we can connect to it, and begin advertising it to others after
|
||||||
|
we are sure that its connection is stable.
|
||||||
|
*/
|
||||||
|
virtual void onPeerConnected(const PeerId& id) = 0;
|
||||||
|
|
||||||
|
/** Called when an existing peer connection drops for whatever reason.
|
||||||
|
Internally, we mark the peer as no longer connected, calculate
|
||||||
|
stability metrics, and consider whether we should try to reconnect
|
||||||
|
to it or drop it from our list.
|
||||||
|
*/
|
||||||
|
virtual void onPeerDisconnected(const PeerId& id) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#include "ripple_core.h"
|
#include "ripple_core.h"
|
||||||
|
|
||||||
|
// Needed for InputParser
|
||||||
|
#include "beast/modules/beast_asio/beast_asio.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
|
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
|
||||||
@@ -71,4 +74,7 @@ namespace ripple
|
|||||||
#include "validator/ValidatorSourceTrustedURL.cpp"
|
#include "validator/ValidatorSourceTrustedURL.cpp"
|
||||||
#include "validator/Validators.cpp"
|
#include "validator/Validators.cpp"
|
||||||
|
|
||||||
|
#include "peerfinder/ripple_PeerFinder.h" // private (for now)
|
||||||
|
#include "peerfinder/ripple_PeerFinder.cpp"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace ripple
|
|||||||
#include "node/NodeObject.h"
|
#include "node/NodeObject.h"
|
||||||
#include "node/NodeStore.h"
|
#include "node/NodeStore.h"
|
||||||
|
|
||||||
|
#include "peerfinder/ripple_PeerFinder.h"
|
||||||
#include "validator/Validators.h"
|
#include "validator/Validators.h"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ enum MessageType
|
|||||||
mtCONTACT = 11;
|
mtCONTACT = 11;
|
||||||
mtGET_PEERS = 12;
|
mtGET_PEERS = 12;
|
||||||
mtPEERS = 13;
|
mtPEERS = 13;
|
||||||
|
mtANNOUNCE = 14;
|
||||||
|
|
||||||
// operations for 'small' nodes
|
// operations for 'small' nodes
|
||||||
mtSEARCH_TRANSACTION = 20;
|
mtSEARCH_TRANSACTION = 20;
|
||||||
@@ -228,6 +229,14 @@ message TMPeers
|
|||||||
repeated TMIPv4EndPoint nodes = 1;
|
repeated TMIPv4EndPoint nodes = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message TMAnnounce
|
||||||
|
{
|
||||||
|
required bytes serverID = 1; // The ID of this server
|
||||||
|
required bool privatePeer = 2; // This peer is private - the announce will not be propagated
|
||||||
|
required uint32 hopCount = 3; // The hop count of this server
|
||||||
|
required bytes viaPeerID = 4; // The ID of the peer through which we know this server
|
||||||
|
repeated TMIPv4EndPoint connectPoints = 5; // Addresses on which this server accepts connections (can be empty)
|
||||||
|
};
|
||||||
|
|
||||||
message TMSearchTransaction
|
message TMSearchTransaction
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user