mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-03 09:25:51 +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)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple_core\ripple_core.cpp" />
|
||||
<ClCompile Include="..\..\src\ripple_core\test\TestOverlay.cpp">
|
||||
<ClCompile Include="..\..\modules\ripple_core\test\TestOverlay.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\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">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|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\NodeStore.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\test\ConnectionType.h" />
|
||||
<ClInclude Include="..\..\src\ripple_core\test\InitPolicy.h" />
|
||||
|
||||
@@ -154,6 +154,9 @@
|
||||
<Filter Include="[2] doc">
|
||||
<UniqueIdentifier>{c69b07a2-44e5-4b06-99a9-81f5d137ea15}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="[1] Ripple\ripple_core\peerfinder">
|
||||
<UniqueIdentifier>{d1648d3f-7d71-495d-afc9-576ed00d7185}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\ripple_basics\containers\ripple_RangeSet.cpp">
|
||||
@@ -219,9 +222,6 @@
|
||||
<ClCompile Include="..\..\src\ripple_core\functional\ripple_LoadMonitor.cpp">
|
||||
<Filter>[1] Ripple\ripple_core\functional</Filter>
|
||||
</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">
|
||||
<Filter>[1] Ripple\ripple_data\crypto</Filter>
|
||||
</ClCompile>
|
||||
@@ -840,9 +840,6 @@
|
||||
<ClCompile Include="..\..\src\ripple_core\validator\Validators.cpp">
|
||||
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
||||
</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">
|
||||
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
||||
</ClCompile>
|
||||
@@ -876,6 +873,13 @@
|
||||
<ClCompile Include="..\..\src\beast\modules\beast_sqlite\beast_sqlite.c">
|
||||
<Filter>[0] src\beast</Filter>
|
||||
</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>
|
||||
<ClInclude Include="..\..\src\ripple_app\ripple_app.h">
|
||||
@@ -1728,6 +1732,9 @@
|
||||
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\BeastConfig.h" />
|
||||
<ClInclude Include="..\..\src\ripple_core\peerfinder\ripple_PeerFinder.h">
|
||||
<Filter>[1] Ripple\ripple_core\peerfinder</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\ripple_data\protocol\ripple.proto">
|
||||
|
||||
@@ -173,4 +173,12 @@
|
||||
#define RIPPLE_APPLICATION_CLEAN_EXIT 0
|
||||
#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
|
||||
|
||||
@@ -17,6 +17,7 @@ class ApplicationImp
|
||||
, public SharedSingleton <ApplicationImp>
|
||||
, public NodeStore::Scheduler
|
||||
, LeakChecked <ApplicationImp>
|
||||
, PeerFinder::Callback
|
||||
{
|
||||
public:
|
||||
// RAII container for a boost::asio::io_service run by beast threads
|
||||
@@ -175,6 +176,7 @@ public:
|
||||
, mUNL (UniqueNodeList::New ())
|
||||
, mProofOfWorkFactory (ProofOfWorkFactory::New ())
|
||||
, m_loadManager (LoadManager::New ())
|
||||
, mPeerFinder (PeerFinder::New (*this))
|
||||
// VFALCO End new stuff
|
||||
// VFALCO TODO replace all NULL with nullptr
|
||||
, mRpcDB (NULL)
|
||||
@@ -366,6 +368,11 @@ public:
|
||||
return *m_peers;
|
||||
}
|
||||
|
||||
PeerFinder& getPeerFinder ()
|
||||
{
|
||||
return *mPeerFinder;
|
||||
}
|
||||
|
||||
// VFALCO TODO Move these to the .cpp
|
||||
bool running ()
|
||||
{
|
||||
@@ -698,6 +705,8 @@ private:
|
||||
void startNewLedger ();
|
||||
bool loadOldLedger (const std::string&, bool);
|
||||
|
||||
void onAnnounceAddress ();
|
||||
|
||||
private:
|
||||
Application::LockType mMasterLock;
|
||||
|
||||
@@ -735,6 +744,7 @@ private:
|
||||
ScopedPointer <PeerDoor> m_peerProxyDoor;
|
||||
ScopedPointer <WSDoor> m_wsPublicDoor;
|
||||
ScopedPointer <WSDoor> m_wsPrivateDoor;
|
||||
ScopedPointer <PeerFinder> mPeerFinder;
|
||||
// VFALCO End Clean stuff
|
||||
|
||||
DatabaseCon* mRpcDB;
|
||||
@@ -1189,6 +1199,11 @@ void ApplicationImp::updateTables ()
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationImp::onAnnounceAddress ()
|
||||
{
|
||||
// NIKB CODEME
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Application& getApp ()
|
||||
|
||||
@@ -28,6 +28,7 @@ class SerializedLedgerEntry;
|
||||
class TransactionMaster;
|
||||
class TxQueue;
|
||||
class LocalCredentials;
|
||||
class PeerFinder;
|
||||
|
||||
class DatabaseCon;
|
||||
|
||||
@@ -95,6 +96,7 @@ public:
|
||||
virtual TransactionMaster& getMasterTransaction () = 0;
|
||||
virtual TxQueue& getTxQueue () = 0;
|
||||
virtual LocalCredentials& getLocalCredentials () = 0;
|
||||
virtual PeerFinder& getPeerFinder () = 0;
|
||||
|
||||
virtual DatabaseCon* getRpcDB () = 0;
|
||||
virtual DatabaseCon* getTxnDB () = 0;
|
||||
|
||||
@@ -335,6 +335,7 @@ private:
|
||||
void sendPacketForce (const PackedMessage::pointer & packet);
|
||||
|
||||
void sendHello ();
|
||||
void SendAnnounce ();
|
||||
|
||||
void recvHello (protocol::TMHello & packet);
|
||||
void recvCluster (protocol::TMCluster & packet);
|
||||
@@ -345,6 +346,7 @@ private:
|
||||
void recvGetContacts (protocol::TMGetContacts & packet);
|
||||
void recvGetPeers (protocol::TMGetPeers & packet, Application::ScopedLockType& masterLockHolder);
|
||||
void recvPeers (protocol::TMPeers & packet);
|
||||
void recvAnnounce (protocol::TMAnnounce & packet);
|
||||
void recvGetObjectByHash (const boost::shared_ptr<protocol::TMGetObjectByHash>& packet);
|
||||
void recvPing (protocol::TMPing & packet);
|
||||
void recvErrorMessage (protocol::TMErrorMsg & packet);
|
||||
@@ -834,6 +836,17 @@ void PeerImp::processReadBuffer ()
|
||||
}
|
||||
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:
|
||||
{
|
||||
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)
|
||||
{
|
||||
protocol::TMGetObjectByHash& packet = *ptr;
|
||||
@@ -2362,6 +2384,32 @@ void PeerImp::sendHello ()
|
||||
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 ()
|
||||
{
|
||||
// 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"
|
||||
|
||||
// Needed for InputParser
|
||||
#include "beast/modules/beast_asio/beast_asio.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
|
||||
@@ -71,4 +74,7 @@ namespace ripple
|
||||
#include "validator/ValidatorSourceTrustedURL.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/NodeStore.h"
|
||||
|
||||
#include "peerfinder/ripple_PeerFinder.h"
|
||||
#include "validator/Validators.h"
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ enum MessageType
|
||||
mtCONTACT = 11;
|
||||
mtGET_PEERS = 12;
|
||||
mtPEERS = 13;
|
||||
mtANNOUNCE = 14;
|
||||
|
||||
// operations for 'small' nodes
|
||||
mtSEARCH_TRANSACTION = 20;
|
||||
@@ -228,6 +229,14 @@ message TMPeers
|
||||
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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user