2010-08-29 18:58:15 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2018-01-02 18:12:05 +01:00
// Copyright (c) 2009-2017 The Bitcoin Core developers
2014-12-13 05:09:33 +01:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 16:02:28 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2010-08-29 18:58:15 +02:00
2013-05-28 01:55:01 +02:00
# if defined(HAVE_CONFIG_H)
2017-11-10 01:57:53 +01:00
# include <config/bitcoin-config.h>
2013-05-28 01:55:01 +02:00
# endif
2017-11-10 01:57:53 +01:00
# include <net.h>
# include <chainparams.h>
# include <clientversion.h>
# include <consensus/consensus.h>
# include <crypto/common.h>
# include <crypto/sha256.h>
# include <primitives/transaction.h>
# include <netbase.h>
# include <scheduler.h>
# include <ui_interface.h>
# include <utilstrencodings.h>
2013-04-13 07:13:08 +02:00
2011-10-07 17:02:21 +02:00
# ifdef WIN32
2011-07-02 03:59:37 +02:00
# include <string.h>
2013-04-13 07:13:08 +02:00
# else
2013-07-17 10:51:40 +02:00
# include <fcntl.h>
# endif
2011-03-26 13:01:27 +01:00
# ifdef USE_UPNP
# include <miniupnpc/miniupnpc.h>
2013-04-13 07:13:08 +02:00
# include <miniupnpc/miniwget.h>
2011-03-26 13:01:27 +01:00
# include <miniupnpc/upnpcommands.h>
# include <miniupnpc/upnperrors.h>
# endif
2014-01-30 10:55:55 +01:00
2015-04-08 20:20:00 +02:00
# include <math.h>
2015-07-03 09:46:17 +02:00
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
2013-06-24 00:23:28 +02:00
# define DUMP_ADDRESSES_INTERVAL 900
2013-04-13 07:13:08 +02:00
2016-06-17 06:10:07 +02:00
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
# define FEELER_SLEEP_WINDOW 1
2017-03-05 10:32:00 +01:00
# if !defined(HAVE_MSG_NOSIGNAL)
2013-05-28 01:55:01 +02:00
# define MSG_NOSIGNAL 0
# endif
2013-06-24 00:23:28 +02:00
2017-03-05 10:32:00 +01:00
// MSG_DONTWAIT is not available on some platforms, if it doesn't exist define it as 0
# if !defined(HAVE_MSG_DONTWAIT)
# define MSG_DONTWAIT 0
# endif
2014-06-24 09:03:18 +02:00
// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
# ifdef WIN32
# ifndef PROTECTION_LEVEL_UNRESTRICTED
# define PROTECTION_LEVEL_UNRESTRICTED 10
# endif
# ifndef IPV6_PROTECTION_LEVEL
# define IPV6_PROTECTION_LEVEL 23
# endif
# endif
2017-06-01 12:34:02 +02:00
/** Used to pass flags to the Bind() function */
enum BindFlags {
BF_NONE = 0 ,
BF_EXPLICIT = ( 1U < < 0 ) ,
BF_REPORT_ERROR = ( 1U < < 1 ) ,
BF_WHITELIST = ( 1U < < 2 ) ,
} ;
2015-08-25 16:30:31 +02:00
const static std : : string NET_MESSAGE_COMMAND_OTHER = " *other* " ;
2016-09-09 12:48:10 +02:00
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL ; // SHA256("netgroup")[0:8]
2016-10-26 21:10:15 +02:00
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL ; // SHA256("localhostnonce")[0:8]
2010-08-29 18:58:15 +02:00
//
// Global state variables
//
2012-05-24 19:02:21 +02:00
bool fDiscover = true ;
2014-05-29 12:33:17 +02:00
bool fListen = true ;
2016-05-12 14:00:22 +02:00
bool fRelayTxes = true ;
2014-05-05 13:22:28 +02:00
CCriticalSection cs_mapLocalHost ;
2016-04-16 01:53:45 +02:00
std : : map < CNetAddr , LocalServiceInfo > mapLocalHost ;
2012-05-04 16:46:22 +02:00
static bool vfLimited [ NET_MAX ] = { } ;
2015-07-31 18:05:42 +02:00
std : : string strSubVersion ;
2010-08-29 18:58:15 +02:00
2016-04-11 18:52:29 +02:00
limitedmap < uint256 , int64_t > mapAlreadyAskedFor ( MAX_INV_SZ ) ;
2010-08-29 18:58:15 +02:00
2016-04-16 23:51:01 +02:00
void CConnman : : AddOneShot ( const std : : string & strDest )
2012-04-24 02:15:00 +02:00
{
LOCK ( cs_vOneShots ) ;
vOneShots . push_back ( strDest ) ;
}
2011-04-21 16:45:08 +02:00
unsigned short GetListenPort ( )
{
2017-08-01 21:17:40 +02:00
return ( unsigned short ) ( gArgs . GetArg ( " -port " , Params ( ) . GetDefaultPort ( ) ) ) ;
2011-04-21 16:45:08 +02:00
}
2010-08-29 18:58:15 +02:00
2012-02-12 13:45:24 +01:00
// find 'best' local address for a particular peer
2012-05-10 20:35:13 +02:00
bool GetLocal ( CService & addr , const CNetAddr * paddrPeer )
2012-02-12 13:45:24 +01:00
{
2014-05-29 12:33:17 +02:00
if ( ! fListen )
2012-02-12 13:45:24 +01:00
return false ;
2010-08-29 18:58:15 +02:00
2012-05-13 00:41:24 +02:00
int nBestScore = - 1 ;
2012-02-12 13:45:24 +01:00
int nBestReachability = - 1 ;
{
LOCK ( cs_mapLocalHost ) ;
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapLocalHost )
2012-02-12 13:45:24 +01:00
{
2017-06-04 22:02:43 +02:00
int nScore = entry . second . nScore ;
int nReachability = entry . first . GetReachabilityFrom ( paddrPeer ) ;
2012-05-13 00:41:24 +02:00
if ( nReachability > nBestReachability | | ( nReachability = = nBestReachability & & nScore > nBestScore ) )
2012-02-12 13:45:24 +01:00
{
2017-06-04 22:02:43 +02:00
addr = CService ( entry . first , entry . second . nPort ) ;
2012-02-12 13:45:24 +01:00
nBestReachability = nReachability ;
2012-05-13 00:41:24 +02:00
nBestScore = nScore ;
2012-02-12 13:45:24 +01:00
}
}
}
2012-05-13 00:41:24 +02:00
return nBestScore > = 0 ;
2012-02-12 13:45:24 +01:00
}
2010-08-29 18:58:15 +02:00
2015-01-24 05:40:50 +01:00
//! Convert the pnSeeds6 array into usable address objects.
static std : : vector < CAddress > convertSeed6 ( const std : : vector < SeedSpec6 > & vSeedsIn )
{
// It'll only connect to one or two seed nodes because once it connects,
// it'll get a pile of addresses with newer timestamps.
// Seed nodes are given a random 'last seen time' of between one and two
// weeks ago.
const int64_t nOneWeek = 7 * 24 * 60 * 60 ;
std : : vector < CAddress > vSeedsOut ;
vSeedsOut . reserve ( vSeedsIn . size ( ) ) ;
2017-07-20 11:32:47 +02:00
for ( const auto & seed_in : vSeedsIn ) {
2015-01-24 05:40:50 +01:00
struct in6_addr ip ;
2017-07-20 11:32:47 +02:00
memcpy ( & ip , seed_in . addr , sizeof ( ip ) ) ;
2017-10-19 23:32:33 +02:00
CAddress addr ( CService ( ip , seed_in . port ) , GetDesirableServiceFlags ( NODE_NONE ) ) ;
2015-01-24 05:40:50 +01:00
addr . nTime = GetTime ( ) - GetRand ( nOneWeek ) - nOneWeek ;
vSeedsOut . push_back ( addr ) ;
}
return vSeedsOut ;
}
2012-02-12 13:45:24 +01:00
// get best local address for a particular peer as a CAddress
2014-07-21 08:32:25 +02:00
// Otherwise, return the unroutable 0.0.0.0 but filled in with
// the normal parameters, since the IP may be changed to a useful
// one by discovery.
2016-04-19 06:04:58 +02:00
CAddress GetLocalAddress ( const CNetAddr * paddrPeer , ServiceFlags nLocalServices )
2012-02-12 13:45:24 +01:00
{
2017-05-18 22:57:53 +02:00
CAddress ret ( CService ( CNetAddr ( ) , GetListenPort ( ) ) , nLocalServices ) ;
2012-05-10 20:35:13 +02:00
CService addr ;
2012-02-12 13:45:24 +01:00
if ( GetLocal ( addr , paddrPeer ) )
{
2016-05-25 17:18:37 +02:00
ret = CAddress ( addr , nLocalServices ) ;
2012-02-12 13:45:24 +01:00
}
2014-07-21 08:32:25 +02:00
ret . nTime = GetAdjustedTime ( ) ;
2012-02-12 13:45:24 +01:00
return ret ;
}
2010-08-29 18:58:15 +02:00
2014-07-21 08:32:25 +02:00
int GetnScore ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
2014-07-21 08:32:25 +02:00
LOCK ( cs_mapLocalHost ) ;
if ( mapLocalHost . count ( addr ) = = LOCAL_NONE )
return 0 ;
return mapLocalHost [ addr ] . nScore ;
}
// Is our peer's addrLocal potentially useful as an external IP source?
bool IsPeerAddrLocalGood ( CNode * pnode )
{
2017-02-06 18:18:51 +01:00
CService addrLocal = pnode - > GetAddrLocal ( ) ;
return fDiscover & & pnode - > addr . IsRoutable ( ) & & addrLocal . IsRoutable ( ) & &
! IsLimited ( addrLocal . GetNetwork ( ) ) ;
2014-07-21 08:32:25 +02:00
}
// pushes our own address to a peer
2016-02-12 19:35:32 +01:00
void AdvertiseLocal ( CNode * pnode )
2014-07-21 08:32:25 +02:00
{
if ( fListen & & pnode - > fSuccessfullyConnected )
2012-02-12 13:45:24 +01:00
{
2016-04-19 06:04:58 +02:00
CAddress addrLocal = GetLocalAddress ( & pnode - > addr , pnode - > GetLocalServices ( ) ) ;
2014-07-21 08:32:25 +02:00
// If discovery is enabled, sometimes give our peer the address it
// tells us that it sees us as in case it has a better idea of our
// address than we do.
if ( IsPeerAddrLocalGood ( pnode ) & & ( ! addrLocal . IsRoutable ( ) | |
GetRand ( ( GetnScore ( addrLocal ) > LOCAL_MANUAL ) ? 8 : 2 ) = = 0 ) )
2012-02-12 13:45:24 +01:00
{
2017-02-06 18:18:51 +01:00
addrLocal . SetIP ( pnode - > GetAddrLocal ( ) ) ;
2014-07-21 08:32:25 +02:00
}
if ( addrLocal . IsRoutable ( ) )
{
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " AdvertiseLocal: advertising address %s \n " , addrLocal . ToString ( ) ) ;
2016-10-13 16:19:20 +02:00
FastRandomContext insecure_rand ;
pnode - > PushAddress ( addrLocal , insecure_rand ) ;
2012-02-12 13:45:24 +01:00
}
}
}
// learn a new local address
2012-05-10 20:35:13 +02:00
bool AddLocal ( const CService & addr , int nScore )
2012-02-12 13:45:24 +01:00
{
if ( ! addr . IsRoutable ( ) )
return false ;
2012-05-24 19:02:21 +02:00
if ( ! fDiscover & & nScore < LOCAL_MANUAL )
2012-05-13 14:11:53 +02:00
return false ;
2012-05-13 23:50:49 +02:00
if ( IsLimited ( addr ) )
2012-05-13 15:11:51 +02:00
return false ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " AddLocal(%s,%i) \n " , addr . ToString ( ) , nScore ) ;
2012-02-12 13:45:24 +01:00
{
LOCK ( cs_mapLocalHost ) ;
2012-05-13 00:41:24 +02:00
bool fAlready = mapLocalHost . count ( addr ) > 0 ;
LocalServiceInfo & info = mapLocalHost [ addr ] ;
if ( ! fAlready | | nScore > = info . nScore ) {
2012-08-29 02:33:25 +02:00
info . nScore = nScore + ( fAlready ? 1 : 0 ) ;
info . nPort = addr . GetPort ( ) ;
2012-05-13 00:41:24 +02:00
}
2012-02-12 13:45:24 +01:00
}
return true ;
}
2012-05-13 01:26:14 +02:00
bool AddLocal ( const CNetAddr & addr , int nScore )
2012-05-10 20:35:13 +02:00
{
2012-05-13 01:26:14 +02:00
return AddLocal ( CService ( addr , GetListenPort ( ) ) , nScore ) ;
2012-05-10 20:35:13 +02:00
}
2015-09-08 17:48:45 +02:00
bool RemoveLocal ( const CService & addr )
{
LOCK ( cs_mapLocalHost ) ;
LogPrintf ( " RemoveLocal(%s) \n " , addr . ToString ( ) ) ;
mapLocalHost . erase ( addr ) ;
return true ;
}
2012-05-04 16:46:22 +02:00
/** Make a particular network entirely off-limits (no automatic connects to it) */
void SetLimited ( enum Network net , bool fLimited )
{
2017-05-24 02:04:38 +02:00
if ( net = = NET_UNROUTABLE | | net = = NET_INTERNAL )
2012-05-14 17:15:58 +02:00
return ;
2012-05-04 16:46:22 +02:00
LOCK ( cs_mapLocalHost ) ;
vfLimited [ net ] = fLimited ;
}
2012-05-14 17:15:58 +02:00
bool IsLimited ( enum Network net )
2012-05-04 16:46:22 +02:00
{
LOCK ( cs_mapLocalHost ) ;
2012-05-14 17:15:58 +02:00
return vfLimited [ net ] ;
}
bool IsLimited ( const CNetAddr & addr )
{
return IsLimited ( addr . GetNetwork ( ) ) ;
2012-05-04 16:46:22 +02:00
}
/** vote for a local address */
2012-05-10 20:35:13 +02:00
bool SeenLocal ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
{
LOCK ( cs_mapLocalHost ) ;
if ( mapLocalHost . count ( addr ) = = 0 )
return false ;
2012-05-13 00:41:24 +02:00
mapLocalHost [ addr ] . nScore + + ;
2012-02-12 13:45:24 +01:00
}
return true ;
}
2014-07-21 08:32:25 +02:00
2012-05-04 16:46:22 +02:00
/** check whether a given address is potentially local */
2012-05-10 20:35:13 +02:00
bool IsLocal ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
LOCK ( cs_mapLocalHost ) ;
return mapLocalHost . count ( addr ) > 0 ;
}
2010-08-29 18:58:15 +02:00
2014-07-30 15:31:36 +02:00
/** check whether a given network is one we can probably connect to */
bool IsReachable ( enum Network net )
{
LOCK ( cs_mapLocalHost ) ;
2016-02-18 07:44:32 +01:00
return ! vfLimited [ net ] ;
2014-07-30 15:31:36 +02:00
}
2012-05-04 16:46:22 +02:00
/** check whether a given address is in a network we can probably connect to */
2012-04-10 20:22:04 +02:00
bool IsReachable ( const CNetAddr & addr )
{
2012-05-04 16:46:22 +02:00
enum Network net = addr . GetNetwork ( ) ;
2014-07-30 15:31:36 +02:00
return IsReachable ( net ) ;
2012-04-10 20:22:04 +02:00
}
2010-08-29 18:58:15 +02:00
2015-09-02 17:03:27 +02:00
2016-04-17 01:13:12 +02:00
CNode * CConnman : : FindNode ( const CNetAddr & ip )
2010-08-29 18:58:15 +02:00
{
2013-04-04 11:30:55 +02:00
LOCK ( cs_vNodes ) ;
2017-07-20 11:32:47 +02:00
for ( CNode * pnode : vNodes ) {
2017-06-01 16:13:35 +02:00
if ( static_cast < CNetAddr > ( pnode - > addr ) = = ip ) {
2017-07-20 11:32:47 +02:00
return pnode ;
}
}
2017-08-07 07:36:37 +02:00
return nullptr ;
2010-08-29 18:58:15 +02:00
}
2016-04-17 01:13:12 +02:00
CNode * CConnman : : FindNode ( const CSubNet & subNet )
2015-05-25 20:03:51 +02:00
{
LOCK ( cs_vNodes ) ;
2017-07-20 11:32:47 +02:00
for ( CNode * pnode : vNodes ) {
2017-06-01 16:13:35 +02:00
if ( subNet . Match ( static_cast < CNetAddr > ( pnode - > addr ) ) ) {
2017-07-20 11:32:47 +02:00
return pnode ;
}
}
2017-08-07 07:36:37 +02:00
return nullptr ;
2015-05-25 20:03:51 +02:00
}
2016-04-17 01:13:12 +02:00
CNode * CConnman : : FindNode ( const std : : string & addrName )
2012-04-19 17:38:03 +02:00
{
LOCK ( cs_vNodes ) ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodes ) {
2017-02-06 18:04:34 +01:00
if ( pnode - > GetAddrName ( ) = = addrName ) {
2017-07-20 11:32:47 +02:00
return pnode ;
2017-02-06 18:04:34 +01:00
}
}
2017-08-07 07:36:37 +02:00
return nullptr ;
2012-04-19 17:38:03 +02:00
}
2016-04-17 01:13:12 +02:00
CNode * CConnman : : FindNode ( const CService & addr )
2010-08-29 18:58:15 +02:00
{
2013-04-04 11:30:55 +02:00
LOCK ( cs_vNodes ) ;
2017-07-20 11:32:47 +02:00
for ( CNode * pnode : vNodes ) {
2017-06-01 16:13:35 +02:00
if ( static_cast < CService > ( pnode - > addr ) = = addr ) {
2017-07-20 11:32:47 +02:00
return pnode ;
}
}
2017-08-07 07:36:37 +02:00
return nullptr ;
2010-08-29 18:58:15 +02:00
}
2016-04-18 02:21:58 +02:00
bool CConnman : : CheckIncomingNonce ( uint64_t nonce )
{
LOCK ( cs_vNodes ) ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodes ) {
2016-04-18 02:21:58 +02:00
if ( ! pnode - > fSuccessfullyConnected & & ! pnode - > fInbound & & pnode - > GetLocalNonce ( ) = = nonce )
return false ;
}
return true ;
}
2017-05-30 11:59:42 +02:00
/** Get the bind address for a socket as CAddress */
static CAddress GetBindAddress ( SOCKET sock )
{
CAddress addr_bind ;
struct sockaddr_storage sockaddr_bind ;
socklen_t sockaddr_bind_len = sizeof ( sockaddr_bind ) ;
if ( sock ! = INVALID_SOCKET ) {
if ( ! getsockname ( sock , ( struct sockaddr * ) & sockaddr_bind , & sockaddr_bind_len ) ) {
addr_bind . SetSockAddr ( ( const struct sockaddr * ) & sockaddr_bind ) ;
} else {
LogPrint ( BCLog : : NET , " Warning: getsockname failed \n " ) ;
}
}
return addr_bind ;
}
2016-04-16 21:59:10 +02:00
CNode * CConnman : : ConnectNode ( CAddress addrConnect , const char * pszDest , bool fCountFailure )
2010-08-29 18:58:15 +02:00
{
2017-08-07 07:36:37 +02:00
if ( pszDest = = nullptr ) {
2012-02-12 13:45:24 +01:00
if ( IsLocal ( addrConnect ) )
2017-08-07 07:36:37 +02:00
return nullptr ;
2010-08-29 18:58:15 +02:00
2012-04-19 17:38:03 +02:00
// Look for an existing connection
2017-06-01 16:13:35 +02:00
CNode * pnode = FindNode ( static_cast < CService > ( addrConnect ) ) ;
2012-04-19 17:38:03 +02:00
if ( pnode )
{
2017-01-24 22:51:22 +01:00
LogPrintf ( " Failed to open new connection, already connected \n " ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2012-04-19 17:38:03 +02:00
}
2010-08-29 18:58:15 +02:00
}
/// debug print
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " trying connection %s lastseen=%.1fhrs \n " ,
2014-01-16 16:15:27 +01:00
pszDest ? pszDest : addrConnect . ToString ( ) ,
2014-05-24 11:14:52 +02:00
pszDest ? 0.0 : ( double ) ( GetAdjustedTime ( ) - addrConnect . nTime ) / 3600.0 ) ;
2010-08-29 18:58:15 +02:00
2017-06-22 20:01:04 +02:00
// Resolve
const int default_port = Params ( ) . GetDefaultPort ( ) ;
if ( pszDest ) {
std : : vector < CService > resolved ;
if ( Lookup ( pszDest , resolved , default_port , fNameLookup & & ! HaveNameProxy ( ) , 256 ) & & ! resolved . empty ( ) ) {
addrConnect = CAddress ( resolved [ GetRand ( resolved . size ( ) ) ] , NODE_NONE ) ;
if ( ! addrConnect . IsValid ( ) ) {
LogPrint ( BCLog : : NET , " Resolver returned invalid address %s for %s " , addrConnect . ToString ( ) , pszDest ) ;
return nullptr ;
}
2016-05-28 16:22:02 +02:00
// It is possible that we already have a connection to the IP/port pszDest resolved to.
// In that case, drop the connection that was just created, and return the existing CNode instead.
// Also store the name we used to connect in that CNode, so that future FindNode() calls to that
// name catch this early.
2017-01-24 22:50:27 +01:00
LOCK ( cs_vNodes ) ;
2017-06-01 16:13:35 +02:00
CNode * pnode = FindNode ( static_cast < CService > ( addrConnect ) ) ;
2016-05-28 16:22:02 +02:00
if ( pnode )
{
2017-02-06 18:04:34 +01:00
pnode - > MaybeSetAddrName ( std : : string ( pszDest ) ) ;
2017-01-24 22:51:22 +01:00
LogPrintf ( " Failed to open new connection, already connected \n " ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-05-28 16:22:02 +02:00
}
}
2017-06-22 20:01:04 +02:00
}
2016-05-28 16:22:02 +02:00
2017-06-22 20:01:04 +02:00
// Connect
bool connected = false ;
2018-02-01 16:29:15 +01:00
SOCKET hSocket = INVALID_SOCKET ;
2017-06-22 20:01:04 +02:00
proxyType proxy ;
if ( addrConnect . IsValid ( ) ) {
bool proxyConnectionFailed = false ;
2017-09-19 00:45:51 +02:00
if ( GetProxy ( addrConnect . GetNetwork ( ) , proxy ) ) {
hSocket = CreateSocket ( proxy . proxy ) ;
if ( hSocket = = INVALID_SOCKET ) {
return nullptr ;
}
2017-06-22 20:01:04 +02:00
connected = ConnectThroughProxy ( proxy , addrConnect . ToStringIP ( ) , addrConnect . GetPort ( ) , hSocket , nConnectTimeout , & proxyConnectionFailed ) ;
2017-09-19 00:45:51 +02:00
} else {
// no proxy needed (none set for target network)
hSocket = CreateSocket ( addrConnect ) ;
if ( hSocket = = INVALID_SOCKET ) {
return nullptr ;
}
2017-06-22 20:01:04 +02:00
connected = ConnectSocketDirectly ( addrConnect , hSocket , nConnectTimeout ) ;
2017-09-19 00:45:51 +02:00
}
2017-06-22 20:01:04 +02:00
if ( ! proxyConnectionFailed ) {
// If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
// the proxy, mark this as an attempt.
addrman . Attempt ( addrConnect , fCountFailure ) ;
}
} else if ( pszDest & & GetNameProxy ( proxy ) ) {
2017-09-19 00:45:51 +02:00
hSocket = CreateSocket ( proxy . proxy ) ;
if ( hSocket = = INVALID_SOCKET ) {
return nullptr ;
}
2017-06-22 20:01:04 +02:00
std : : string host ;
int port = default_port ;
SplitHostPort ( std : : string ( pszDest ) , port , host ) ;
connected = ConnectThroughProxy ( proxy , host , port , hSocket , nConnectTimeout , nullptr ) ;
}
2017-10-02 20:18:32 +02:00
if ( ! connected ) {
CloseSocket ( hSocket ) ;
return nullptr ;
2010-08-29 18:58:15 +02:00
}
2014-05-24 11:14:52 +02:00
2017-10-02 20:18:32 +02:00
// Add node
NodeId id = GetNewNodeId ( ) ;
uint64_t nonce = GetDeterministicRandomizer ( RANDOMIZER_ID_LOCALHOSTNONCE ) . Write ( id ) . Finalize ( ) ;
CAddress addr_bind = GetBindAddress ( hSocket ) ;
CNode * pnode = new CNode ( id , nLocalServices , GetBestHeight ( ) , hSocket , addrConnect , CalculateKeyedNetGroup ( addrConnect ) , nonce , addr_bind , pszDest ? pszDest : " " , false ) ;
pnode - > AddRef ( ) ;
return pnode ;
2010-08-29 18:58:15 +02:00
}
2016-04-16 23:43:11 +02:00
void CConnman : : DumpBanlist ( )
2016-04-18 23:59:31 +02:00
{
2016-04-16 23:43:11 +02:00
SweepBanned ( ) ; // clean unused entries (if bantime has expired)
2016-04-18 23:59:31 +02:00
2016-04-16 23:43:11 +02:00
if ( ! BannedSetIsDirty ( ) )
2016-04-18 23:59:31 +02:00
return ;
int64_t nStart = GetTimeMillis ( ) ;
CBanDB bandb ;
banmap_t banmap ;
2016-04-16 23:43:11 +02:00
GetBanned ( banmap ) ;
2017-04-19 18:49:11 +02:00
if ( bandb . Write ( banmap ) ) {
SetBannedSetDirty ( false ) ;
}
2016-04-18 23:59:31 +02:00
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " Flushed %d banned node ips/subnets to banlist.dat %dms \n " ,
2016-04-18 23:59:31 +02:00
banmap . size ( ) , GetTimeMillis ( ) - nStart ) ;
}
2010-08-29 18:58:15 +02:00
void CNode : : CloseSocketDisconnect ( )
{
fDisconnect = true ;
2017-02-06 20:05:45 +01:00
LOCK ( cs_hSocket ) ;
2010-08-29 18:58:15 +02:00
if ( hSocket ! = INVALID_SOCKET )
{
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " disconnecting peer=%d \n " , id ) ;
2014-07-10 12:13:03 +02:00
CloseSocket ( hSocket ) ;
2010-08-29 18:58:15 +02:00
}
}
2016-04-16 23:43:11 +02:00
void CConnman : : ClearBanned ( )
2011-09-06 22:09:04 +02:00
{
2016-04-18 23:02:43 +02:00
{
LOCK ( cs_setBanned ) ;
setBanned . clear ( ) ;
setBannedIsDirty = true ;
}
DumpBanlist ( ) ; //store banlist to disk
2016-05-26 03:26:46 +02:00
if ( clientInterface )
clientInterface - > BannedListChanged ( ) ;
2011-09-06 22:09:04 +02:00
}
2016-04-16 23:43:11 +02:00
bool CConnman : : IsBanned ( CNetAddr ip )
2011-09-06 22:09:04 +02:00
{
2017-06-09 04:05:53 +02:00
LOCK ( cs_setBanned ) ;
2017-07-20 11:32:47 +02:00
for ( const auto & it : setBanned ) {
CSubNet subNet = it . first ;
CBanEntry banEntry = it . second ;
2015-05-25 20:03:51 +02:00
2017-06-09 04:05:53 +02:00
if ( subNet . Match ( ip ) & & GetTime ( ) < banEntry . nBanUntil ) {
return true ;
2015-05-25 20:03:51 +02:00
}
}
2017-06-09 04:05:53 +02:00
return false ;
2015-05-25 20:03:51 +02:00
}
2016-04-16 23:43:11 +02:00
bool CConnman : : IsBanned ( CSubNet subnet )
2015-05-25 20:03:51 +02:00
{
2017-06-09 04:05:53 +02:00
LOCK ( cs_setBanned ) ;
banmap_t : : iterator i = setBanned . find ( subnet ) ;
if ( i ! = setBanned . end ( ) )
2015-05-25 20:03:51 +02:00
{
2017-06-09 04:05:53 +02:00
CBanEntry banEntry = ( * i ) . second ;
if ( GetTime ( ) < banEntry . nBanUntil ) {
return true ;
2011-09-06 22:09:04 +02:00
}
}
2017-06-09 04:05:53 +02:00
return false ;
2011-09-06 22:09:04 +02:00
}
2016-04-16 23:43:11 +02:00
void CConnman : : Ban ( const CNetAddr & addr , const BanReason & banReason , int64_t bantimeoffset , bool sinceUnixEpoch ) {
2015-06-29 20:37:22 +02:00
CSubNet subNet ( addr ) ;
2015-06-26 21:38:33 +02:00
Ban ( subNet , banReason , bantimeoffset , sinceUnixEpoch ) ;
2015-05-25 20:03:51 +02:00
}
2016-04-16 23:43:11 +02:00
void CConnman : : Ban ( const CSubNet & subNet , const BanReason & banReason , int64_t bantimeoffset , bool sinceUnixEpoch ) {
2015-06-26 21:38:33 +02:00
CBanEntry banEntry ( GetTime ( ) ) ;
banEntry . banReason = banReason ;
if ( bantimeoffset < = 0 )
{
2017-08-01 21:17:40 +02:00
bantimeoffset = gArgs . GetArg ( " -bantime " , DEFAULT_MISBEHAVING_BANTIME ) ;
2015-06-26 21:38:33 +02:00
sinceUnixEpoch = false ;
}
banEntry . nBanUntil = ( sinceUnixEpoch ? 0 : GetTime ( ) ) + bantimeoffset ;
2016-04-18 23:02:43 +02:00
{
LOCK ( cs_setBanned ) ;
if ( setBanned [ subNet ] . nBanUntil < banEntry . nBanUntil ) {
setBanned [ subNet ] = banEntry ;
setBannedIsDirty = true ;
}
else
return ;
}
2016-05-26 03:26:46 +02:00
if ( clientInterface )
clientInterface - > BannedListChanged ( ) ;
2016-04-18 23:02:43 +02:00
{
LOCK ( cs_vNodes ) ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodes ) {
2017-06-01 16:13:35 +02:00
if ( subNet . Match ( static_cast < CNetAddr > ( pnode - > addr ) ) )
2016-04-18 23:02:43 +02:00
pnode - > fDisconnect = true ;
}
}
if ( banReason = = BanReasonManuallyAdded )
DumpBanlist ( ) ; //store banlist to disk immediately if user requested ban
2011-09-06 22:09:04 +02:00
}
2016-04-16 23:43:11 +02:00
bool CConnman : : Unban ( const CNetAddr & addr ) {
2015-06-29 20:37:22 +02:00
CSubNet subNet ( addr ) ;
2015-05-25 20:03:51 +02:00
return Unban ( subNet ) ;
}
2016-04-16 23:43:11 +02:00
bool CConnman : : Unban ( const CSubNet & subNet ) {
2015-06-19 15:27:37 +02:00
{
2016-04-18 23:02:43 +02:00
LOCK ( cs_setBanned ) ;
if ( ! setBanned . erase ( subNet ) )
return false ;
2015-06-19 15:27:37 +02:00
setBannedIsDirty = true ;
}
2016-05-26 03:26:46 +02:00
if ( clientInterface )
clientInterface - > BannedListChanged ( ) ;
2016-04-18 23:02:43 +02:00
DumpBanlist ( ) ; //store banlist to disk immediately
return true ;
2015-05-19 10:07:23 +02:00
}
2016-04-16 23:43:11 +02:00
void CConnman : : GetBanned ( banmap_t & banMap )
2015-05-19 10:07:23 +02:00
{
LOCK ( cs_setBanned ) ;
2017-04-19 18:49:11 +02:00
// Sweep the banlist so expired bans are not returned
SweepBanned ( ) ;
2015-05-19 10:07:23 +02:00
banMap = setBanned ; //create a thread safe copy
}
2016-04-16 23:43:11 +02:00
void CConnman : : SetBanned ( const banmap_t & banMap )
2015-06-19 15:27:37 +02:00
{
LOCK ( cs_setBanned ) ;
setBanned = banMap ;
setBannedIsDirty = true ;
}
2016-04-16 23:43:11 +02:00
void CConnman : : SweepBanned ( )
2015-06-19 15:27:37 +02:00
{
int64_t now = GetTime ( ) ;
2017-11-19 08:38:27 +01:00
bool notifyUI = false ;
2015-06-19 15:27:37 +02:00
{
2017-11-19 08:38:27 +01:00
LOCK ( cs_setBanned ) ;
banmap_t : : iterator it = setBanned . begin ( ) ;
while ( it ! = setBanned . end ( ) )
2015-06-19 15:27:37 +02:00
{
2017-11-19 08:38:27 +01:00
CSubNet subNet = ( * it ) . first ;
CBanEntry banEntry = ( * it ) . second ;
if ( now > banEntry . nBanUntil )
{
setBanned . erase ( it + + ) ;
setBannedIsDirty = true ;
notifyUI = true ;
LogPrint ( BCLog : : NET , " %s: Removed banned node ip/subnet from banlist.dat: %s \n " , __func__ , subNet . ToString ( ) ) ;
}
else
+ + it ;
2015-06-19 15:27:37 +02:00
}
}
2017-11-06 03:34:40 +01:00
// update UI
2017-11-19 08:38:27 +01:00
if ( notifyUI & & clientInterface ) {
2017-11-06 03:34:40 +01:00
clientInterface - > BannedListChanged ( ) ;
2015-06-19 15:27:37 +02:00
}
}
2016-04-16 23:43:11 +02:00
bool CConnman : : BannedSetIsDirty ( )
2015-06-19 15:27:37 +02:00
{
LOCK ( cs_setBanned ) ;
return setBannedIsDirty ;
}
2016-04-16 23:43:11 +02:00
void CConnman : : SetBannedSetDirty ( bool dirty )
2015-06-19 15:27:37 +02:00
{
LOCK ( cs_setBanned ) ; //reuse setBanned lock for the isDirty flag
setBannedIsDirty = dirty ;
}
2014-06-21 13:34:36 +02:00
2016-04-18 00:34:32 +02:00
bool CConnman : : IsWhitelistedRange ( const CNetAddr & addr ) {
2017-06-02 03:18:57 +02:00
for ( const CSubNet & subnet : vWhitelistedRange ) {
2014-06-21 13:34:36 +02:00
if ( subnet . Match ( addr ) )
return true ;
}
return false ;
}
2017-02-06 18:04:34 +01:00
std : : string CNode : : GetAddrName ( ) const {
LOCK ( cs_addrName ) ;
return addrName ;
}
void CNode : : MaybeSetAddrName ( const std : : string & addrNameIn ) {
LOCK ( cs_addrName ) ;
if ( addrName . empty ( ) ) {
addrName = addrNameIn ;
}
}
2017-02-06 18:18:51 +01:00
CService CNode : : GetAddrLocal ( ) const {
LOCK ( cs_addrLocal ) ;
return addrLocal ;
}
void CNode : : SetAddrLocal ( const CService & addrLocalIn ) {
LOCK ( cs_addrLocal ) ;
if ( addrLocal . IsValid ( ) ) {
error ( " Addr local already set for node: %i. Refusing to change from %s to %s " , id , addrLocal . ToString ( ) , addrLocalIn . ToString ( ) ) ;
} else {
addrLocal = addrLocalIn ;
}
}
2012-06-29 23:24:53 +02:00
# undef X
# define X(name) stats.name = name
void CNode : : copyStats ( CNodeStats & stats )
{
2013-11-18 01:25:17 +01:00
stats . nodeid = this - > GetId ( ) ;
2012-06-29 23:24:53 +02:00
X ( nServices ) ;
2016-10-05 01:27:11 +02:00
X ( addr ) ;
2017-05-30 11:59:42 +02:00
X ( addrBind ) ;
2017-02-06 17:53:34 +01:00
{
LOCK ( cs_filter ) ;
X ( fRelayTxes ) ;
}
2012-06-29 23:24:53 +02:00
X ( nLastSend ) ;
X ( nLastRecv ) ;
X ( nTimeConnected ) ;
2014-12-15 11:06:15 +01:00
X ( nTimeOffset ) ;
2017-02-06 18:04:34 +01:00
stats . addrName = GetAddrName ( ) ;
2012-06-29 23:24:53 +02:00
X ( nVersion ) ;
2017-02-06 18:08:31 +01:00
{
LOCK ( cs_SubVer ) ;
X ( cleanSubVer ) ;
}
2012-06-29 23:24:53 +02:00
X ( fInbound ) ;
2017-10-05 17:49:16 +02:00
X ( m_manual_connection ) ;
2012-06-29 23:24:53 +02:00
X ( nStartingHeight ) ;
2017-02-06 08:34:57 +01:00
{
LOCK ( cs_vSend ) ;
X ( mapSendBytesPerMsgCmd ) ;
X ( nSendBytes ) ;
}
{
LOCK ( cs_vRecv ) ;
X ( mapRecvBytesPerMsgCmd ) ;
X ( nRecvBytes ) ;
}
2014-06-21 13:34:36 +02:00
X ( fWhitelisted ) ;
2013-11-15 12:24:34 +01:00
2013-08-22 13:34:33 +02:00
// It is common for nodes with good ping times to suddenly become lagged,
// due to a new block arriving or other large transfer.
// Merely reporting pingtime might fool the caller into thinking the node was still responsive,
// since pingtime does not update until the ping is complete, which might take a while.
// So, if a ping is taking an unusually long time in flight,
// the caller can immediately detect that this is happening.
2013-04-13 07:13:08 +02:00
int64_t nPingUsecWait = 0 ;
2013-08-22 13:34:33 +02:00
if ( ( 0 ! = nPingNonceSent ) & & ( 0 ! = nPingUsecStart ) ) {
nPingUsecWait = GetTimeMicros ( ) - nPingUsecStart ;
}
2013-11-15 12:24:34 +01:00
2013-08-22 13:34:33 +02:00
// Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
stats . dPingTime = ( ( ( double ) nPingUsecTime ) / 1e6 ) ;
2016-10-14 16:11:38 +02:00
stats . dMinPing = ( ( ( double ) nMinPingUsecTime ) / 1e6 ) ;
2013-08-22 13:34:33 +02:00
stats . dPingWait = ( ( ( double ) nPingUsecWait ) / 1e6 ) ;
2013-11-15 12:24:34 +01:00
2013-08-22 07:50:19 +02:00
// Leave string empty if addrLocal invalid (not filled in yet)
2017-02-06 18:18:51 +01:00
CService addrLocalUnlocked = GetAddrLocal ( ) ;
stats . addrLocal = addrLocalUnlocked . IsValid ( ) ? addrLocalUnlocked . ToString ( ) : " " ;
2012-06-29 23:24:53 +02:00
}
# undef X
2010-08-29 18:58:15 +02:00
2016-04-19 03:33:54 +02:00
bool CNode : : ReceiveMsgBytes ( const char * pch , unsigned int nBytes , bool & complete )
2012-11-16 01:41:12 +01:00
{
2016-04-19 03:33:54 +02:00
complete = false ;
2016-12-31 08:05:17 +01:00
int64_t nTimeMicros = GetTimeMicros ( ) ;
2017-02-06 08:34:57 +01:00
LOCK ( cs_vRecv ) ;
2016-12-31 08:05:17 +01:00
nLastRecv = nTimeMicros / 1000000 ;
nRecvBytes + = nBytes ;
2012-11-16 01:41:12 +01:00
while ( nBytes > 0 ) {
// get current incomplete message, or create a new one
2013-03-01 01:41:28 +01:00
if ( vRecvMsg . empty ( ) | |
2012-11-16 01:41:12 +01:00
vRecvMsg . back ( ) . complete ( ) )
2016-12-31 08:05:15 +01:00
vRecvMsg . push_back ( CNetMessage ( Params ( ) . MessageStart ( ) , SER_NETWORK , INIT_PROTO_VERSION ) ) ;
2012-11-16 01:41:12 +01:00
CNetMessage & msg = vRecvMsg . back ( ) ;
// absorb network data
int handled ;
if ( ! msg . in_data )
handled = msg . readHeader ( pch , nBytes ) ;
else
handled = msg . readData ( pch , nBytes ) ;
if ( handled < 0 )
2017-03-06 17:54:08 +01:00
return false ;
2012-11-16 01:41:12 +01:00
2015-03-05 13:01:22 +01:00
if ( msg . in_data & & msg . hdr . nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH ) {
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " Oversized message from peer=%i, disconnecting \n " , GetId ( ) ) ;
2015-03-05 13:01:22 +01:00
return false ;
}
2012-11-16 01:41:12 +01:00
pch + = handled ;
nBytes - = handled ;
2014-07-06 16:06:46 +02:00
2015-04-05 11:35:37 +02:00
if ( msg . complete ( ) ) {
2015-08-25 16:30:31 +02:00
//store received bytes per message command
//to prevent a memory DOS, only allow valid commands
mapMsgCmdSize : : iterator i = mapRecvBytesPerMsgCmd . find ( msg . hdr . pchCommand ) ;
if ( i = = mapRecvBytesPerMsgCmd . end ( ) )
i = mapRecvBytesPerMsgCmd . find ( NET_MESSAGE_COMMAND_OTHER ) ;
assert ( i ! = mapRecvBytesPerMsgCmd . end ( ) ) ;
i - > second + = msg . hdr . nMessageSize + CMessageHeader : : HEADER_SIZE ;
2016-12-31 08:05:17 +01:00
msg . nTime = nTimeMicros ;
2016-04-19 03:33:54 +02:00
complete = true ;
2015-04-05 11:35:37 +02:00
}
2012-11-16 01:41:12 +01:00
}
return true ;
}
2017-02-02 20:33:41 +01:00
void CNode : : SetSendVersion ( int nVersionIn )
{
// Send version may only be changed in the version message, and
// only one version message is allowed per session. We can therefore
// treat this value as const and even atomic as long as it's only used
// once a version message has been successfully processed. Any attempt to
// set this twice is an error.
if ( nSendVersion ! = 0 ) {
error ( " Send version already set for node: %i. Refusing to change from %i to %i " , id , nSendVersion , nVersionIn ) ;
} else {
nSendVersion = nVersionIn ;
}
}
int CNode : : GetSendVersion ( ) const
{
// The send version should always be explicitly set to
// INIT_PROTO_VERSION rather than using this value until SetSendVersion
// has been called.
if ( nSendVersion = = 0 ) {
error ( " Requesting unset send version for node: %i. Using %i " , id , INIT_PROTO_VERSION ) ;
return INIT_PROTO_VERSION ;
}
return nSendVersion ;
}
2012-11-16 01:41:12 +01:00
int CNetMessage : : readHeader ( const char * pch , unsigned int nBytes )
{
// copy data to temporary parsing buffer
unsigned int nRemaining = 24 - nHdrPos ;
unsigned int nCopy = std : : min ( nRemaining , nBytes ) ;
memcpy ( & hdrbuf [ nHdrPos ] , pch , nCopy ) ;
nHdrPos + = nCopy ;
// if header incomplete, exit
if ( nHdrPos < 24 )
return nCopy ;
// deserialize to CMessageHeader
try {
hdrbuf > > hdr ;
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & ) {
2012-11-16 01:41:12 +01:00
return - 1 ;
}
// reject messages larger than MAX_SIZE
if ( hdr . nMessageSize > MAX_SIZE )
2017-03-06 17:54:08 +01:00
return - 1 ;
2012-11-16 01:41:12 +01:00
// switch state to reading message data
in_data = true ;
return nCopy ;
}
int CNetMessage : : readData ( const char * pch , unsigned int nBytes )
{
unsigned int nRemaining = hdr . nMessageSize - nDataPos ;
unsigned int nCopy = std : : min ( nRemaining , nBytes ) ;
2014-06-21 17:00:38 +02:00
if ( vRecv . size ( ) < nDataPos + nCopy ) {
// Allocate up to 256 KiB ahead, but never more than the total message size.
vRecv . resize ( std : : min ( hdr . nMessageSize , nDataPos + nCopy + 256 * 1024 ) ) ;
}
2016-10-30 23:02:16 +01:00
hasher . Write ( ( const unsigned char * ) pch , nCopy ) ;
2012-11-16 01:41:12 +01:00
memcpy ( & vRecv [ nDataPos ] , pch , nCopy ) ;
nDataPos + = nCopy ;
return nCopy ;
}
2016-10-30 23:02:16 +01:00
const uint256 & CNetMessage : : GetMessageHash ( ) const
{
assert ( complete ( ) ) ;
if ( data_hash . IsNull ( ) )
hasher . Finalize ( data_hash . begin ( ) ) ;
return data_hash ;
}
2010-08-29 18:58:15 +02:00
2012-11-16 00:04:52 +01:00
// requires LOCK(cs_vSend)
2017-01-24 02:32:52 +01:00
size_t CConnman : : SocketSendData ( CNode * pnode ) const
2012-11-16 00:04:52 +01:00
{
2016-11-11 02:17:30 +01:00
auto it = pnode - > vSendMsg . begin ( ) ;
2016-05-21 12:04:02 +02:00
size_t nSentSize = 0 ;
2013-03-24 16:52:24 +01:00
while ( it ! = pnode - > vSendMsg . end ( ) ) {
2016-11-11 02:17:30 +01:00
const auto & data = * it ;
2013-03-24 16:52:24 +01:00
assert ( data . size ( ) > pnode - > nSendOffset ) ;
2017-02-06 20:05:45 +01:00
int nBytes = 0 ;
{
LOCK ( pnode - > cs_hSocket ) ;
if ( pnode - > hSocket = = INVALID_SOCKET )
break ;
nBytes = send ( pnode - > hSocket , reinterpret_cast < const char * > ( data . data ( ) ) + pnode - > nSendOffset , data . size ( ) - pnode - > nSendOffset , MSG_NOSIGNAL | MSG_DONTWAIT ) ;
}
2013-03-24 16:52:24 +01:00
if ( nBytes > 0 ) {
2017-01-19 19:01:18 +01:00
pnode - > nLastSend = GetSystemTimeInSeconds ( ) ;
2013-04-07 19:31:13 +02:00
pnode - > nSendBytes + = nBytes ;
2013-03-24 16:52:24 +01:00
pnode - > nSendOffset + = nBytes ;
2016-05-21 12:04:02 +02:00
nSentSize + = nBytes ;
2013-03-24 16:52:24 +01:00
if ( pnode - > nSendOffset = = data . size ( ) ) {
pnode - > nSendOffset = 0 ;
pnode - > nSendSize - = data . size ( ) ;
2016-12-31 08:05:32 +01:00
pnode - > fPauseSend = pnode - > nSendSize > nSendBufferMaxSize ;
2013-03-24 16:52:24 +01:00
it + + ;
} else {
// could not send full message; stop sending more
break ;
}
} else {
if ( nBytes < 0 ) {
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
{
2014-05-08 14:15:19 +02:00
LogPrintf ( " socket send error %s \n " , NetworkErrorString ( nErr ) ) ;
2013-03-24 16:52:24 +01:00
pnode - > CloseSocketDisconnect ( ) ;
}
}
// couldn't send anything at all
break ;
2012-11-16 00:04:52 +01:00
}
}
2013-03-24 16:52:24 +01:00
if ( it = = pnode - > vSendMsg . end ( ) ) {
assert ( pnode - > nSendOffset = = 0 ) ;
assert ( pnode - > nSendSize = = 0 ) ;
}
pnode - > vSendMsg . erase ( pnode - > vSendMsg . begin ( ) , it ) ;
2016-05-21 12:04:02 +02:00
return nSentSize ;
2012-11-16 00:04:52 +01:00
}
2010-08-29 18:58:15 +02:00
2016-04-18 21:58:19 +02:00
struct NodeEvictionCandidate
{
NodeId id ;
int64_t nTimeConnected ;
int64_t nMinPingUsecTime ;
2016-05-22 07:55:15 +02:00
int64_t nLastBlockTime ;
int64_t nLastTXTime ;
2016-11-01 01:08:47 +01:00
bool fRelevantServices ;
2016-05-22 07:55:15 +02:00
bool fRelayTxes ;
bool fBloomFilter ;
2016-04-18 21:58:19 +02:00
CAddress addr ;
2016-05-25 15:38:32 +02:00
uint64_t nKeyedNetGroup ;
2015-08-21 02:29:04 +02:00
} ;
2016-04-18 21:58:19 +02:00
static bool ReverseCompareNodeMinPingTime ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
2015-08-13 11:58:58 +02:00
{
2016-04-18 21:58:19 +02:00
return a . nMinPingUsecTime > b . nMinPingUsecTime ;
2015-08-13 11:58:58 +02:00
}
2016-04-18 21:58:19 +02:00
static bool ReverseCompareNodeTimeConnected ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
2015-08-13 11:58:58 +02:00
{
2016-04-18 21:58:19 +02:00
return a . nTimeConnected > b . nTimeConnected ;
2015-08-13 11:58:58 +02:00
}
2016-05-23 09:21:05 +02:00
static bool CompareNetGroupKeyed ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b ) {
2016-05-25 15:38:32 +02:00
return a . nKeyedNetGroup < b . nKeyedNetGroup ;
2016-05-22 07:55:15 +02:00
}
static bool CompareNodeBlockTime ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
{
// There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.
if ( a . nLastBlockTime ! = b . nLastBlockTime ) return a . nLastBlockTime < b . nLastBlockTime ;
2016-11-01 01:08:47 +01:00
if ( a . fRelevantServices ! = b . fRelevantServices ) return b . fRelevantServices ;
2016-05-22 07:55:15 +02:00
return a . nTimeConnected > b . nTimeConnected ;
}
static bool CompareNodeTXTime ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
{
// There is a fall-through here because it is common for a node to have more than a few peers that have not yet relayed txn.
if ( a . nLastTXTime ! = b . nLastTXTime ) return a . nLastTXTime < b . nLastTXTime ;
if ( a . fRelayTxes ! = b . fRelayTxes ) return b . fRelayTxes ;
if ( a . fBloomFilter ! = b . fBloomFilter ) return a . fBloomFilter ;
return a . nTimeConnected > b . nTimeConnected ;
}
2015-08-13 11:58:58 +02:00
2017-10-19 09:53:01 +02:00
//! Sort an array by the specified comparator, then erase the last K elements.
template < typename T , typename Comparator >
static void EraseLastKElements ( std : : vector < T > & elements , Comparator comparator , size_t k )
{
std : : sort ( elements . begin ( ) , elements . end ( ) , comparator ) ;
size_t eraseSize = std : : min ( k , elements . size ( ) ) ;
elements . erase ( elements . end ( ) - eraseSize , elements . end ( ) ) ;
}
2016-04-29 16:23:51 +02:00
/** Try to find a connection to evict when the node is full.
* Extreme care must be taken to avoid opening the node to attacker
* triggered network partitioning .
* The strategy used here is to protect a small number of peers
* for each of several distinct characteristics which are difficult
* to forge . In order to partition a node the attacker must be
* simultaneously better at all of them than honest peers .
*/
2016-04-17 01:13:12 +02:00
bool CConnman : : AttemptToEvictConnection ( )
{
2016-04-18 21:58:19 +02:00
std : : vector < NodeEvictionCandidate > vEvictionCandidates ;
2015-08-13 11:58:58 +02:00
{
LOCK ( cs_vNodes ) ;
2017-07-20 11:32:47 +02:00
for ( const CNode * node : vNodes ) {
2015-08-13 11:58:58 +02:00
if ( node - > fWhitelisted )
continue ;
if ( ! node - > fInbound )
continue ;
if ( node - > fDisconnect )
continue ;
2017-04-11 18:13:55 +02:00
NodeEvictionCandidate candidate = { node - > GetId ( ) , node - > nTimeConnected , node - > nMinPingUsecTime ,
2016-11-01 01:08:47 +01:00
node - > nLastBlockTime , node - > nLastTXTime ,
2017-10-04 23:59:30 +02:00
HasAllDesirableServiceFlags ( node - > nServices ) ,
2017-08-07 07:36:37 +02:00
node - > fRelayTxes , node - > pfilter ! = nullptr , node - > addr , node - > nKeyedNetGroup } ;
2016-04-18 21:58:19 +02:00
vEvictionCandidates . push_back ( candidate ) ;
2015-08-13 11:58:58 +02:00
}
}
// Protect connections with certain characteristics
2015-08-21 01:47:49 +02:00
// Deterministically select 4 peers to protect by netgroup.
2016-05-23 09:21:05 +02:00
// An attacker cannot predict which netgroups will be protected
2017-10-19 09:53:01 +02:00
EraseLastKElements ( vEvictionCandidates , CompareNetGroupKeyed , 4 ) ;
2016-04-29 16:23:51 +02:00
// Protect the 8 nodes with the lowest minimum ping time.
2015-08-21 01:47:49 +02:00
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
2017-10-19 09:53:01 +02:00
EraseLastKElements ( vEvictionCandidates , ReverseCompareNodeMinPingTime , 8 ) ;
2016-05-22 07:55:15 +02:00
// Protect 4 nodes that most recently sent us transactions.
// An attacker cannot manipulate this metric without performing useful work.
2017-10-19 09:53:01 +02:00
EraseLastKElements ( vEvictionCandidates , CompareNodeTXTime , 4 ) ;
2016-05-22 07:55:15 +02:00
// Protect 4 nodes that most recently sent us blocks.
// An attacker cannot manipulate this metric without performing useful work.
2017-10-19 09:53:01 +02:00
EraseLastKElements ( vEvictionCandidates , CompareNodeBlockTime , 4 ) ;
2015-08-26 01:31:13 +02:00
// Protect the half of the remaining nodes which have been connected the longest.
2016-04-29 16:23:51 +02:00
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
2017-10-19 09:53:01 +02:00
EraseLastKElements ( vEvictionCandidates , ReverseCompareNodeTimeConnected , vEvictionCandidates . size ( ) / 2 ) ;
2015-08-13 11:58:58 +02:00
2015-08-23 00:15:39 +02:00
if ( vEvictionCandidates . empty ( ) ) return false ;
2015-08-13 11:58:58 +02:00
2015-11-23 04:48:54 +01:00
// Identify the network group with the most connections and youngest member.
// (vEvictionCandidates is already sorted by reverse connect time)
2016-05-25 15:38:32 +02:00
uint64_t naMostConnections ;
2015-08-13 11:58:58 +02:00
unsigned int nMostConnections = 0 ;
2015-11-23 04:48:54 +01:00
int64_t nMostConnectionsTime = 0 ;
2016-06-10 16:09:06 +02:00
std : : map < uint64_t , std : : vector < NodeEvictionCandidate > > mapNetGroupNodes ;
2017-06-02 03:18:57 +02:00
for ( const NodeEvictionCandidate & node : vEvictionCandidates ) {
2017-10-19 09:53:01 +02:00
std : : vector < NodeEvictionCandidate > & group = mapNetGroupNodes [ node . nKeyedNetGroup ] ;
group . push_back ( node ) ;
int64_t grouptime = group [ 0 ] . nTimeConnected ;
2015-08-13 11:58:58 +02:00
2017-10-19 09:53:01 +02:00
if ( group . size ( ) > nMostConnections | | ( group . size ( ) = = nMostConnections & & grouptime > nMostConnectionsTime ) ) {
nMostConnections = group . size ( ) ;
2015-11-23 04:48:54 +01:00
nMostConnectionsTime = grouptime ;
2016-05-25 15:38:32 +02:00
naMostConnections = node . nKeyedNetGroup ;
2015-08-13 11:58:58 +02:00
}
}
2015-08-26 02:06:15 +02:00
// Reduce to the network group with the most connections
2016-06-10 16:09:06 +02:00
vEvictionCandidates = std : : move ( mapNetGroupNodes [ naMostConnections ] ) ;
2015-08-13 11:58:58 +02:00
2015-11-23 04:48:54 +01:00
// Disconnect from the network group with the most connections
2016-04-18 21:58:19 +02:00
NodeId evicted = vEvictionCandidates . front ( ) . id ;
LOCK ( cs_vNodes ) ;
2017-07-20 11:32:47 +02:00
for ( CNode * pnode : vNodes ) {
if ( pnode - > GetId ( ) = = evicted ) {
pnode - > fDisconnect = true ;
2016-04-18 21:58:19 +02:00
return true ;
}
}
return false ;
2015-08-13 11:58:58 +02:00
}
2016-04-16 20:47:18 +02:00
void CConnman : : AcceptConnection ( const ListenSocket & hListenSocket ) {
2015-08-13 11:00:10 +02:00
struct sockaddr_storage sockaddr ;
socklen_t len = sizeof ( sockaddr ) ;
SOCKET hSocket = accept ( hListenSocket . socket , ( struct sockaddr * ) & sockaddr , & len ) ;
CAddress addr ;
int nInbound = 0 ;
2016-08-31 19:17:28 +02:00
int nMaxInbound = nMaxConnections - ( nMaxOutbound + nMaxFeeler ) ;
2015-08-13 11:00:10 +02:00
2017-05-30 11:59:42 +02:00
if ( hSocket ! = INVALID_SOCKET ) {
if ( ! addr . SetSockAddr ( ( const struct sockaddr * ) & sockaddr ) ) {
2015-08-13 11:00:10 +02:00
LogPrintf ( " Warning: Unknown socket family \n " ) ;
2017-05-30 11:59:42 +02:00
}
}
2015-08-13 11:00:10 +02:00
2016-04-18 00:34:32 +02:00
bool whitelisted = hListenSocket . whitelisted | | IsWhitelistedRange ( addr ) ;
2015-08-13 11:00:10 +02:00
{
LOCK ( cs_vNodes ) ;
2017-07-20 11:32:47 +02:00
for ( const CNode * pnode : vNodes ) {
if ( pnode - > fInbound ) nInbound + + ;
}
2015-08-13 11:00:10 +02:00
}
if ( hSocket = = INVALID_SOCKET )
{
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK )
LogPrintf ( " socket error accept failed: %s \n " , NetworkErrorString ( nErr ) ) ;
2015-08-13 11:16:46 +02:00
return ;
2015-08-13 11:00:10 +02:00
}
2015-08-13 11:16:46 +02:00
2013-03-26 02:33:25 +01:00
if ( ! fNetworkActive ) {
LogPrintf ( " connection from %s dropped: not accepting new connections \n " , addr . ToString ( ) ) ;
CloseSocket ( hSocket ) ;
return ;
}
2015-08-13 11:16:46 +02:00
if ( ! IsSelectableSocket ( hSocket ) )
2015-08-13 11:00:10 +02:00
{
LogPrintf ( " connection from %s dropped: non-selectable socket \n " , addr . ToString ( ) ) ;
CloseSocket ( hSocket ) ;
2015-08-13 11:16:46 +02:00
return ;
2015-08-13 11:00:10 +02:00
}
2015-08-13 11:16:46 +02:00
2015-10-22 01:52:29 +02:00
// According to the internet TCP_NODELAY is not carried into accepted sockets
// on all platforms. Set it again here just to be sure.
2017-03-23 06:02:02 +01:00
SetSocketNoDelay ( hSocket ) ;
2015-10-22 01:52:29 +02:00
2016-04-16 23:43:11 +02:00
if ( IsBanned ( addr ) & & ! whitelisted )
2015-08-13 11:00:10 +02:00
{
2017-10-30 23:56:37 +01:00
LogPrint ( BCLog : : NET , " connection from %s dropped (banned) \n " , addr . ToString ( ) ) ;
2015-08-13 11:00:10 +02:00
CloseSocket ( hSocket ) ;
2015-08-13 11:16:46 +02:00
return ;
2015-08-13 11:00:10 +02:00
}
2015-08-13 11:16:46 +02:00
2015-08-13 11:19:17 +02:00
if ( nInbound > = nMaxInbound )
2015-08-13 11:00:10 +02:00
{
2016-05-22 07:55:15 +02:00
if ( ! AttemptToEvictConnection ( ) ) {
2015-08-13 11:58:58 +02:00
// No connection to evict, disconnect the new connection
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " failed to find an eviction candidate - connection dropped (full) \n " ) ;
2015-08-13 11:58:58 +02:00
CloseSocket ( hSocket ) ;
return ;
}
2015-08-13 11:00:10 +02:00
}
2016-10-26 21:10:15 +02:00
NodeId id = GetNewNodeId ( ) ;
uint64_t nonce = GetDeterministicRandomizer ( RANDOMIZER_ID_LOCALHOSTNONCE ) . Write ( id ) . Finalize ( ) ;
2017-05-30 11:59:42 +02:00
CAddress addr_bind = GetBindAddress ( hSocket ) ;
2016-10-26 21:10:15 +02:00
2017-05-30 11:59:42 +02:00
CNode * pnode = new CNode ( id , nLocalServices , GetBestHeight ( ) , hSocket , addr , CalculateKeyedNetGroup ( addr ) , nonce , addr_bind , " " , true ) ;
2015-08-13 11:16:46 +02:00
pnode - > AddRef ( ) ;
pnode - > fWhitelisted = whitelisted ;
2017-07-06 20:08:23 +02:00
m_msgproc - > InitializeNode ( pnode ) ;
2015-08-13 11:00:10 +02:00
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " connection from %s accepted \n " , addr . ToString ( ) ) ;
2015-08-13 11:16:46 +02:00
{
LOCK ( cs_vNodes ) ;
vNodes . push_back ( pnode ) ;
2015-08-13 11:00:10 +02:00
}
}
2016-04-16 20:47:18 +02:00
void CConnman : : ThreadSocketHandler ( )
2010-08-29 18:58:15 +02:00
{
2012-04-22 20:01:25 +02:00
unsigned int nPrevNodeCount = 0 ;
2016-12-27 23:12:44 +01:00
while ( ! interruptNet )
2010-08-29 18:58:15 +02:00
{
//
// Disconnect nodes
//
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-08-29 18:58:15 +02:00
// Disconnect unused nodes
2016-04-16 01:53:45 +02:00
std : : vector < CNode * > vNodesCopy = vNodes ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 18:58:15 +02:00
{
2016-12-31 08:05:11 +01:00
if ( pnode - > fDisconnect )
2010-08-29 18:58:15 +02:00
{
// remove from vNodes
vNodes . erase ( remove ( vNodes . begin ( ) , vNodes . end ( ) , pnode ) , vNodes . end ( ) ) ;
2012-05-10 18:44:07 +02:00
// release outbound grant (if any)
pnode - > grantOutbound . Release ( ) ;
2012-04-04 16:01:57 +02:00
2010-08-29 18:58:15 +02:00
// close socket and cleanup
pnode - > CloseSocketDisconnect ( ) ;
// hold in disconnected pool until all refs are released
2016-11-27 03:47:22 +01:00
pnode - > Release ( ) ;
2010-08-29 18:58:15 +02:00
vNodesDisconnected . push_back ( pnode ) ;
}
}
2013-07-25 02:25:25 +02:00
}
{
2010-08-29 18:58:15 +02:00
// Delete disconnected nodes
2016-04-16 01:53:45 +02:00
std : : list < CNode * > vNodesDisconnectedCopy = vNodesDisconnected ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesDisconnectedCopy )
2010-08-29 18:58:15 +02:00
{
// wait until threads are done using it
2017-02-04 22:44:05 +01:00
if ( pnode - > GetRefCount ( ) < = 0 ) {
2010-08-29 18:58:15 +02:00
bool fDelete = false ;
2012-04-06 18:39:12 +02:00
{
2017-02-03 02:03:46 +01:00
TRY_LOCK ( pnode - > cs_inventory , lockInv ) ;
2017-02-04 22:44:05 +01:00
if ( lockInv ) {
2017-02-03 02:03:46 +01:00
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
if ( lockSend ) {
fDelete = true ;
}
2012-04-06 18:39:12 +02:00
}
}
2017-02-04 22:44:05 +01:00
if ( fDelete ) {
2010-08-29 18:58:15 +02:00
vNodesDisconnected . remove ( pnode ) ;
2016-05-25 00:59:16 +02:00
DeleteNode ( pnode ) ;
2010-08-29 18:58:15 +02:00
}
}
}
}
2016-11-26 04:29:55 +01:00
size_t vNodesSize ;
{
LOCK ( cs_vNodes ) ;
vNodesSize = vNodes . size ( ) ;
}
if ( vNodesSize ! = nPrevNodeCount ) {
nPrevNodeCount = vNodesSize ;
2016-05-26 03:26:46 +02:00
if ( clientInterface )
clientInterface - > NotifyNumConnectionsChanged ( nPrevNodeCount ) ;
2010-08-29 18:58:15 +02:00
}
//
// Find which sockets have data to receive
//
struct timeval timeout ;
timeout . tv_sec = 0 ;
timeout . tv_usec = 50000 ; // frequency to poll pnode->vSend
fd_set fdsetRecv ;
fd_set fdsetSend ;
fd_set fdsetError ;
FD_ZERO ( & fdsetRecv ) ;
FD_ZERO ( & fdsetSend ) ;
FD_ZERO ( & fdsetError ) ;
SOCKET hSocketMax = 0 ;
2012-09-05 22:01:28 +02:00
bool have_fds = false ;
2010-12-22 14:08:00 +01:00
2017-06-02 03:18:57 +02:00
for ( const ListenSocket & hListenSocket : vhListenSocket ) {
2014-06-21 13:34:36 +02:00
FD_SET ( hListenSocket . socket , & fdsetRecv ) ;
2016-04-16 01:53:45 +02:00
hSocketMax = std : : max ( hSocketMax , hListenSocket . socket ) ;
2012-09-05 22:01:28 +02:00
have_fds = true ;
2012-05-11 15:28:59 +02:00
}
2014-06-24 09:09:45 +02:00
2010-08-29 18:58:15 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodes )
2010-08-29 18:58:15 +02:00
{
2013-04-30 18:42:01 +02:00
// Implement the following logic:
// * If there is data to send, select() for sending data. As this only
// happens when optimistic write failed, we choose to first drain the
// write buffer in this case before receiving more. This avoids
// needlessly queueing received data, if the remote peer is not themselves
// receiving data. This means properly utilizing TCP flow control signalling.
2016-12-31 08:05:36 +01:00
// * Otherwise, if there is space left in the receive buffer, select() for
// receiving data.
// * Hand off all complete messages to the processor, to be handled without
// blocking here.
2017-02-06 19:47:24 +01:00
bool select_recv = ! pnode - > fPauseRecv ;
bool select_send ;
2012-04-06 18:39:12 +02:00
{
2016-12-24 20:34:20 +01:00
LOCK ( pnode - > cs_vSend ) ;
2017-02-06 19:47:24 +01:00
select_send = ! pnode - > vSendMsg . empty ( ) ;
2012-04-06 18:39:12 +02:00
}
2017-02-06 19:47:24 +01:00
2017-02-06 20:05:45 +01:00
LOCK ( pnode - > cs_hSocket ) ;
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
2017-02-06 19:47:24 +01:00
FD_SET ( pnode - > hSocket , & fdsetError ) ;
hSocketMax = std : : max ( hSocketMax , pnode - > hSocket ) ;
have_fds = true ;
if ( select_send ) {
FD_SET ( pnode - > hSocket , & fdsetSend ) ;
continue ;
}
if ( select_recv ) {
FD_SET ( pnode - > hSocket , & fdsetRecv ) ;
2013-04-30 18:42:01 +02:00
}
2010-08-29 18:58:15 +02:00
}
}
2012-09-05 22:01:28 +02:00
int nSelect = select ( have_fds ? hSocketMax + 1 : 0 ,
& fdsetRecv , & fdsetSend , & fdsetError , & timeout ) ;
2016-12-27 23:12:44 +01:00
if ( interruptNet )
return ;
2013-03-07 04:31:26 +01:00
2010-08-29 18:58:15 +02:00
if ( nSelect = = SOCKET_ERROR )
{
2012-09-05 22:01:28 +02:00
if ( have_fds )
2011-06-07 00:48:37 +02:00
{
2012-09-05 22:01:28 +02:00
int nErr = WSAGetLastError ( ) ;
2014-05-08 14:15:19 +02:00
LogPrintf ( " socket select error %s \n " , NetworkErrorString ( nErr ) ) ;
2012-04-15 22:52:09 +02:00
for ( unsigned int i = 0 ; i < = hSocketMax ; i + + )
2011-06-07 00:48:37 +02:00
FD_SET ( i , & fdsetRecv ) ;
}
2010-08-29 18:58:15 +02:00
FD_ZERO ( & fdsetSend ) ;
FD_ZERO ( & fdsetError ) ;
2016-12-27 23:12:44 +01:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( timeout . tv_usec / 1000 ) ) )
return ;
2010-08-29 18:58:15 +02:00
}
//
// Accept new connections
//
2017-06-02 03:18:57 +02:00
for ( const ListenSocket & hListenSocket : vhListenSocket )
2010-08-29 18:58:15 +02:00
{
2014-06-21 13:34:36 +02:00
if ( hListenSocket . socket ! = INVALID_SOCKET & & FD_ISSET ( hListenSocket . socket , & fdsetRecv ) )
2012-04-06 18:39:12 +02:00
{
2015-08-13 11:00:10 +02:00
AcceptConnection ( hListenSocket ) ;
2010-08-29 18:58:15 +02:00
}
}
//
// Service each socket
//
2016-04-16 01:53:45 +02:00
std : : vector < CNode * > vNodesCopy ;
2010-08-29 18:58:15 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-08-29 18:58:15 +02:00
vNodesCopy = vNodes ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 18:58:15 +02:00
pnode - > AddRef ( ) ;
}
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 18:58:15 +02:00
{
2016-12-27 23:12:44 +01:00
if ( interruptNet )
return ;
2010-08-29 18:58:15 +02:00
//
// Receive
//
2017-02-06 19:47:24 +01:00
bool recvSet = false ;
bool sendSet = false ;
bool errorSet = false ;
2017-02-06 20:05:45 +01:00
{
LOCK ( pnode - > cs_hSocket ) ;
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
recvSet = FD_ISSET ( pnode - > hSocket , & fdsetRecv ) ;
sendSet = FD_ISSET ( pnode - > hSocket , & fdsetSend ) ;
errorSet = FD_ISSET ( pnode - > hSocket , & fdsetError ) ;
}
2017-02-06 19:47:24 +01:00
if ( recvSet | | errorSet )
2010-08-29 18:58:15 +02:00
{
2017-03-06 17:54:08 +01:00
// typical socket buffer is 8K-64K
char pchBuf [ 0x10000 ] ;
int nBytes = 0 ;
2010-08-29 18:58:15 +02:00
{
2017-03-06 17:54:08 +01:00
LOCK ( pnode - > cs_hSocket ) ;
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
nBytes = recv ( pnode - > hSocket , pchBuf , sizeof ( pchBuf ) , MSG_DONTWAIT ) ;
}
if ( nBytes > 0 )
{
bool notify = false ;
if ( ! pnode - > ReceiveMsgBytes ( pchBuf , nBytes , notify ) )
pnode - > CloseSocketDisconnect ( ) ;
RecordBytesRecv ( nBytes ) ;
if ( notify ) {
size_t nSizeAdded = 0 ;
auto it ( pnode - > vRecvMsg . begin ( ) ) ;
for ( ; it ! = pnode - > vRecvMsg . end ( ) ; + + it ) {
if ( ! it - > complete ( ) )
break ;
nSizeAdded + = it - > vRecv . size ( ) + CMessageHeader : : HEADER_SIZE ;
2010-08-29 18:58:15 +02:00
}
2011-02-16 19:18:11 +01:00
{
2017-03-06 17:54:08 +01:00
LOCK ( pnode - > cs_vProcessMsg ) ;
pnode - > vProcessMsg . splice ( pnode - > vProcessMsg . end ( ) , pnode - > vRecvMsg , pnode - > vRecvMsg . begin ( ) , it ) ;
pnode - > nProcessQueueSize + = nSizeAdded ;
pnode - > fPauseRecv = pnode - > nProcessQueueSize > nReceiveFloodSize ;
2011-02-16 19:18:11 +01:00
}
2017-03-06 17:54:08 +01:00
WakeMessageHandler ( ) ;
}
}
else if ( nBytes = = 0 )
{
// socket closed gracefully
if ( ! pnode - > fDisconnect ) {
LogPrint ( BCLog : : NET , " socket closed \n " ) ;
}
pnode - > CloseSocketDisconnect ( ) ;
}
else if ( nBytes < 0 )
{
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
{
if ( ! pnode - > fDisconnect )
LogPrintf ( " socket recv error %s \n " , NetworkErrorString ( nErr ) ) ;
pnode - > CloseSocketDisconnect ( ) ;
2010-08-29 18:58:15 +02:00
}
}
}
//
// Send
//
2017-02-06 19:47:24 +01:00
if ( sendSet )
2010-08-29 18:58:15 +02:00
{
2016-12-24 20:34:20 +01:00
LOCK ( pnode - > cs_vSend ) ;
size_t nBytes = SocketSendData ( pnode ) ;
if ( nBytes ) {
RecordBytesSent ( nBytes ) ;
2016-04-19 03:44:42 +02:00
}
2010-08-29 18:58:15 +02:00
}
//
// Inactivity checking
//
2017-01-19 19:01:18 +01:00
int64_t nTime = GetSystemTimeInSeconds ( ) ;
2013-10-15 00:34:20 +02:00
if ( nTime - pnode - > nTimeConnected > 60 )
2010-08-29 18:58:15 +02:00
{
if ( pnode - > nLastRecv = = 0 | | pnode - > nLastSend = = 0 )
{
2017-04-11 18:13:55 +02:00
LogPrint ( BCLog : : NET , " socket no message in first 60 seconds, %d %d from %d \n " , pnode - > nLastRecv ! = 0 , pnode - > nLastSend ! = 0 , pnode - > GetId ( ) ) ;
2010-08-29 18:58:15 +02:00
pnode - > fDisconnect = true ;
}
2013-10-15 00:34:20 +02:00
else if ( nTime - pnode - > nLastSend > TIMEOUT_INTERVAL )
2010-08-29 18:58:15 +02:00
{
2013-10-15 00:34:20 +02:00
LogPrintf ( " socket sending timeout: %is \n " , nTime - pnode - > nLastSend ) ;
2010-08-29 18:58:15 +02:00
pnode - > fDisconnect = true ;
}
2013-10-15 00:34:20 +02:00
else if ( nTime - pnode - > nLastRecv > ( pnode - > nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90 * 60 ) )
2010-08-29 18:58:15 +02:00
{
2013-10-15 00:34:20 +02:00
LogPrintf ( " socket receive timeout: %is \n " , nTime - pnode - > nLastRecv ) ;
pnode - > fDisconnect = true ;
}
else if ( pnode - > nPingNonceSent & & pnode - > nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros ( ) )
{
LogPrintf ( " ping timeout: %fs \n " , 0.000001 * ( GetTimeMicros ( ) - pnode - > nPingUsecStart ) ) ;
2010-08-29 18:58:15 +02:00
pnode - > fDisconnect = true ;
}
2017-02-07 21:23:17 +01:00
else if ( ! pnode - > fSuccessfullyConnected )
{
2018-02-03 10:08:04 +01:00
LogPrint ( BCLog : : NET , " version handshake timeout from %d \n " , pnode - > GetId ( ) ) ;
2017-02-07 21:23:17 +01:00
pnode - > fDisconnect = true ;
}
2010-08-29 18:58:15 +02:00
}
}
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 18:58:15 +02:00
pnode - > Release ( ) ;
}
}
}
2016-12-31 08:05:21 +01:00
void CConnman : : WakeMessageHandler ( )
{
2016-12-31 08:05:26 +01:00
{
std : : lock_guard < std : : mutex > lock ( mutexMsgProc ) ;
fMsgProcWake = true ;
}
2016-12-31 08:05:21 +01:00
condMsgProc . notify_one ( ) ;
}
2010-08-29 18:58:15 +02:00
2011-03-26 13:01:27 +01:00
# ifdef USE_UPNP
2018-02-07 23:20:16 +01:00
static CThreadInterrupt g_upnp_interrupt ;
static std : : thread g_upnp_thread ;
2013-03-07 04:31:26 +01:00
void ThreadMapPort ( )
2011-03-26 13:01:27 +01:00
{
2012-09-05 23:36:19 +02:00
std : : string port = strprintf ( " %u " , GetListenPort ( ) ) ;
2017-06-21 21:10:00 +02:00
const char * multicastif = nullptr ;
const char * minissdpdpath = nullptr ;
struct UPNPDev * devlist = nullptr ;
2011-03-26 13:01:27 +01:00
char lanaddr [ 64 ] ;
2011-12-10 17:52:50 +01:00
# ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 ) ;
2015-08-23 22:53:49 +02:00
# elif MINIUPNPC_API_VERSION < 14
2011-12-10 17:52:50 +01:00
/* miniupnpc 1.6 */
int error = 0 ;
2011-08-12 00:20:07 +02:00
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 , 0 , & error ) ;
2015-08-23 22:53:49 +02:00
# else
/* miniupnpc 1.9.20150730 */
int error = 0 ;
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 , 0 , 2 , & error ) ;
2011-12-10 17:52:50 +01:00
# endif
2011-03-26 13:01:27 +01:00
struct UPNPUrls urls ;
struct IGDdatas data ;
int r ;
2011-04-16 20:35:45 +02:00
r = UPNP_GetValidIGD ( devlist , & urls , & data , lanaddr , sizeof ( lanaddr ) ) ;
if ( r = = 1 )
2011-03-26 13:01:27 +01:00
{
2012-05-24 19:02:21 +02:00
if ( fDiscover ) {
2012-02-10 04:41:42 +01:00
char externalIPAddress [ 40 ] ;
r = UPNP_GetExternalIPAddress ( urls . controlURL , data . first . servicetype , externalIPAddress ) ;
if ( r ! = UPNPCOMMAND_SUCCESS )
2013-09-18 12:38:08 +02:00
LogPrintf ( " UPnP: GetExternalIPAddress() returned %d \n " , r ) ;
2012-02-10 04:41:42 +01:00
else
{
if ( externalIPAddress [ 0 ] )
{
2016-05-31 19:05:52 +02:00
CNetAddr resolved ;
if ( LookupHost ( externalIPAddress , resolved , false ) ) {
LogPrintf ( " UPnP: ExternalIPAddress = %s \n " , resolved . ToString ( ) . c_str ( ) ) ;
AddLocal ( resolved , LOCAL_UPNP ) ;
}
2012-02-10 04:41:42 +01:00
}
else
2013-09-18 12:38:08 +02:00
LogPrintf ( " UPnP: GetExternalIPAddress failed. \n " ) ;
2012-02-10 04:41:42 +01:00
}
}
2016-04-16 01:53:45 +02:00
std : : string strDesc = " Bitcoin " + FormatFullVersion ( ) ;
2011-08-12 00:20:07 +02:00
2018-02-07 23:20:16 +01:00
do {
2012-01-31 23:36:25 +01:00
# ifndef UPNPDISCOVER_SUCCESS
2018-02-07 23:20:16 +01:00
/* miniupnpc 1.5 */
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype ,
port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 ) ;
2012-01-31 23:36:25 +01:00
# else
2018-02-07 23:20:16 +01:00
/* miniupnpc 1.6 */
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype ,
port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 , " 0 " ) ;
2012-01-31 23:36:25 +01:00
# endif
2018-02-07 23:20:16 +01:00
if ( r ! = UPNPCOMMAND_SUCCESS )
LogPrintf ( " AddPortMapping(%s, %s, %s) failed with code %d (%s) \n " ,
port , port , lanaddr , r , strupnperror ( r ) ) ;
else
LogPrintf ( " UPnP Port Mapping successful. \n " ) ;
2011-03-26 13:01:27 +01:00
}
2018-02-07 23:20:16 +01:00
while ( g_upnp_interrupt . sleep_for ( std : : chrono : : minutes ( 20 ) ) ) ;
r = UPNP_DeletePortMapping ( urls . controlURL , data . first . servicetype , port . c_str ( ) , " TCP " , 0 ) ;
LogPrintf ( " UPNP_DeletePortMapping() returned: %d \n " , r ) ;
freeUPNPDevlist ( devlist ) ; devlist = nullptr ;
FreeUPNPUrls ( & urls ) ;
2011-03-26 13:01:27 +01:00
} else {
2013-09-18 12:38:08 +02:00
LogPrintf ( " No valid UPnP IGDs found \n " ) ;
2017-06-21 21:10:00 +02:00
freeUPNPDevlist ( devlist ) ; devlist = nullptr ;
2011-04-16 20:35:45 +02:00
if ( r ! = 0 )
FreeUPNPUrls ( & urls ) ;
2011-03-26 13:01:27 +01:00
}
}
2018-02-07 23:20:16 +01:00
void StartMapPort ( )
2011-03-26 13:01:27 +01:00
{
2018-02-07 23:20:16 +01:00
if ( ! g_upnp_thread . joinable ( ) ) {
assert ( ! g_upnp_interrupt ) ;
g_upnp_thread = std : : thread ( ( std : : bind ( & TraceThread < void ( * ) ( ) > , " upnp " , & ThreadMapPort ) ) ) ;
}
}
2013-03-07 04:31:26 +01:00
2018-02-07 23:20:16 +01:00
void InterruptMapPort ( )
{
if ( g_upnp_thread . joinable ( ) ) {
g_upnp_interrupt ( ) ;
2013-03-07 04:31:26 +01:00
}
2018-02-07 23:20:16 +01:00
}
void StopMapPort ( )
{
if ( g_upnp_thread . joinable ( ) ) {
g_upnp_thread . join ( ) ;
g_upnp_interrupt . reset ( ) ;
2011-03-26 13:01:27 +01:00
}
}
2013-03-07 04:31:26 +01:00
2011-08-09 18:38:17 +02:00
# else
2018-02-07 23:20:16 +01:00
void StartMapPort ( )
{
// Intentionally left blank.
}
void InterruptMapPort ( )
{
// Intentionally left blank.
}
void StopMapPort ( )
2011-08-09 18:38:17 +02:00
{
// Intentionally left blank.
}
2011-03-26 13:01:27 +01:00
# endif
2016-04-16 20:47:18 +02:00
void CConnman : : ThreadDNSAddressSeed ( )
2011-11-21 18:25:00 +01:00
{
2014-07-29 17:04:46 +02:00
// goal: only query DNS seeds if address need is acute
2016-10-18 01:11:35 +02:00
// Avoiding DNS seeds when we don't need them improves user privacy by
// creating fewer identifying DNS requests, reduces trust by giving seeds
// less influence on the network topology, and reduces traffic to the seeds.
2014-07-29 17:04:46 +02:00
if ( ( addrman . size ( ) > 0 ) & &
2017-08-01 21:17:40 +02:00
( ! gArgs . GetBoolArg ( " -forcednsseed " , DEFAULT_FORCEDNSSEED ) ) ) {
2016-12-27 23:12:44 +01:00
if ( ! interruptNet . sleep_for ( std : : chrono : : seconds ( 11 ) ) )
return ;
2014-07-29 17:04:46 +02:00
LOCK ( cs_vNodes ) ;
2016-10-18 01:11:35 +02:00
int nRelevant = 0 ;
for ( auto pnode : vNodes ) {
2017-10-06 23:27:56 +02:00
nRelevant + = pnode - > fSuccessfullyConnected & & ! pnode - > fFeeler & & ! pnode - > fOneShot & & ! pnode - > m_manual_connection & & ! pnode - > fInbound ;
2016-10-18 01:11:35 +02:00
}
if ( nRelevant > = 2 ) {
2014-07-29 17:04:46 +02:00
LogPrintf ( " P2P peers available. Skipped DNS seeding. \n " ) ;
return ;
}
}
2017-10-19 23:32:45 +02:00
const std : : vector < std : : string > & vSeeds = Params ( ) . DNSSeeds ( ) ;
2011-03-09 04:40:50 +01:00
int found = 0 ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Loading addresses from DNS seeds (could take a while) \n " ) ;
2013-01-30 05:13:17 +01:00
2017-10-19 23:32:45 +02:00
for ( const std : : string & seed : vSeeds ) {
2017-04-14 22:29:57 +02:00
if ( interruptNet ) {
return ;
}
2013-01-30 05:13:17 +01:00
if ( HaveNameProxy ( ) ) {
2017-10-19 23:32:45 +02:00
AddOneShot ( seed ) ;
2013-01-30 05:13:17 +01:00
} else {
2016-04-16 01:53:45 +02:00
std : : vector < CNetAddr > vIPs ;
std : : vector < CAddress > vAdd ;
2017-10-04 23:59:30 +02:00
ServiceFlags requiredServiceBits = GetDesirableServiceFlags ( NODE_NONE ) ;
2017-10-19 23:32:45 +02:00
std : : string host = strprintf ( " x%x.%s " , requiredServiceBits , seed ) ;
2017-05-24 02:48:08 +02:00
CNetAddr resolveSource ;
if ( ! resolveSource . SetInternal ( host ) ) {
continue ;
}
if ( LookupHost ( host . c_str ( ) , vIPs , 0 , true ) )
2013-01-30 05:13:17 +01:00
{
2017-06-02 03:18:57 +02:00
for ( const CNetAddr & ip : vIPs )
2011-05-02 15:34:42 +02:00
{
2013-01-30 05:13:17 +01:00
int nOneDay = 24 * 3600 ;
2016-05-21 23:55:22 +02:00
CAddress addr = CAddress ( CService ( ip , Params ( ) . GetDefaultPort ( ) ) , requiredServiceBits ) ;
2013-01-30 05:13:17 +01:00
addr . nTime = GetTime ( ) - 3 * nOneDay - GetRand ( 4 * nOneDay ) ; // use a random age between 3 and 7 days old
vAdd . push_back ( addr ) ;
found + + ;
2011-05-02 15:34:42 +02:00
}
2017-05-24 02:48:08 +02:00
addrman . Add ( vAdd , resolveSource ) ;
2017-10-19 23:32:45 +02:00
} else {
// We now avoid directly using results from DNS Seeds which do not support service bit filtering,
// instead using them as a oneshot to get nodes with our desired service bits.
AddOneShot ( seed ) ;
2016-04-13 02:38:06 +02:00
}
2011-03-09 04:40:50 +01:00
}
}
2013-09-18 12:38:08 +02:00
LogPrintf ( " %d addresses found from DNS seeds \n " , found ) ;
2011-03-09 04:40:50 +01:00
}
2010-08-29 18:58:15 +02:00
2011-11-21 18:25:00 +01:00
2016-04-16 23:43:11 +02:00
void CConnman : : DumpAddresses ( )
2012-01-04 23:39:45 +01:00
{
2013-04-13 07:13:08 +02:00
int64_t nStart = GetTimeMillis ( ) ;
2012-05-17 04:11:19 +02:00
2012-01-04 23:39:45 +01:00
CAddrDB adb ;
2012-05-17 04:11:19 +02:00
adb . Write ( addrman ) ;
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " Flushed %d addresses to peers.dat %dms \n " ,
2012-05-17 04:11:19 +02:00
addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
2012-01-04 23:39:45 +01:00
}
2010-08-29 18:58:15 +02:00
2016-04-16 23:43:11 +02:00
void CConnman : : DumpData ( )
2015-06-19 15:27:37 +02:00
{
DumpAddresses ( ) ;
2015-07-03 10:46:08 +02:00
DumpBanlist ( ) ;
2015-06-19 15:27:37 +02:00
}
2016-04-16 20:47:18 +02:00
void CConnman : : ProcessOneShot ( )
2012-04-24 02:15:00 +02:00
{
2016-04-16 01:53:45 +02:00
std : : string strDest ;
2012-04-24 02:15:00 +02:00
{
LOCK ( cs_vOneShots ) ;
if ( vOneShots . empty ( ) )
return ;
strDest = vOneShots . front ( ) ;
vOneShots . pop_front ( ) ;
}
CAddress addr ;
2012-05-10 18:44:07 +02:00
CSemaphoreGrant grant ( * semOutbound , true ) ;
if ( grant ) {
2018-02-01 20:04:49 +01:00
OpenNetworkConnection ( addr , false , & grant , strDest . c_str ( ) , true ) ;
2012-05-10 18:44:07 +02:00
}
2012-04-24 02:15:00 +02:00
}
2017-10-23 19:36:15 +02:00
bool CConnman : : GetTryNewOutboundPeer ( )
{
return m_try_another_outbound_peer ;
}
void CConnman : : SetTryNewOutboundPeer ( bool flag )
{
m_try_another_outbound_peer = flag ;
2017-10-24 22:56:07 +02:00
LogPrint ( BCLog : : NET , " net: setting try another outbound peer=%s \n " , flag ? " true " : " false " ) ;
2017-10-23 19:36:15 +02:00
}
// Return the number of peers we have over our outbound connection limit
// Exclude peers that are marked for disconnect, or are going to be
// disconnected soon (eg one-shots and feelers)
// Also exclude peers that haven't finished initial connection handshake yet
// (so that we don't decide we're over our desired connection limit, and then
// evict some peer that has finished the handshake)
int CConnman : : GetExtraOutboundCount ( )
{
int nOutbound = 0 ;
{
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes ) {
if ( ! pnode - > fInbound & & ! pnode - > m_manual_connection & & ! pnode - > fFeeler & & ! pnode - > fDisconnect & & ! pnode - > fOneShot & & pnode - > fSuccessfullyConnected ) {
+ + nOutbound ;
}
}
}
return std : : max ( nOutbound - nMaxOutbound , 0 ) ;
}
2017-06-15 09:39:07 +02:00
void CConnman : : ThreadOpenConnections ( const std : : vector < std : : string > connect )
2010-08-29 18:58:15 +02:00
{
// Connect to specific addresses
2017-06-15 09:39:07 +02:00
if ( ! connect . empty ( ) )
2010-08-29 18:58:15 +02:00
{
2013-04-13 07:13:08 +02:00
for ( int64_t nLoop = 0 ; ; nLoop + + )
2010-08-29 18:58:15 +02:00
{
2012-04-24 02:15:00 +02:00
ProcessOneShot ( ) ;
2017-06-15 09:39:07 +02:00
for ( const std : : string & strAddr : connect )
2010-08-29 18:58:15 +02:00
{
2016-06-08 19:12:22 +02:00
CAddress addr ( CService ( ) , NODE_NONE ) ;
2017-10-04 23:59:30 +02:00
OpenNetworkConnection ( addr , false , nullptr , strAddr . c_str ( ) , false , false , true ) ;
2010-08-29 18:58:15 +02:00
for ( int i = 0 ; i < 10 & & i < nLoop ; i + + )
{
2016-12-27 23:12:44 +01:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2010-08-29 18:58:15 +02:00
}
}
2016-12-27 23:12:44 +01:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2010-08-29 18:58:15 +02:00
}
}
// Initiate network connections
2013-04-13 07:13:08 +02:00
int64_t nStart = GetTime ( ) ;
2016-06-17 06:10:07 +02:00
// Minimum time before next feeler connection (in microseconds).
int64_t nNextFeeler = PoissonNextSend ( nStart * 1000 * 1000 , FEELER_INTERVAL ) ;
2016-12-27 23:12:44 +01:00
while ( ! interruptNet )
2010-08-29 18:58:15 +02:00
{
2012-04-24 02:15:00 +02:00
ProcessOneShot ( ) ;
2016-12-27 23:12:44 +01:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2012-02-15 21:17:15 +01:00
2012-05-10 18:44:07 +02:00
CSemaphoreGrant grant ( * semOutbound ) ;
2016-12-27 23:12:44 +01:00
if ( interruptNet )
return ;
2010-08-29 18:58:15 +02:00
2013-05-07 15:16:25 +02:00
// Add seed nodes if DNS seeds are all down (an infrastructure attack?).
if ( addrman . size ( ) = = 0 & & ( GetTime ( ) - nStart > 60 ) ) {
static bool done = false ;
if ( ! done ) {
2013-09-18 12:38:08 +02:00
LogPrintf ( " Adding fixed seed nodes as DNS doesn't seem to be available. \n " ) ;
2016-05-31 19:05:52 +02:00
CNetAddr local ;
2017-06-21 21:45:20 +02:00
local . SetInternal ( " fixedseeds " ) ;
2016-05-31 19:05:52 +02:00
addrman . Add ( convertSeed6 ( Params ( ) . FixedSeeds ( ) ) , local ) ;
2013-05-07 15:16:25 +02:00
done = true ;
2010-08-29 18:58:15 +02:00
}
}
//
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect ;
2012-07-02 02:23:26 +02:00
// Only connect out to one peer per network group (/16 for IPv4).
2010-08-29 18:58:15 +02:00
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
2012-05-10 18:44:07 +02:00
int nOutbound = 0 ;
2016-04-16 01:53:45 +02:00
std : : set < std : : vector < unsigned char > > setConnected ;
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_vNodes ) ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodes ) {
2017-10-05 17:49:16 +02:00
if ( ! pnode - > fInbound & & ! pnode - > m_manual_connection ) {
2016-12-11 21:26:06 +01:00
// Netgroups for inbound and addnode peers are not excluded because our goal here
// is to not use multiple of our limited outbound slots on a single netgroup
// but inbound and addnode peers do not use our outbound slots. Inbound peers
// also have the added issue that they're attacker controlled and could be used
// to prevent us from connecting to particular hosts if we used them here.
2012-07-02 02:23:26 +02:00
setConnected . insert ( pnode - > addr . GetGroup ( ) ) ;
2012-05-10 18:44:07 +02:00
nOutbound + + ;
2012-07-02 02:23:26 +02:00
}
2012-05-10 18:44:07 +02:00
}
2012-04-06 18:39:12 +02:00
}
2010-08-29 18:58:15 +02:00
2016-06-17 06:10:07 +02:00
// Feeler Connections
//
// Design goals:
// * Increase the number of connectable addresses in the tried table.
//
// Method:
2017-05-27 12:00:37 +02:00
// * Choose a random address from new and attempt to connect to it if we can connect
2016-06-17 06:10:07 +02:00
// successfully it is added to tried.
2017-05-27 12:00:37 +02:00
// * Start attempting feeler connections only after node finishes making outbound
2016-06-17 06:10:07 +02:00
// connections.
// * Only make a feeler connection once every few minutes.
//
bool fFeeler = false ;
2017-10-23 19:36:15 +02:00
if ( nOutbound > = nMaxOutbound & & ! GetTryNewOutboundPeer ( ) ) {
2016-06-17 06:10:07 +02:00
int64_t nTime = GetTimeMicros ( ) ; // The current time right now (in microseconds).
if ( nTime > nNextFeeler ) {
nNextFeeler = PoissonNextSend ( nTime , FEELER_INTERVAL ) ;
fFeeler = true ;
} else {
continue ;
}
}
2011-10-04 05:41:47 +02:00
2016-06-17 06:10:07 +02:00
int64_t nANow = GetAdjustedTime ( ) ;
2012-01-04 23:39:45 +01:00
int nTries = 0 ;
2016-12-27 23:12:44 +01:00
while ( ! interruptNet )
2010-08-29 18:58:15 +02:00
{
2016-06-17 06:10:07 +02:00
CAddrInfo addr = addrman . Select ( fFeeler ) ;
2010-08-29 18:58:15 +02:00
2012-01-04 23:39:45 +01:00
// if we selected an invalid address, restart
2012-03-31 17:58:25 +02:00
if ( ! addr . IsValid ( ) | | setConnected . count ( addr . GetGroup ( ) ) | | IsLocal ( addr ) )
2012-01-04 23:39:45 +01:00
break ;
2010-08-29 18:58:15 +02:00
2012-08-21 17:32:04 +02:00
// If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
// stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
// already-connected network ranges, ...) before trying new addrman addresses.
2012-01-04 23:39:45 +01:00
nTries + + ;
2012-08-21 17:32:04 +02:00
if ( nTries > 100 )
break ;
2010-08-29 18:58:15 +02:00
2012-05-04 16:46:22 +02:00
if ( IsLimited ( addr ) )
continue ;
2012-01-04 23:39:45 +01:00
// only consider very recently tried nodes after 30 failed attempts
if ( nANow - addr . nLastTry < 600 & & nTries < 30 )
continue ;
2017-10-04 23:59:30 +02:00
// for non-feelers, require all the services we'll want,
// for feelers, only require they be a full node (only because most
// SPV clients don't have a good address DB available)
if ( ! fFeeler & & ! HasAllDesirableServiceFlags ( addr . nServices ) ) {
continue ;
} else if ( fFeeler & & ! MayHaveUsefulAddressDB ( addr . nServices ) ) {
2015-11-17 00:20:49 +01:00
continue ;
2017-05-24 23:00:27 +02:00
}
2015-11-17 00:20:49 +01:00
2012-01-04 23:39:45 +01:00
// do not allow non-default ports, unless after 50 invalid addresses selected already
2013-05-07 15:16:25 +02:00
if ( addr . GetPort ( ) ! = Params ( ) . GetDefaultPort ( ) & & nTries < 50 )
2012-01-04 23:39:45 +01:00
continue ;
addrConnect = addr ;
break ;
2010-08-29 18:58:15 +02:00
}
2016-06-17 06:10:07 +02:00
if ( addrConnect . IsValid ( ) ) {
if ( fFeeler ) {
// Add small amount of random noise before connection to avoid synchronization.
int randsleep = GetRandInt ( FEELER_SLEEP_WINDOW * 1000 ) ;
2016-12-27 23:12:44 +01:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( randsleep ) ) )
return ;
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " Making feeler connection to %s \n " , addrConnect . ToString ( ) ) ;
2016-06-17 06:10:07 +02:00
}
2017-08-07 07:36:37 +02:00
OpenNetworkConnection ( addrConnect , ( int ) setConnected . size ( ) > = std : : min ( nMaxConnections - 1 , 2 ) , & grant , nullptr , false , fFeeler ) ;
2016-06-17 06:10:07 +02:00
}
2010-08-29 18:58:15 +02:00
}
}
2016-04-17 00:12:58 +02:00
std : : vector < AddedNodeInfo > CConnman : : GetAddedNodeInfo ( )
2011-12-17 01:48:03 +01:00
{
2016-05-28 15:32:30 +02:00
std : : vector < AddedNodeInfo > ret ;
std : : list < std : : string > lAddresses ( 0 ) ;
2012-07-02 19:55:16 +02:00
{
LOCK ( cs_vAddedNodes ) ;
2016-05-28 15:32:30 +02:00
ret . reserve ( vAddedNodes . size ( ) ) ;
2017-07-20 11:32:47 +02:00
std : : copy ( vAddedNodes . cbegin ( ) , vAddedNodes . cend ( ) , std : : back_inserter ( lAddresses ) ) ;
2012-07-02 19:55:16 +02:00
}
2011-12-17 01:48:03 +01:00
2016-05-28 15:32:30 +02:00
// Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService
std : : map < CService , bool > mapConnected ;
std : : map < std : : string , std : : pair < bool , CService > > mapConnectedByName ;
{
LOCK ( cs_vNodes ) ;
for ( const CNode * pnode : vNodes ) {
if ( pnode - > addr . IsValid ( ) ) {
mapConnected [ pnode - > addr ] = pnode - > fInbound ;
2012-07-02 19:55:16 +02:00
}
2017-02-06 18:04:34 +01:00
std : : string addrName = pnode - > GetAddrName ( ) ;
if ( ! addrName . empty ( ) ) {
mapConnectedByName [ std : : move ( addrName ) ] = std : : make_pair ( pnode - > fInbound , static_cast < const CService & > ( pnode - > addr ) ) ;
2012-04-19 17:38:03 +02:00
}
}
}
2017-06-02 03:18:57 +02:00
for ( const std : : string & strAddNode : lAddresses ) {
2016-08-04 22:37:49 +02:00
CService service ( LookupNumeric ( strAddNode . c_str ( ) , Params ( ) . GetDefaultPort ( ) ) ) ;
2016-05-28 15:32:30 +02:00
if ( service . IsValid ( ) ) {
// strAddNode is an IP:port
auto it = mapConnected . find ( service ) ;
if ( it ! = mapConnected . end ( ) ) {
ret . push_back ( AddedNodeInfo { strAddNode , service , true , it - > second } ) ;
} else {
ret . push_back ( AddedNodeInfo { strAddNode , CService ( ) , false , false } ) ;
}
} else {
// strAddNode is a name
auto it = mapConnectedByName . find ( strAddNode ) ;
if ( it ! = mapConnectedByName . end ( ) ) {
ret . push_back ( AddedNodeInfo { strAddNode , it - > second . second , true , it - > second . first } ) ;
} else {
ret . push_back ( AddedNodeInfo { strAddNode , CService ( ) , false , false } ) ;
2012-04-19 17:38:03 +02:00
}
}
}
2016-05-28 15:32:30 +02:00
return ret ;
}
2016-04-16 20:47:18 +02:00
void CConnman : : ThreadOpenAddedConnections ( )
2016-05-28 15:32:30 +02:00
{
2016-12-11 05:39:26 +01:00
while ( true )
2011-12-17 01:48:03 +01:00
{
2016-12-11 05:39:26 +01:00
CSemaphoreGrant grant ( * semAddnode ) ;
2016-05-28 15:32:30 +02:00
std : : vector < AddedNodeInfo > vInfo = GetAddedNodeInfo ( ) ;
2016-12-11 05:39:26 +01:00
bool tried = false ;
2016-05-28 15:32:30 +02:00
for ( const AddedNodeInfo & info : vInfo ) {
if ( ! info . fConnected ) {
2016-12-11 05:39:26 +01:00
if ( ! grant . TryAcquire ( ) ) {
// If we've used up our semaphore and need a new one, lets not wait here since while we are waiting
// the addednodeinfo state might change.
break ;
}
tried = true ;
2017-06-23 18:29:50 +02:00
CAddress addr ( CService ( ) , NODE_NONE ) ;
OpenNetworkConnection ( addr , false , & grant , info . strAddedNode . c_str ( ) , false , false , true ) ;
2016-12-27 23:12:44 +01:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2016-05-28 15:32:30 +02:00
}
2012-07-02 19:55:16 +02:00
}
2016-12-11 05:39:26 +01:00
// Retry every 60 seconds if a connection was attempted, otherwise two seconds
2017-01-07 18:49:14 +01:00
if ( ! interruptNet . sleep_for ( std : : chrono : : seconds ( tried ? 60 : 2 ) ) )
2016-12-27 23:12:44 +01:00
return ;
2011-12-17 01:48:03 +01:00
}
}
2012-07-26 02:48:39 +02:00
// if successful, this moves the passed grant to the constructed node
2018-02-01 20:04:49 +01:00
void CConnman : : OpenNetworkConnection ( const CAddress & addrConnect , bool fCountFailure , CSemaphoreGrant * grantOutbound , const char * pszDest , bool fOneShot , bool fFeeler , bool manual_connection )
2010-08-29 18:58:15 +02:00
{
//
// Initiate outbound network connection
//
2016-12-27 23:12:44 +01:00
if ( interruptNet ) {
2018-02-01 20:04:49 +01:00
return ;
2016-12-27 23:12:44 +01:00
}
2013-03-26 02:33:25 +01:00
if ( ! fNetworkActive ) {
2018-02-01 20:04:49 +01:00
return ;
2013-03-26 02:33:25 +01:00
}
2014-05-24 11:14:52 +02:00
if ( ! pszDest ) {
2012-02-12 13:45:24 +01:00
if ( IsLocal ( addrConnect ) | |
2017-06-01 16:13:35 +02:00
FindNode ( static_cast < CNetAddr > ( addrConnect ) ) | | IsBanned ( addrConnect ) | |
2014-07-21 15:00:42 +02:00
FindNode ( addrConnect . ToStringIPPort ( ) ) )
2018-02-01 20:04:49 +01:00
return ;
2015-05-31 15:44:22 +02:00
} else if ( FindNode ( std : : string ( pszDest ) ) )
2018-02-01 20:04:49 +01:00
return ;
2010-08-29 18:58:15 +02:00
2015-04-19 21:34:43 +02:00
CNode * pnode = ConnectNode ( addrConnect , pszDest , fCountFailure ) ;
2013-03-07 04:31:26 +01:00
2010-08-29 18:58:15 +02:00
if ( ! pnode )
2018-02-01 20:04:49 +01:00
return ;
2012-05-10 18:44:07 +02:00
if ( grantOutbound )
grantOutbound - > MoveTo ( pnode - > grantOutbound ) ;
2012-04-24 02:15:00 +02:00
if ( fOneShot )
pnode - > fOneShot = true ;
2016-06-17 06:10:07 +02:00
if ( fFeeler )
pnode - > fFeeler = true ;
2017-10-05 17:49:16 +02:00
if ( manual_connection )
pnode - > m_manual_connection = true ;
2010-08-29 18:58:15 +02:00
2017-07-06 20:08:23 +02:00
m_msgproc - > InitializeNode ( pnode ) ;
2017-01-24 22:51:22 +01:00
{
LOCK ( cs_vNodes ) ;
vNodes . push_back ( pnode ) ;
}
2010-08-29 18:58:15 +02:00
}
2016-04-16 20:47:18 +02:00
void CConnman : : ThreadMessageHandler ( )
2010-08-29 18:58:15 +02:00
{
2016-12-27 23:12:44 +01:00
while ( ! flagInterruptMsgProc )
2010-08-29 18:58:15 +02:00
{
2016-04-16 01:53:45 +02:00
std : : vector < CNode * > vNodesCopy ;
2010-08-29 18:58:15 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2010-08-29 18:58:15 +02:00
vNodesCopy = vNodes ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesCopy ) {
2010-08-29 18:58:15 +02:00
pnode - > AddRef ( ) ;
2013-04-05 00:43:04 +02:00
}
2010-08-29 18:58:15 +02:00
}
2016-12-31 08:05:26 +01:00
bool fMoreWork = false ;
2013-11-15 12:24:34 +01:00
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 18:58:15 +02:00
{
2013-03-01 01:41:28 +01:00
if ( pnode - > fDisconnect )
continue ;
2010-08-29 18:58:15 +02:00
// Receive messages
2017-07-06 20:08:23 +02:00
bool fMoreNodeWork = m_msgproc - > ProcessMessages ( pnode , flagInterruptMsgProc ) ;
2016-12-31 08:05:36 +01:00
fMoreWork | = ( fMoreNodeWork & & ! pnode - > fPauseSend ) ;
2016-12-27 23:12:44 +01:00
if ( flagInterruptMsgProc )
return ;
2010-08-29 18:58:15 +02:00
// Send messages
2012-04-06 18:39:12 +02:00
{
2017-01-13 05:08:52 +01:00
LOCK ( pnode - > cs_sendProcessing ) ;
2017-07-06 20:08:23 +02:00
m_msgproc - > SendMessages ( pnode , flagInterruptMsgProc ) ;
2012-04-06 18:39:12 +02:00
}
2017-07-06 19:40:09 +02:00
2016-12-27 23:12:44 +01:00
if ( flagInterruptMsgProc )
return ;
2010-08-29 18:58:15 +02:00
}
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_vNodes ) ;
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 18:58:15 +02:00
pnode - > Release ( ) ;
}
2013-11-15 12:24:34 +01:00
2016-12-31 08:05:26 +01:00
std : : unique_lock < std : : mutex > lock ( mutexMsgProc ) ;
if ( ! fMoreWork ) {
condMsgProc . wait_until ( lock , std : : chrono : : steady_clock : : now ( ) + std : : chrono : : milliseconds ( 100 ) , [ this ] { return fMsgProcWake ; } ) ;
2016-12-27 23:12:44 +01:00
}
2016-12-31 08:05:26 +01:00
fMsgProcWake = false ;
2010-08-29 18:58:15 +02:00
}
}
2016-04-16 21:46:00 +02:00
bool CConnman : : BindListenPort ( const CService & addrBind , std : : string & strError , bool fWhitelisted )
2010-08-29 18:58:15 +02:00
{
strError = " " ;
int nOne = 1 ;
// Create socket for listening for incoming connections
2012-05-11 15:28:59 +02:00
struct sockaddr_storage sockaddr ;
socklen_t len = sizeof ( sockaddr ) ;
if ( ! addrBind . GetSockAddr ( ( struct sockaddr * ) & sockaddr , & len ) )
{
2014-05-24 11:14:52 +02:00
strError = strprintf ( " Error: Bind address family for %s not supported " , addrBind . ToString ( ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
2012-05-11 15:28:59 +02:00
return false ;
}
2017-10-02 22:31:37 +02:00
SOCKET hListenSocket = CreateSocket ( addrBind ) ;
2010-08-29 18:58:15 +02:00
if ( hListenSocket = = INVALID_SOCKET )
{
2014-05-08 14:15:19 +02:00
strError = strprintf ( " Error: Couldn't open socket for incoming connections (socket returned error %s) " , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
2010-08-29 18:58:15 +02:00
return false ;
}
2014-06-24 09:03:18 +02:00
# ifndef WIN32
2010-08-29 18:58:15 +02:00
// Allow binding if the port is still in TIME_WAIT state after
2015-08-20 21:50:13 +02:00
// the program was closed and restarted.
2010-08-29 18:58:15 +02:00
setsockopt ( hListenSocket , SOL_SOCKET , SO_REUSEADDR , ( void * ) & nOne , sizeof ( int ) ) ;
2015-08-20 21:50:13 +02:00
# else
setsockopt ( hListenSocket , SOL_SOCKET , SO_REUSEADDR , ( const char * ) & nOne , sizeof ( int ) ) ;
2010-08-29 18:58:15 +02:00
# endif
2012-05-11 15:28:59 +02:00
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if ( addrBind . IsIPv6 ( ) ) {
# ifdef IPV6_V6ONLY
2013-07-13 13:05:04 +02:00
# ifdef WIN32
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( const char * ) & nOne , sizeof ( int ) ) ;
# else
2012-05-11 15:28:59 +02:00
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( void * ) & nOne , sizeof ( int ) ) ;
2012-03-31 17:58:25 +02:00
# endif
2013-07-13 13:05:04 +02:00
# endif
2012-05-11 15:28:59 +02:00
# ifdef WIN32
2014-06-24 09:03:18 +02:00
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED ;
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_PROTECTION_LEVEL , ( const char * ) & nProtLevel , sizeof ( int ) ) ;
2012-05-11 15:28:59 +02:00
# endif
}
if ( : : bind ( hListenSocket , ( struct sockaddr * ) & sockaddr , len ) = = SOCKET_ERROR )
2010-08-29 18:58:15 +02:00
{
int nErr = WSAGetLastError ( ) ;
if ( nErr = = WSAEADDRINUSE )
2015-12-09 11:53:12 +01:00
strError = strprintf ( _ ( " Unable to bind to %s on this computer. %s is probably already running. " ) , addrBind . ToString ( ) , _ ( PACKAGE_NAME ) ) ;
2010-08-29 18:58:15 +02:00
else
2014-05-08 14:15:19 +02:00
strError = strprintf ( _ ( " Unable to bind to %s on this computer (bind returned error %s) " ) , addrBind . ToString ( ) , NetworkErrorString ( nErr ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
2014-07-17 22:33:58 +02:00
CloseSocket ( hListenSocket ) ;
2010-08-29 18:58:15 +02:00
return false ;
}
2014-01-16 16:15:27 +01:00
LogPrintf ( " Bound to %s \n " , addrBind . ToString ( ) ) ;
2010-08-29 18:58:15 +02:00
// Listen for incoming connections
if ( listen ( hListenSocket , SOMAXCONN ) = = SOCKET_ERROR )
{
2014-05-08 14:15:19 +02:00
strError = strprintf ( _ ( " Error: Listening for incoming connections failed (listen returned error %s) " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " %s \n " , strError ) ;
2014-07-17 22:33:58 +02:00
CloseSocket ( hListenSocket ) ;
2010-08-29 18:58:15 +02:00
return false ;
}
2014-06-21 13:34:36 +02:00
vhListenSocket . push_back ( ListenSocket ( hListenSocket , fWhitelisted ) ) ;
2012-05-11 15:28:59 +02:00
2014-06-21 13:34:36 +02:00
if ( addrBind . IsRoutable ( ) & & fDiscover & & ! fWhitelisted )
2012-05-11 15:28:59 +02:00
AddLocal ( addrBind , LOCAL_BIND ) ;
2010-08-29 18:58:15 +02:00
return true ;
}
2018-02-07 23:42:39 +01:00
void Discover ( )
2010-08-29 18:58:15 +02:00
{
2012-05-24 19:02:21 +02:00
if ( ! fDiscover )
2012-02-19 20:44:35 +01:00
return ;
2010-08-29 18:58:15 +02:00
2011-10-07 17:02:21 +02:00
# ifdef WIN32
2012-07-26 02:48:39 +02:00
// Get local host IP
2014-11-13 15:23:15 +01:00
char pszHostName [ 256 ] = " " ;
2010-08-29 18:58:15 +02:00
if ( gethostname ( pszHostName , sizeof ( pszHostName ) ) ! = SOCKET_ERROR )
{
2016-04-16 01:53:45 +02:00
std : : vector < CNetAddr > vaddr ;
2016-04-13 02:23:16 +02:00
if ( LookupHost ( pszHostName , vaddr , 0 , true ) )
2012-05-01 01:44:59 +02:00
{
2017-06-02 03:18:57 +02:00
for ( const CNetAddr & addr : vaddr )
2012-05-01 01:44:59 +02:00
{
2014-11-13 15:20:57 +01:00
if ( AddLocal ( addr , LOCAL_IF ) )
LogPrintf ( " %s: %s - %s \n " , __func__ , pszHostName , addr . ToString ( ) ) ;
2012-05-01 01:44:59 +02:00
}
}
2010-08-29 18:58:15 +02:00
}
# else
// Get local host ip
struct ifaddrs * myaddrs ;
if ( getifaddrs ( & myaddrs ) = = 0 )
{
2017-08-07 07:36:37 +02:00
for ( struct ifaddrs * ifa = myaddrs ; ifa ! = nullptr ; ifa = ifa - > ifa_next )
2010-08-29 18:58:15 +02:00
{
2017-08-07 07:36:37 +02:00
if ( ifa - > ifa_addr = = nullptr ) continue ;
2010-08-29 18:58:15 +02:00
if ( ( ifa - > ifa_flags & IFF_UP ) = = 0 ) continue ;
if ( strcmp ( ifa - > ifa_name , " lo " ) = = 0 ) continue ;
if ( strcmp ( ifa - > ifa_name , " lo0 " ) = = 0 ) continue ;
if ( ifa - > ifa_addr - > sa_family = = AF_INET )
{
struct sockaddr_in * s4 = ( struct sockaddr_in * ) ( ifa - > ifa_addr ) ;
2012-02-12 13:45:24 +01:00
CNetAddr addr ( s4 - > sin_addr ) ;
2012-03-31 17:58:25 +02:00
if ( AddLocal ( addr , LOCAL_IF ) )
2014-11-13 15:20:57 +01:00
LogPrintf ( " %s: IPv4 %s: %s \n " , __func__ , ifa - > ifa_name , addr . ToString ( ) ) ;
2010-08-29 18:58:15 +02:00
}
else if ( ifa - > ifa_addr - > sa_family = = AF_INET6 )
{
struct sockaddr_in6 * s6 = ( struct sockaddr_in6 * ) ( ifa - > ifa_addr ) ;
2012-02-12 13:45:24 +01:00
CNetAddr addr ( s6 - > sin6_addr ) ;
2012-03-31 17:58:25 +02:00
if ( AddLocal ( addr , LOCAL_IF ) )
2014-11-13 15:20:57 +01:00
LogPrintf ( " %s: IPv6 %s: %s \n " , __func__ , ifa - > ifa_name , addr . ToString ( ) ) ;
2010-08-29 18:58:15 +02:00
}
}
freeifaddrs ( myaddrs ) ;
}
# endif
2012-02-19 20:44:35 +01:00
}
2013-03-26 02:33:25 +01:00
void CConnman : : SetNetworkActive ( bool active )
{
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " SetNetworkActive: %s \n " , active ) ;
2013-03-26 02:33:25 +01:00
2017-07-14 16:00:19 +02:00
if ( fNetworkActive = = active ) {
return ;
}
fNetworkActive = active ;
2013-03-26 02:33:25 +01:00
2017-07-14 16:00:19 +02:00
if ( ! fNetworkActive ) {
2013-03-26 02:33:25 +01:00
LOCK ( cs_vNodes ) ;
// Close sockets to all nodes
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodes ) {
2013-03-26 02:33:25 +01:00
pnode - > CloseSocketDisconnect ( ) ;
}
}
2013-03-26 03:07:06 +01:00
uiInterface . NotifyNetworkActiveChanged ( fNetworkActive ) ;
2013-03-26 02:33:25 +01:00
}
2016-09-09 12:48:10 +02:00
CConnman : : CConnman ( uint64_t nSeed0In , uint64_t nSeed1In ) : nSeed0 ( nSeed0In ) , nSeed1 ( nSeed1In )
2016-04-16 20:47:18 +02:00
{
2013-03-26 02:33:25 +01:00
fNetworkActive = true ;
2016-04-16 23:43:11 +02:00
setBannedIsDirty = false ;
fAddressesInitialized = false ;
2016-04-18 02:20:34 +02:00
nLastNodeId = 0 ;
2016-04-19 06:01:19 +02:00
nSendBufferMaxSize = 0 ;
nReceiveFloodSize = 0 ;
2016-12-27 23:12:44 +01:00
flagInterruptMsgProc = false ;
2017-10-23 19:36:15 +02:00
SetTryNewOutboundPeer ( false ) ;
[net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest& request)
When running test_bitcoin under Valgrind I found the following issue:
```
$ valgrind src/test/test_bitcoin
...
==10465== Use of uninitialised value of size 8
==10465== at 0x6D09B61: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B1BB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<unsigned long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B36C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D17699: std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x4CAAD7: operator<< (ostream:171)
==10465== by 0x4CAAD7: formatValue<ServiceFlags> (tinyformat.h:345)
==10465== by 0x4CAAD7: void tinyformat::detail::FormatArg::formatImpl<ServiceFlags>(std::ostream&, char const*, char const*, int, void const*) (tinyformat.h:523)
==10465== by 0x1924D4: format (tinyformat.h:510)
==10465== by 0x1924D4: tinyformat::detail::formatImpl(std::ostream&, char const*, tinyformat::detail::FormatArg const*, int) (tinyformat.h:803)
==10465== by 0x553A55: vformat (tinyformat.h:947)
==10465== by 0x553A55: format<ServiceFlags> (tinyformat.h:957)
==10465== by 0x553A55: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > tinyformat::format<ServiceFlags>(char const*, ServiceFlags const&) (tinyformat.h:966)
==10465== by 0x54C952: getnetworkinfo(JSONRPCRequest const&) (net.cpp:462)
==10465== by 0x28EDB5: CallRPC(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (rpc_tests.cpp:31)
==10465== by 0x293947: rpc_tests::rpc_togglenetwork::test_method() (rpc_tests.cpp:88)
==10465== by 0x2950E5: rpc_tests::rpc_togglenetwork_invoker() (rpc_tests.cpp:84)
==10465== by 0x182496: invoke<void (*)()> (callback.hpp:56)
==10465== by 0x182496: boost::unit_test::ut_detail::callback0_impl_t<boost::unit_test::ut_detail::unused, void (*)()>::invoke() (callback.hpp:89)
...
```
The read of the uninitialized variable nLocalServices is triggered by g_connman->GetLocalServices()
in getnetworkinfo(const JSONRPCRequest& request) (net.cpp:462):
```c++
UniValue getnetworkinfo(const JSONRPCRequest& request)
{
...
if(g_connman)
obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
...
}
```
The reason for the uninitialized nLocalServices is that CConnman::Start(...) is not called
by the tests, and hence the initialization normally performed by CConnman::Start(...) is
not done.
This commit adds a method Init(const Options& connOptions) which is called by both the
constructor and CConnman::Start(...). This method initializes nLocalServices and the other
relevant values from the supplied Options object.
2017-08-02 14:02:36 +02:00
Options connOptions ;
Init ( connOptions ) ;
2016-04-16 20:47:18 +02:00
}
2016-04-18 02:20:34 +02:00
NodeId CConnman : : GetNewNodeId ( )
2016-04-16 23:43:11 +02:00
{
2016-04-18 02:20:34 +02:00
return nLastNodeId . fetch_add ( 1 , std : : memory_order_relaxed ) ;
}
2016-04-16 23:43:11 +02:00
2017-06-01 12:34:02 +02:00
bool CConnman : : Bind ( const CService & addr , unsigned int flags ) {
if ( ! ( flags & BF_EXPLICIT ) & & IsLimited ( addr ) )
return false ;
std : : string strError ;
if ( ! BindListenPort ( addr , strError , ( flags & BF_WHITELIST ) ! = 0 ) ) {
if ( ( flags & BF_REPORT_ERROR ) & & clientInterface ) {
clientInterface - > ThreadSafeMessageBox ( strError , " " , CClientUIInterface : : MSG_ERROR ) ;
}
return false ;
}
return true ;
}
bool CConnman : : InitBinds ( const std : : vector < CService > & binds , const std : : vector < CService > & whiteBinds ) {
bool fBound = false ;
for ( const auto & addrBind : binds ) {
fBound | = Bind ( addrBind , ( BF_EXPLICIT | BF_REPORT_ERROR ) ) ;
}
for ( const auto & addrBind : whiteBinds ) {
fBound | = Bind ( addrBind , ( BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST ) ) ;
}
if ( binds . empty ( ) & & whiteBinds . empty ( ) ) {
struct in_addr inaddr_any ;
inaddr_any . s_addr = INADDR_ANY ;
fBound | = Bind ( CService ( in6addr_any , GetListenPort ( ) ) , BF_NONE ) ;
fBound | = Bind ( CService ( inaddr_any , GetListenPort ( ) ) , ! fBound ? BF_REPORT_ERROR : BF_NONE ) ;
}
return fBound ;
}
[net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest& request)
When running test_bitcoin under Valgrind I found the following issue:
```
$ valgrind src/test/test_bitcoin
...
==10465== Use of uninitialised value of size 8
==10465== at 0x6D09B61: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B1BB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<unsigned long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B36C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D17699: std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x4CAAD7: operator<< (ostream:171)
==10465== by 0x4CAAD7: formatValue<ServiceFlags> (tinyformat.h:345)
==10465== by 0x4CAAD7: void tinyformat::detail::FormatArg::formatImpl<ServiceFlags>(std::ostream&, char const*, char const*, int, void const*) (tinyformat.h:523)
==10465== by 0x1924D4: format (tinyformat.h:510)
==10465== by 0x1924D4: tinyformat::detail::formatImpl(std::ostream&, char const*, tinyformat::detail::FormatArg const*, int) (tinyformat.h:803)
==10465== by 0x553A55: vformat (tinyformat.h:947)
==10465== by 0x553A55: format<ServiceFlags> (tinyformat.h:957)
==10465== by 0x553A55: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > tinyformat::format<ServiceFlags>(char const*, ServiceFlags const&) (tinyformat.h:966)
==10465== by 0x54C952: getnetworkinfo(JSONRPCRequest const&) (net.cpp:462)
==10465== by 0x28EDB5: CallRPC(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (rpc_tests.cpp:31)
==10465== by 0x293947: rpc_tests::rpc_togglenetwork::test_method() (rpc_tests.cpp:88)
==10465== by 0x2950E5: rpc_tests::rpc_togglenetwork_invoker() (rpc_tests.cpp:84)
==10465== by 0x182496: invoke<void (*)()> (callback.hpp:56)
==10465== by 0x182496: boost::unit_test::ut_detail::callback0_impl_t<boost::unit_test::ut_detail::unused, void (*)()>::invoke() (callback.hpp:89)
...
```
The read of the uninitialized variable nLocalServices is triggered by g_connman->GetLocalServices()
in getnetworkinfo(const JSONRPCRequest& request) (net.cpp:462):
```c++
UniValue getnetworkinfo(const JSONRPCRequest& request)
{
...
if(g_connman)
obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
...
}
```
The reason for the uninitialized nLocalServices is that CConnman::Start(...) is not called
by the tests, and hence the initialization normally performed by CConnman::Start(...) is
not done.
This commit adds a method Init(const Options& connOptions) which is called by both the
constructor and CConnman::Start(...). This method initializes nLocalServices and the other
relevant values from the supplied Options object.
2017-08-02 14:02:36 +02:00
bool CConnman : : Start ( CScheduler & scheduler , const Options & connOptions )
2016-04-18 02:20:34 +02:00
{
[net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest& request)
When running test_bitcoin under Valgrind I found the following issue:
```
$ valgrind src/test/test_bitcoin
...
==10465== Use of uninitialised value of size 8
==10465== at 0x6D09B61: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B1BB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<unsigned long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B36C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D17699: std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x4CAAD7: operator<< (ostream:171)
==10465== by 0x4CAAD7: formatValue<ServiceFlags> (tinyformat.h:345)
==10465== by 0x4CAAD7: void tinyformat::detail::FormatArg::formatImpl<ServiceFlags>(std::ostream&, char const*, char const*, int, void const*) (tinyformat.h:523)
==10465== by 0x1924D4: format (tinyformat.h:510)
==10465== by 0x1924D4: tinyformat::detail::formatImpl(std::ostream&, char const*, tinyformat::detail::FormatArg const*, int) (tinyformat.h:803)
==10465== by 0x553A55: vformat (tinyformat.h:947)
==10465== by 0x553A55: format<ServiceFlags> (tinyformat.h:957)
==10465== by 0x553A55: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > tinyformat::format<ServiceFlags>(char const*, ServiceFlags const&) (tinyformat.h:966)
==10465== by 0x54C952: getnetworkinfo(JSONRPCRequest const&) (net.cpp:462)
==10465== by 0x28EDB5: CallRPC(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (rpc_tests.cpp:31)
==10465== by 0x293947: rpc_tests::rpc_togglenetwork::test_method() (rpc_tests.cpp:88)
==10465== by 0x2950E5: rpc_tests::rpc_togglenetwork_invoker() (rpc_tests.cpp:84)
==10465== by 0x182496: invoke<void (*)()> (callback.hpp:56)
==10465== by 0x182496: boost::unit_test::ut_detail::callback0_impl_t<boost::unit_test::ut_detail::unused, void (*)()>::invoke() (callback.hpp:89)
...
```
The read of the uninitialized variable nLocalServices is triggered by g_connman->GetLocalServices()
in getnetworkinfo(const JSONRPCRequest& request) (net.cpp:462):
```c++
UniValue getnetworkinfo(const JSONRPCRequest& request)
{
...
if(g_connman)
obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
...
}
```
The reason for the uninitialized nLocalServices is that CConnman::Start(...) is not called
by the tests, and hence the initialization normally performed by CConnman::Start(...) is
not done.
This commit adds a method Init(const Options& connOptions) which is called by both the
constructor and CConnman::Start(...). This method initializes nLocalServices and the other
relevant values from the supplied Options object.
2017-08-02 14:02:36 +02:00
Init ( connOptions ) ;
2017-11-21 18:02:57 +01:00
{
LOCK ( cs_totalBytesRecv ) ;
nTotalBytesRecv = 0 ;
}
{
LOCK ( cs_totalBytesSent ) ;
nTotalBytesSent = 0 ;
nMaxOutboundTotalBytesSentInCycle = 0 ;
nMaxOutboundCycleStartTime = 0 ;
}
2016-04-19 03:44:42 +02:00
2017-06-01 12:34:02 +02:00
if ( fListen & & ! InitBinds ( connOptions . vBinds , connOptions . vWhiteBinds ) ) {
if ( clientInterface ) {
clientInterface - > ThreadSafeMessageBox (
_ ( " Failed to listen on any port. Use -listen=0 if you want this. " ) ,
" " , CClientUIInterface : : MSG_ERROR ) ;
}
return false ;
}
2017-05-27 12:00:37 +02:00
for ( const auto & strDest : connOptions . vSeedNodes ) {
AddOneShot ( strDest ) ;
}
2017-02-26 01:41:51 +01:00
if ( clientInterface ) {
clientInterface - > InitMessage ( _ ( " Loading P2P addresses... " ) ) ;
}
2015-07-03 09:46:17 +02:00
// Load addresses from peers.dat
2014-09-18 14:08:43 +02:00
int64_t nStart = GetTimeMillis ( ) ;
{
CAddrDB adb ;
2015-07-03 09:46:17 +02:00
if ( adb . Read ( addrman ) )
LogPrintf ( " Loaded %i addresses from peers.dat %dms \n " , addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
2016-02-02 10:45:11 +01:00
else {
2016-03-16 17:54:30 +01:00
addrman . Clear ( ) ; // Addrman can be in an inconsistent state after failure, reset it
2014-09-18 14:08:43 +02:00
LogPrintf ( " Invalid or missing peers.dat; recreating \n " ) ;
2016-02-02 10:45:11 +01:00
DumpAddresses ( ) ;
}
2014-09-18 14:08:43 +02:00
}
2016-05-26 03:26:46 +02:00
if ( clientInterface )
clientInterface - > InitMessage ( _ ( " Loading banlist... " ) ) ;
2015-07-03 09:46:17 +02:00
// Load addresses from banlist.dat
nStart = GetTimeMillis ( ) ;
2015-06-19 15:27:37 +02:00
CBanDB bandb ;
2015-06-26 21:38:33 +02:00
banmap_t banmap ;
2015-07-03 09:44:49 +02:00
if ( bandb . Read ( banmap ) ) {
2016-04-16 23:43:11 +02:00
SetBanned ( banmap ) ; // thread save setter
SetBannedSetDirty ( false ) ; // no need to write down, just read data
SweepBanned ( ) ; // sweep out unused entries
2015-07-03 09:44:49 +02:00
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " Loaded %d banned node ips/subnets from banlist.dat %dms \n " ,
2015-07-03 09:44:49 +02:00
banmap . size ( ) , GetTimeMillis ( ) - nStart ) ;
2016-02-02 10:45:11 +01:00
} else {
2015-06-19 15:27:37 +02:00
LogPrintf ( " Invalid or missing banlist.dat; recreating \n " ) ;
2016-04-16 23:43:11 +02:00
SetBannedSetDirty ( true ) ; // force write
2016-02-02 10:45:11 +01:00
DumpBanlist ( ) ;
}
2015-06-19 15:27:37 +02:00
2016-07-22 16:01:12 +02:00
uiInterface . InitMessage ( _ ( " Starting network threads... " ) ) ;
2014-09-18 14:08:43 +02:00
fAddressesInitialized = true ;
2017-08-07 07:36:37 +02:00
if ( semOutbound = = nullptr ) {
2012-05-10 18:44:07 +02:00
// initialize semaphore
2017-08-15 07:46:56 +02:00
semOutbound = MakeUnique < CSemaphore > ( std : : min ( ( nMaxOutbound + nMaxFeeler ) , nMaxConnections ) ) ;
2012-05-10 18:44:07 +02:00
}
2017-08-07 07:36:37 +02:00
if ( semAddnode = = nullptr ) {
2016-12-11 05:39:26 +01:00
// initialize semaphore
2017-08-15 07:46:56 +02:00
semAddnode = MakeUnique < CSemaphore > ( nMaxAddnode ) ;
2016-12-11 05:39:26 +01:00
}
2012-05-10 18:44:07 +02:00
2010-08-29 18:58:15 +02:00
//
// Start threads
//
2017-07-06 19:40:09 +02:00
assert ( m_msgproc ) ;
2016-12-27 23:13:31 +01:00
InterruptSocks5 ( false ) ;
2016-12-27 23:12:44 +01:00
interruptNet . reset ( ) ;
flagInterruptMsgProc = false ;
2010-08-29 18:58:15 +02:00
2016-12-31 08:05:26 +01:00
{
std : : unique_lock < std : : mutex > lock ( mutexMsgProc ) ;
fMsgProcWake = false ;
}
2016-12-27 23:11:57 +01:00
// Send and receive from sockets, accept connections
2016-12-27 23:12:44 +01:00
threadSocketHandler = std : : thread ( & TraceThread < std : : function < void ( ) > > , " net " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadSocketHandler , this ) ) ) ;
2010-08-29 18:58:15 +02:00
2017-08-01 21:17:40 +02:00
if ( ! gArgs . GetBoolArg ( " -dnsseed " , true ) )
2013-09-18 12:38:08 +02:00
LogPrintf ( " DNS seeding disabled \n " ) ;
2011-11-21 18:25:00 +01:00
else
2016-12-27 23:12:44 +01:00
threadDNSAddressSeed = std : : thread ( & TraceThread < std : : function < void ( ) > > , " dnsseed " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadDNSAddressSeed , this ) ) ) ;
2010-08-29 18:58:15 +02:00
2011-12-17 01:48:03 +01:00
// Initiate outbound connections from -addnode
2016-12-27 23:12:44 +01:00
threadOpenAddedConnections = std : : thread ( & TraceThread < std : : function < void ( ) > > , " addcon " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadOpenAddedConnections , this ) ) ) ;
2011-12-17 01:48:03 +01:00
2017-06-15 09:39:07 +02:00
if ( connOptions . m_use_addrman_outgoing & & ! connOptions . m_specified_outgoing . empty ( ) ) {
if ( clientInterface ) {
clientInterface - > ThreadSafeMessageBox (
_ ( " Cannot provide specific connections and have addrman find outgoing connections at the same. " ) ,
" " , CClientUIInterface : : MSG_ERROR ) ;
}
return false ;
}
if ( connOptions . m_use_addrman_outgoing | | ! connOptions . m_specified_outgoing . empty ( ) )
threadOpenConnections = std : : thread ( & TraceThread < std : : function < void ( ) > > , " opencon " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadOpenConnections , this , connOptions . m_specified_outgoing ) ) ) ;
2010-08-29 18:58:15 +02:00
// Process messages
2016-12-27 23:12:44 +01:00
threadMessageHandler = std : : thread ( & TraceThread < std : : function < void ( ) > > , " msghand " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadMessageHandler , this ) ) ) ;
2010-08-29 18:58:15 +02:00
2016-04-16 23:43:11 +02:00
// Dump network addresses
2017-01-20 21:36:13 +01:00
scheduler . scheduleEvery ( std : : bind ( & CConnman : : DumpData , this ) , DUMP_ADDRESSES_INTERVAL * 1000 ) ;
2016-04-16 23:43:11 +02:00
2016-04-16 20:47:18 +02:00
return true ;
2010-08-29 18:58:15 +02:00
}
class CNetCleanup
{
public :
2014-05-24 11:14:52 +02:00
CNetCleanup ( ) { }
2010-08-29 18:58:15 +02:00
~ CNetCleanup ( )
{
2011-10-07 17:02:21 +02:00
# ifdef WIN32
2010-08-29 18:58:15 +02:00
// Shutdown Windows Sockets
WSACleanup ( ) ;
# endif
}
}
instance_of_cnetcleanup ;
2012-08-13 05:26:30 +02:00
2016-12-27 23:12:44 +01:00
void CConnman : : Interrupt ( )
2016-04-16 20:47:18 +02:00
{
2016-12-27 23:12:44 +01:00
{
std : : lock_guard < std : : mutex > lock ( mutexMsgProc ) ;
flagInterruptMsgProc = true ;
}
condMsgProc . notify_all ( ) ;
interruptNet ( ) ;
2016-12-27 23:13:31 +01:00
InterruptSocks5 ( true ) ;
2016-12-27 23:12:44 +01:00
2017-03-08 20:55:28 +01:00
if ( semOutbound ) {
for ( int i = 0 ; i < ( nMaxOutbound + nMaxFeeler ) ; i + + ) {
2016-04-16 20:47:18 +02:00
semOutbound - > post ( ) ;
2017-03-08 20:55:28 +01:00
}
}
2017-03-08 20:41:57 +01:00
2017-03-08 20:55:28 +01:00
if ( semAddnode ) {
for ( int i = 0 ; i < nMaxAddnode ; i + + ) {
2017-03-08 20:41:57 +01:00
semAddnode - > post ( ) ;
2017-03-08 20:55:28 +01:00
}
}
2016-12-27 23:12:44 +01:00
}
void CConnman : : Stop ( )
{
if ( threadMessageHandler . joinable ( ) )
threadMessageHandler . join ( ) ;
if ( threadOpenConnections . joinable ( ) )
threadOpenConnections . join ( ) ;
if ( threadOpenAddedConnections . joinable ( ) )
threadOpenAddedConnections . join ( ) ;
if ( threadDNSAddressSeed . joinable ( ) )
threadDNSAddressSeed . join ( ) ;
if ( threadSocketHandler . joinable ( ) )
threadSocketHandler . join ( ) ;
2016-04-16 20:47:18 +02:00
2016-04-16 23:43:11 +02:00
if ( fAddressesInitialized )
{
DumpData ( ) ;
fAddressesInitialized = false ;
}
2016-04-16 20:47:18 +02:00
// Close sockets
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodes )
2017-02-06 20:05:45 +01:00
pnode - > CloseSocketDisconnect ( ) ;
2017-06-02 03:18:57 +02:00
for ( ListenSocket & hListenSocket : vhListenSocket )
2016-04-16 20:47:18 +02:00
if ( hListenSocket . socket ! = INVALID_SOCKET )
if ( ! CloseSocket ( hListenSocket . socket ) )
LogPrintf ( " CloseSocket(hListenSocket) failed with error %s \n " , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
// clean up some globals (to help leak detection)
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodes ) {
2016-05-25 00:59:16 +02:00
DeleteNode ( pnode ) ;
}
2017-06-02 03:18:57 +02:00
for ( CNode * pnode : vNodesDisconnected ) {
2016-05-25 00:59:16 +02:00
DeleteNode ( pnode ) ;
}
2016-04-16 20:47:18 +02:00
vNodes . clear ( ) ;
vNodesDisconnected . clear ( ) ;
vhListenSocket . clear ( ) ;
2017-08-09 16:07:22 +02:00
semOutbound . reset ( ) ;
semAddnode . reset ( ) ;
2016-04-16 20:47:18 +02:00
}
2016-05-25 00:59:16 +02:00
void CConnman : : DeleteNode ( CNode * pnode )
{
assert ( pnode ) ;
bool fUpdateConnectionTime = false ;
2017-07-06 19:40:09 +02:00
m_msgproc - > FinalizeNode ( pnode - > GetId ( ) , fUpdateConnectionTime ) ;
if ( fUpdateConnectionTime ) {
2016-05-25 00:59:16 +02:00
addrman . Connected ( pnode - > addr ) ;
2017-07-06 19:40:09 +02:00
}
2016-05-25 00:59:16 +02:00
delete pnode ;
}
2016-04-16 20:47:18 +02:00
CConnman : : ~ CConnman ( )
{
2016-12-27 23:12:44 +01:00
Interrupt ( ) ;
2016-09-13 20:42:55 +02:00
Stop ( ) ;
2016-04-16 20:47:18 +02:00
}
2012-08-13 05:26:30 +02:00
2016-04-16 23:43:11 +02:00
size_t CConnman : : GetAddressCount ( ) const
{
return addrman . size ( ) ;
}
void CConnman : : SetServices ( const CService & addr , ServiceFlags nServices )
{
addrman . SetServices ( addr , nServices ) ;
}
void CConnman : : MarkAddressGood ( const CAddress & addr )
{
addrman . Good ( addr ) ;
}
void CConnman : : AddNewAddresses ( const std : : vector < CAddress > & vAddr , const CAddress & addrFrom , int64_t nTimePenalty )
{
addrman . Add ( vAddr , addrFrom , nTimePenalty ) ;
}
std : : vector < CAddress > CConnman : : GetAddresses ( )
{
return addrman . GetAddr ( ) ;
}
2016-04-17 00:12:58 +02:00
bool CConnman : : AddNode ( const std : : string & strNode )
{
LOCK ( cs_vAddedNodes ) ;
2017-07-20 11:32:47 +02:00
for ( const std : : string & it : vAddedNodes ) {
if ( strNode = = it ) return false ;
2016-04-17 00:12:58 +02:00
}
vAddedNodes . push_back ( strNode ) ;
return true ;
}
bool CConnman : : RemoveAddedNode ( const std : : string & strNode )
{
LOCK ( cs_vAddedNodes ) ;
for ( std : : vector < std : : string > : : iterator it = vAddedNodes . begin ( ) ; it ! = vAddedNodes . end ( ) ; + + it ) {
if ( strNode = = * it ) {
vAddedNodes . erase ( it ) ;
return true ;
}
}
return false ;
}
2016-04-17 00:30:03 +02:00
size_t CConnman : : GetNodeCount ( NumConnections flags )
{
LOCK ( cs_vNodes ) ;
if ( flags = = CConnman : : CONNECTIONS_ALL ) // Shortcut if we want total
return vNodes . size ( ) ;
int nNum = 0 ;
2017-07-20 11:32:47 +02:00
for ( const auto & pnode : vNodes ) {
if ( flags & ( pnode - > fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT ) ) {
2016-04-17 00:30:03 +02:00
nNum + + ;
2017-07-20 11:32:47 +02:00
}
}
2016-04-17 00:30:03 +02:00
return nNum ;
}
void CConnman : : GetNodeStats ( std : : vector < CNodeStats > & vstats )
{
vstats . clear ( ) ;
LOCK ( cs_vNodes ) ;
vstats . reserve ( vNodes . size ( ) ) ;
2017-07-20 11:32:47 +02:00
for ( CNode * pnode : vNodes ) {
2017-02-06 17:44:38 +01:00
vstats . emplace_back ( ) ;
pnode - > copyStats ( vstats . back ( ) ) ;
2016-04-17 00:30:03 +02:00
}
}
bool CConnman : : DisconnectNode ( const std : : string & strNode )
{
2017-01-24 22:50:27 +01:00
LOCK ( cs_vNodes ) ;
2016-04-17 00:30:03 +02:00
if ( CNode * pnode = FindNode ( strNode ) ) {
pnode - > fDisconnect = true ;
return true ;
}
return false ;
}
bool CConnman : : DisconnectNode ( NodeId id )
{
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes ) {
2017-04-11 18:13:55 +02:00
if ( id = = pnode - > GetId ( ) ) {
2016-04-17 00:30:03 +02:00
pnode - > fDisconnect = true ;
return true ;
}
}
return false ;
}
2016-04-19 03:44:42 +02:00
void CConnman : : RecordBytesRecv ( uint64_t bytes )
2013-08-22 18:09:32 +02:00
{
LOCK ( cs_totalBytesRecv ) ;
nTotalBytesRecv + = bytes ;
}
2016-04-19 03:44:42 +02:00
void CConnman : : RecordBytesSent ( uint64_t bytes )
2013-08-22 18:09:32 +02:00
{
LOCK ( cs_totalBytesSent ) ;
nTotalBytesSent + = bytes ;
2015-09-02 17:03:27 +02:00
uint64_t now = GetTime ( ) ;
if ( nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now )
{
// timeframe expired, reset cycle
nMaxOutboundCycleStartTime = now ;
nMaxOutboundTotalBytesSentInCycle = 0 ;
}
// TODO, exclude whitebind peers
nMaxOutboundTotalBytesSentInCycle + = bytes ;
}
2016-04-19 03:44:42 +02:00
void CConnman : : SetMaxOutboundTarget ( uint64_t limit )
2015-09-02 17:03:27 +02:00
{
LOCK ( cs_totalBytesSent ) ;
nMaxOutboundLimit = limit ;
}
2016-04-19 03:44:42 +02:00
uint64_t CConnman : : GetMaxOutboundTarget ( )
2015-09-02 17:03:27 +02:00
{
LOCK ( cs_totalBytesSent ) ;
return nMaxOutboundLimit ;
}
2016-04-19 03:44:42 +02:00
uint64_t CConnman : : GetMaxOutboundTimeframe ( )
2015-09-02 17:03:27 +02:00
{
LOCK ( cs_totalBytesSent ) ;
return nMaxOutboundTimeframe ;
}
2016-04-19 03:44:42 +02:00
uint64_t CConnman : : GetMaxOutboundTimeLeftInCycle ( )
2015-09-02 17:03:27 +02:00
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
return 0 ;
if ( nMaxOutboundCycleStartTime = = 0 )
return nMaxOutboundTimeframe ;
uint64_t cycleEndTime = nMaxOutboundCycleStartTime + nMaxOutboundTimeframe ;
uint64_t now = GetTime ( ) ;
return ( cycleEndTime < now ) ? 0 : cycleEndTime - GetTime ( ) ;
}
2016-04-19 03:44:42 +02:00
void CConnman : : SetMaxOutboundTimeframe ( uint64_t timeframe )
2015-09-02 17:03:27 +02:00
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundTimeframe ! = timeframe )
{
// reset measure-cycle in case of changing
// the timeframe
nMaxOutboundCycleStartTime = GetTime ( ) ;
}
nMaxOutboundTimeframe = timeframe ;
}
2016-04-19 03:44:42 +02:00
bool CConnman : : OutboundTargetReached ( bool historicalBlockServingLimit )
2015-09-02 17:03:27 +02:00
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
return false ;
if ( historicalBlockServingLimit )
{
2016-01-17 12:03:56 +01:00
// keep a large enough buffer to at least relay each block once
2015-09-02 17:03:27 +02:00
uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle ( ) ;
2016-01-03 18:54:50 +01:00
uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SERIALIZED_SIZE ;
2015-09-02 17:03:27 +02:00
if ( buffer > = nMaxOutboundLimit | | nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit - buffer )
return true ;
}
else if ( nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit )
return true ;
return false ;
}
2016-04-19 03:44:42 +02:00
uint64_t CConnman : : GetOutboundTargetBytesLeft ( )
2015-09-02 17:03:27 +02:00
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
return 0 ;
return ( nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit ) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle ;
2013-08-22 18:09:32 +02:00
}
2016-04-19 03:44:42 +02:00
uint64_t CConnman : : GetTotalBytesRecv ( )
2013-08-22 18:09:32 +02:00
{
LOCK ( cs_totalBytesRecv ) ;
return nTotalBytesRecv ;
}
2016-04-19 03:44:42 +02:00
uint64_t CConnman : : GetTotalBytesSent ( )
2013-08-22 18:09:32 +02:00
{
LOCK ( cs_totalBytesSent ) ;
return nTotalBytesSent ;
}
2013-10-28 07:28:00 +01:00
2016-04-19 06:04:58 +02:00
ServiceFlags CConnman : : GetLocalServices ( ) const
{
return nLocalServices ;
}
2016-05-24 22:42:17 +02:00
void CConnman : : SetBestHeight ( int height )
{
nBestHeight . store ( height , std : : memory_order_release ) ;
}
int CConnman : : GetBestHeight ( ) const
{
return nBestHeight . load ( std : : memory_order_acquire ) ;
}
2016-04-19 06:01:19 +02:00
unsigned int CConnman : : GetReceiveFloodSize ( ) const { return nReceiveFloodSize ; }
2014-08-21 05:17:21 +02:00
2017-05-30 11:59:42 +02:00
CNode : : CNode ( NodeId idIn , ServiceFlags nLocalServicesIn , int nMyStartingHeightIn , SOCKET hSocketIn , const CAddress & addrIn , uint64_t nKeyedNetGroupIn , uint64_t nLocalHostNonceIn , const CAddress & addrBindIn , const std : : string & addrNameIn , bool fInboundIn ) :
2017-02-06 17:42:49 +01:00
nTimeConnected ( GetSystemTimeInSeconds ( ) ) ,
2016-05-25 15:38:32 +02:00
addr ( addrIn ) ,
2017-05-30 11:59:42 +02:00
addrBind ( addrBindIn ) ,
2016-10-31 22:06:15 +01:00
fInbound ( fInboundIn ) ,
2016-09-09 12:48:10 +02:00
nKeyedNetGroup ( nKeyedNetGroupIn ) ,
2015-07-19 21:43:34 +02:00
addrKnown ( 5000 , 0.001 ) ,
2016-10-31 22:06:15 +01:00
filterInventoryKnown ( 50000 , 0.000001 ) ,
2017-04-11 18:11:27 +02:00
id ( idIn ) ,
2016-10-26 21:10:15 +02:00
nLocalHostNonce ( nLocalHostNonceIn ) ,
2016-10-31 22:06:15 +01:00
nLocalServices ( nLocalServicesIn ) ,
2016-09-13 02:00:33 +02:00
nMyStartingHeight ( nMyStartingHeightIn ) ,
nSendVersion ( 0 )
2014-08-21 05:17:21 +02:00
{
2016-06-08 19:12:22 +02:00
nServices = NODE_NONE ;
2014-08-21 05:17:21 +02:00
hSocket = hSocketIn ;
nRecvVersion = INIT_PROTO_VERSION ;
nLastSend = 0 ;
nLastRecv = 0 ;
nSendBytes = 0 ;
nRecvBytes = 0 ;
2014-12-15 11:06:15 +01:00
nTimeOffset = 0 ;
2014-08-21 05:17:21 +02:00
addrName = addrNameIn = = " " ? addr . ToStringIPPort ( ) : addrNameIn ;
nVersion = 0 ;
strSubVer = " " ;
fWhitelisted = false ;
fOneShot = false ;
2017-10-05 17:49:16 +02:00
m_manual_connection = false ;
2014-08-21 05:17:21 +02:00
fClient = false ; // set by version message
2016-06-17 06:10:07 +02:00
fFeeler = false ;
2014-08-21 05:17:21 +02:00
fSuccessfullyConnected = false ;
fDisconnect = false ;
nRefCount = 0 ;
nSendSize = 0 ;
nSendOffset = 0 ;
2014-12-15 09:11:16 +01:00
hashContinue = uint256 ( ) ;
2014-08-21 05:17:21 +02:00
nStartingHeight = - 1 ;
2015-11-29 10:52:51 +01:00
filterInventoryKnown . reset ( ) ;
2016-04-08 16:26:41 +02:00
fSendMempool = false ;
2014-08-21 05:17:21 +02:00
fGetAddr = false ;
2015-04-08 20:20:00 +02:00
nNextLocalAddrSend = 0 ;
nNextAddrSend = 0 ;
nNextInvSend = 0 ;
2014-08-21 05:17:21 +02:00
fRelayTxes = false ;
2016-04-11 03:09:34 +02:00
fSentAddr = false ;
2017-08-15 07:46:56 +02:00
pfilter = MakeUnique < CBloomFilter > ( ) ;
2016-05-20 18:19:26 +02:00
timeLastMempoolReq = 0 ;
2016-05-22 07:55:15 +02:00
nLastBlockTime = 0 ;
nLastTXTime = 0 ;
2014-08-21 05:17:21 +02:00
nPingNonceSent = 0 ;
nPingUsecStart = 0 ;
nPingUsecTime = 0 ;
fPingQueued = false ;
2015-09-04 15:43:21 +02:00
nMinPingUsecTime = std : : numeric_limits < int64_t > : : max ( ) ;
2016-02-12 21:57:15 +01:00
minFeeFilter = 0 ;
lastSentFeeFilter = 0 ;
nextSendTimeFeeFilter = 0 ;
2016-12-31 08:05:30 +01:00
fPauseRecv = false ;
2016-12-31 08:05:32 +01:00
fPauseSend = false ;
2016-12-31 08:05:30 +01:00
nProcessQueueSize = 0 ;
2016-04-18 02:21:58 +02:00
2017-06-02 03:18:57 +02:00
for ( const std : : string & msg : getAllNetMessageTypes ( ) )
2015-12-07 15:31:32 +01:00
mapRecvBytesPerMsgCmd [ msg ] = 0 ;
2015-08-25 16:30:31 +02:00
mapRecvBytesPerMsgCmd [ NET_MESSAGE_COMMAND_OTHER ] = 0 ;
2014-08-21 05:17:21 +02:00
2016-12-25 21:19:40 +01:00
if ( fLogIPs ) {
LogPrint ( BCLog : : NET , " Added connection to %s peer=%d \n " , addrName , id ) ;
} else {
LogPrint ( BCLog : : NET , " Added connection peer=%d \n " , id ) ;
}
2014-08-21 05:17:21 +02:00
}
CNode : : ~ CNode ( )
{
CloseSocket ( hSocket ) ;
}
void CNode : : AskFor ( const CInv & inv )
{
2015-11-23 02:54:23 +01:00
if ( mapAskFor . size ( ) > MAPASKFOR_MAX_SZ | | setAskFor . size ( ) > SETASKFOR_MAX_SZ )
2014-09-09 09:18:05 +02:00
return ;
2015-11-23 02:54:23 +01:00
// a peer may not have multiple non-responded queue positions for a single inv item
2014-07-16 23:31:41 +02:00
if ( ! setAskFor . insert ( inv . hash ) . second )
return ;
2014-08-21 05:17:21 +02:00
// We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent
int64_t nRequestTime ;
2016-04-11 18:52:29 +02:00
limitedmap < uint256 , int64_t > : : const_iterator it = mapAlreadyAskedFor . find ( inv . hash ) ;
2014-08-21 05:17:21 +02:00
if ( it ! = mapAlreadyAskedFor . end ( ) )
nRequestTime = it - > second ;
else
nRequestTime = 0 ;
2016-12-25 21:19:40 +01:00
LogPrint ( BCLog : : NET , " askfor %s %d (%s) peer=%d \n " , inv . ToString ( ) , nRequestTime , DateTimeStrFormat ( " %H:%M:%S " , nRequestTime / 1000000 ) , id ) ;
2014-08-21 05:17:21 +02:00
// Make sure not to reuse time indexes to keep things in the same order
int64_t nNow = GetTimeMicros ( ) - 1000000 ;
static int64_t nLastTime ;
+ + nLastTime ;
nNow = std : : max ( nNow , nLastTime ) ;
nLastTime = nNow ;
// Each retry is 2 minutes after the last
nRequestTime = std : : max ( nRequestTime + 2 * 60 * 1000000 , nNow ) ;
if ( it ! = mapAlreadyAskedFor . end ( ) )
mapAlreadyAskedFor . update ( it , nRequestTime ) ;
else
2016-04-11 18:52:29 +02:00
mapAlreadyAskedFor . insert ( std : : make_pair ( inv . hash , nRequestTime ) ) ;
2014-08-21 05:17:21 +02:00
mapAskFor . insert ( std : : make_pair ( nRequestTime , inv ) ) ;
}
2017-01-21 02:34:57 +01:00
bool CConnman : : NodeFullyConnected ( const CNode * pnode )
{
return pnode & & pnode - > fSuccessfullyConnected & & ! pnode - > fDisconnect ;
}
2016-11-11 02:17:30 +01:00
void CConnman : : PushMessage ( CNode * pnode , CSerializedNetMsg & & msg )
2016-09-13 02:00:33 +02:00
{
2016-11-11 02:17:30 +01:00
size_t nMessageSize = msg . data . size ( ) ;
size_t nTotalSize = nMessageSize + CMessageHeader : : HEADER_SIZE ;
2017-04-11 18:13:55 +02:00
LogPrint ( BCLog : : NET , " sending %s (%d bytes) peer=%d \n " , SanitizeString ( msg . command . c_str ( ) ) , nMessageSize , pnode - > GetId ( ) ) ;
2016-09-13 02:00:33 +02:00
2016-11-11 02:17:30 +01:00
std : : vector < unsigned char > serializedHeader ;
serializedHeader . reserve ( CMessageHeader : : HEADER_SIZE ) ;
uint256 hash = Hash ( msg . data . data ( ) , msg . data . data ( ) + nMessageSize ) ;
CMessageHeader hdr ( Params ( ) . MessageStart ( ) , msg . command . c_str ( ) , nMessageSize ) ;
memcpy ( hdr . pchChecksum , hash . begin ( ) , CMessageHeader : : CHECKSUM_SIZE ) ;
2016-09-13 02:00:33 +02:00
2016-11-11 02:17:30 +01:00
CVectorWriter { SER_NETWORK , INIT_PROTO_VERSION , serializedHeader , 0 , hdr } ;
2016-09-13 02:00:33 +02:00
size_t nBytesSent = 0 ;
{
LOCK ( pnode - > cs_vSend ) ;
bool optimisticSend ( pnode - > vSendMsg . empty ( ) ) ;
//log total amount of bytes per command
2016-11-11 02:17:30 +01:00
pnode - > mapSendBytesPerMsgCmd [ msg . command ] + = nTotalSize ;
pnode - > nSendSize + = nTotalSize ;
2016-12-31 08:05:32 +01:00
if ( pnode - > nSendSize > nSendBufferMaxSize )
pnode - > fPauseSend = true ;
2016-11-11 02:17:30 +01:00
pnode - > vSendMsg . push_back ( std : : move ( serializedHeader ) ) ;
if ( nMessageSize )
pnode - > vSendMsg . push_back ( std : : move ( msg . data ) ) ;
2016-09-13 02:00:33 +02:00
// If write queue empty, attempt "optimistic write"
if ( optimisticSend = = true )
nBytesSent = SocketSendData ( pnode ) ;
}
if ( nBytesSent )
RecordBytesSent ( nBytesSent ) ;
}
2016-04-17 01:13:12 +02:00
bool CConnman : : ForNode ( NodeId id , std : : function < bool ( CNode * pnode ) > func )
{
CNode * found = nullptr ;
LOCK ( cs_vNodes ) ;
for ( auto & & pnode : vNodes ) {
2017-04-11 18:13:55 +02:00
if ( pnode - > GetId ( ) = = id ) {
2016-04-17 01:13:12 +02:00
found = pnode ;
break ;
}
}
2017-01-21 02:34:57 +01:00
return found ! = nullptr & & NodeFullyConnected ( found ) & & func ( found ) ;
2016-04-17 01:13:12 +02:00
}
2015-04-08 20:20:00 +02:00
int64_t PoissonNextSend ( int64_t nNow , int average_interval_seconds ) {
return nNow + ( int64_t ) ( log1p ( GetRand ( 1ULL < < 48 ) * - 0.0000000000000035527136788 /* -1/2^48 */ ) * average_interval_seconds * - 1000000.0 + 0.5 ) ;
}
2016-05-25 15:38:32 +02:00
2017-01-24 02:32:52 +01:00
CSipHasher CConnman : : GetDeterministicRandomizer ( uint64_t id ) const
2016-05-25 15:38:32 +02:00
{
2016-09-09 12:48:10 +02:00
return CSipHasher ( nSeed0 , nSeed1 ) . Write ( id ) ;
}
2016-05-25 15:38:32 +02:00
2017-01-24 02:32:52 +01:00
uint64_t CConnman : : CalculateKeyedNetGroup ( const CAddress & ad ) const
2016-09-09 12:48:10 +02:00
{
2016-05-25 15:38:32 +02:00
std : : vector < unsigned char > vchNetGroup ( ad . GetGroup ( ) ) ;
2017-02-19 19:18:04 +01:00
return GetDeterministicRandomizer ( RANDOMIZER_ID_NETGROUP ) . Write ( vchNetGroup . data ( ) , vchNetGroup . size ( ) ) . Finalize ( ) ;
2016-05-25 15:38:32 +02:00
}