Skip to content

Commit

Permalink
Merge #8282: net: Feeler connections to increase online addrs in the …
Browse files Browse the repository at this point in the history
…tried table.

dbb1f64 Added feeler connections increasing good addrs in the tried table. (Ethan Heilman)
  • Loading branch information
laanwj authored and sickpig committed Apr 14, 2017
1 parent ac53931 commit 40f8ffc
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 10 deletions.
6 changes: 6 additions & 0 deletions src/main.cpp
Expand Up @@ -5253,6 +5253,12 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t

if (strCommand == NetMsgType::VERSION)
{
// Feeler connections exist only to verify if address is online.
if (pfrom->fFeeler) {
assert(pfrom->fInbound == false);
pfrom->fDisconnect = true;
}

// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
Expand Down
62 changes: 53 additions & 9 deletions src/net.cpp
Expand Up @@ -47,6 +47,9 @@
// Dump addresses to peers.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900

// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1

#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
Expand All @@ -66,6 +69,7 @@ using namespace std;

namespace {
// BU replaced this with a configuration option const int MAX_OUTBOUND_CONNECTIONS = 8;
const int MAX_FEELER_CONNECTIONS = 1;

struct ListenSocket {
SOCKET socket;
Expand Down Expand Up @@ -1097,7 +1101,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
LOCK(cs_vAddedNodes);
nMaxAddNodeOutbound = std::min((int)vAddedNodes.size(), nMaxOutConnections);
}
int nMaxInbound = nMaxConnections - nMaxOutConnections - nMaxAddNodeOutbound;
int nMaxInbound = nMaxConnections - (nMaxOutConnections + MAX_FEELER_CONNECTIONS) - nMaxAddNodeOutbound;
assert(nMaxInbound > 0);
//REVISIT: a. This doesn't take into account RPC "addnode <node> onetry" outbound connections as those aren't tracked
// b. This also doesn't take into account whether or not the tracked vAddedNodes are valid or connected
// c. There is also an edge case where if less than nMaxOutConnections entries exist in vAddedNodes
Expand Down Expand Up @@ -1747,7 +1752,11 @@ void ThreadOpenConnections()

// Initiate network connections
int64_t nStart = GetTime();
while (true) {

// Minimum time before next feeler connection (in microseconds).
int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
while (true)
{
ProcessOneShot();

MilliSleep(500);
Expand Down Expand Up @@ -1783,12 +1792,36 @@ void ThreadOpenConnections()
}
}
}
assert(nOutbound <= (nMaxOutConnections + MAX_FEELER_CONNECTIONS));

int64_t nANow = GetAdjustedTime();
// Feeler Connections
//
// Design goals:
// * Increase the number of connectable addresses in the tried table.
//
// Method:
// * Choose a random address from new and attempt to connect to it if we can connect
// successfully it is added to tried.
// * Start attempting feeler connections only after node finishes making outbound
// connections.
// * Only make a feeler connection once every few minutes.
//
bool fFeeler = false;
if (nOutbound >= nMaxOutConnections) {
int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
if (nTime > nNextFeeler) {
nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
fFeeler = true;
} else {
continue;
}
}

int64_t nANow = GetAdjustedTime();
int nTries = 0;
while (true) {
CAddrInfo addr = addrman.Select();
while (true)
{
CAddrInfo addr = addrman.Select(fFeeler);

// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
Expand Down Expand Up @@ -1818,8 +1851,16 @@ void ThreadOpenConnections()

if (addrConnect.IsValid())
{
if (fFeeler)
{
// Add small amount of random noise before connection to avoid synchronization.
int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
MilliSleep(randsleep);
LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString());
}

//Seeded outbound connections track against the original semaphore
OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant);
OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, NULL, false, fFeeler);
}
}
}
Expand Down Expand Up @@ -1920,7 +1961,7 @@ void ThreadOpenAddedConnections()
}

// if successful, this moves the passed grant to the constructed node
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
{

//
Expand Down Expand Up @@ -1950,6 +1991,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem
pnode->fNetworkNode = true;
if (fOneShot)
pnode->fOneShot = true;
if (fFeeler)
pnode->fFeeler = true;

return true;
}
Expand Down Expand Up @@ -2203,7 +2246,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)

if (semOutbound == NULL) {
// initialize semaphore
int nMaxOutbound = min(nMaxOutConnections, nMaxConnections);
int nMaxOutbound = min((nMaxOutConnections + MAX_FEELER_CONNECTIONS), nMaxConnections);
semOutbound = new CSemaphore(nMaxOutbound);
}

Expand Down Expand Up @@ -2262,7 +2305,7 @@ bool StopNode()
LogPrintf("StopNode()\n");
MapPort(false);
if (semOutbound)
for (int i=0; i<nMaxOutConnections; i++)
for (int i=0; i<(nMaxOutConnections + MAX_FEELER_CONNECTIONS); i++)
semOutbound->post();

if (fAddressesInitialized)
Expand Down Expand Up @@ -2637,6 +2680,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fWhitelisted = false;
fOneShot = false;
fClient = false; // set by version message
fFeeler = false;
fInbound = fInboundIn;
fNetworkNode = false;
fSuccessfullyConnected = false;
Expand Down
5 changes: 4 additions & 1 deletion src/net.h
Expand Up @@ -44,6 +44,8 @@ namespace boost {
static const int PING_INTERVAL = 2 * 60;
/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
static const int TIMEOUT_INTERVAL = 20 * 60;
/** Run the feeler connection loop once every 2 minutes or 120 seconds. **/
static const int FEELER_INTERVAL = 120;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
/** The maximum number of new addresses to accumulate before announcing. */
Expand Down Expand Up @@ -98,7 +100,7 @@ CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
int DisconnectSubNetNodes(const CSubNet& subNet);
CNode* ConnectNode(CAddress addrConnect, const char* pszDest = NULL);
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService& bindAddr, std::string& strError, bool fWhitelisted = false);
Expand Down Expand Up @@ -373,6 +375,7 @@ class CNode
// the network or wire types and the cleaned string used when displayed or logged.
std::string strSubVer, cleanSubVer;
bool fWhitelisted; // This peer can bypass DoS banning.
bool fFeeler; // If true this node is being used as a short lived feeler.
bool fOneShot;
bool fClient;
bool fInbound;
Expand Down
22 changes: 22 additions & 0 deletions src/test/net_tests.cpp
Expand Up @@ -133,4 +133,26 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_CHECK(addrman2.size() == 0);
}

BOOST_AUTO_TEST_CASE(cnode_simple_test)
{
SOCKET hSocket = INVALID_SOCKET;

in_addr ipv4Addr;
ipv4Addr.s_addr = 0xa0b0c001;

CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
std::string pszDest = "";
bool fInboundIn = false;

// Test that fFeeler is false by default.
CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn);
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);

fInboundIn = true;
CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn);
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 40f8ffc

Please sign in to comment.