@ -43,6 +43,9 @@
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
# define DUMP_ADDRESSES_INTERVAL 900
# 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)
# if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
# define MSG_NOSIGNAL 0
# define MSG_NOSIGNAL 0
# endif
# endif
@ -61,6 +64,7 @@
namespace {
namespace {
const int MAX_OUTBOUND_CONNECTIONS = 8 ;
const int MAX_OUTBOUND_CONNECTIONS = 8 ;
const int MAX_FEELER_CONNECTIONS = 1 ;
struct ListenSocket {
struct ListenSocket {
SOCKET socket ;
SOCKET socket ;
@ -1017,7 +1021,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
SOCKET hSocket = accept ( hListenSocket . socket , ( struct sockaddr * ) & sockaddr , & len ) ;
SOCKET hSocket = accept ( hListenSocket . socket , ( struct sockaddr * ) & sockaddr , & len ) ;
CAddress addr ;
CAddress addr ;
int nInbound = 0 ;
int nInbound = 0 ;
int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS ;
int nMaxInbound = nMaxConnections - ( MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS ) ;
assert ( nMaxInbound > 0 ) ;
if ( hSocket ! = INVALID_SOCKET )
if ( hSocket ! = INVALID_SOCKET )
if ( ! addr . SetSockAddr ( ( const struct sockaddr * ) & sockaddr ) )
if ( ! addr . SetSockAddr ( ( const struct sockaddr * ) & sockaddr ) )
@ -1613,6 +1618,9 @@ void ThreadOpenConnections()
// Initiate network connections
// Initiate network connections
int64_t nStart = GetTime ( ) ;
int64_t nStart = GetTime ( ) ;
// Minimum time before next feeler connection (in microseconds).
int64_t nNextFeeler = PoissonNextSend ( nStart * 1000 * 1000 , FEELER_INTERVAL ) ;
while ( true )
while ( true )
{
{
ProcessOneShot ( ) ;
ProcessOneShot ( ) ;
@ -1652,13 +1660,36 @@ void ThreadOpenConnections()
}
}
}
}
}
}
assert ( nOutbound < = ( MAX_OUTBOUND_CONNECTIONS + 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 > = MAX_OUTBOUND_CONNECTIONS ) {
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 ;
int nTries = 0 ;
while ( true )
while ( true )
{
{
CAddrInfo addr = addrman . Select ( ) ;
CAddrInfo addr = addrman . Select ( fFeeler ) ;
// if we selected an invalid address, restart
// if we selected an invalid address, restart
if ( ! addr . IsValid ( ) | | setConnected . count ( addr . GetGroup ( ) ) | | IsLocal ( addr ) )
if ( ! addr . IsValid ( ) | | setConnected . count ( addr . GetGroup ( ) ) | | IsLocal ( addr ) )
@ -1694,8 +1725,17 @@ void ThreadOpenConnections()
break ;
break ;
}
}
if ( addrConnect . IsValid ( ) )
if ( addrConnect . IsValid ( ) ) {
OpenNetworkConnection ( addrConnect , ( int ) setConnected . size ( ) > = std : : min ( nMaxConnections - 1 , 2 ) , & grant ) ;
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 ( ) ) ;
}
OpenNetworkConnection ( addrConnect , ( int ) setConnected . size ( ) > = std : : min ( nMaxConnections - 1 , 2 ) , & grant , NULL , false , fFeeler ) ;
}
}
}
}
}
@ -1777,7 +1817,7 @@ void ThreadOpenAddedConnections()
}
}
// if successful, this moves the passed grant to the constructed node
// 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 )
{
{
//
//
// Initiate outbound network connection
// Initiate outbound network connection
@ -1801,6 +1841,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem
pnode - > fNetworkNode = true ;
pnode - > fNetworkNode = true ;
if ( fOneShot )
if ( fOneShot )
pnode - > fOneShot = true ;
pnode - > fOneShot = true ;
if ( fFeeler )
pnode - > fFeeler = true ;
return true ;
return true ;
}
}
@ -2062,7 +2104,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if ( semOutbound = = NULL ) {
if ( semOutbound = = NULL ) {
// initialize semaphore
// initialize semaphore
int nMaxOutbound = std : : min ( MAX_OUTBOUND_CONNECTIONS , nMaxConnections ) ;
int nMaxOutbound = std : : min ( ( MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS ) , nMaxConnections ) ;
semOutbound = new CSemaphore ( nMaxOutbound ) ;
semOutbound = new CSemaphore ( nMaxOutbound ) ;
}
}
@ -2107,7 +2149,7 @@ bool StopNode()
LogPrintf ( " StopNode() \n " ) ;
LogPrintf ( " StopNode() \n " ) ;
MapPort ( false ) ;
MapPort ( false ) ;
if ( semOutbound )
if ( semOutbound )
for ( int i = 0 ; i < MAX_OUTBOUND_CONNECTIONS ; i + + )
for ( int i = 0 ; i < ( MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS ) ; i + + )
semOutbound - > post ( ) ;
semOutbound - > post ( ) ;
if ( fAddressesInitialized )
if ( fAddressesInitialized )
@ -2448,6 +2490,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fWhitelisted = false ;
fWhitelisted = false ;
fOneShot = false ;
fOneShot = false ;
fClient = false ; // set by version message
fClient = false ; // set by version message
fFeeler = false ;
fInbound = fInboundIn ;
fInbound = fInboundIn ;
fNetworkNode = false ;
fNetworkNode = false ;
fSuccessfullyConnected = false ;
fSuccessfullyConnected = false ;