2010-08-29 12:58:15 -04:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2020-01-14 16:17:38 -03:00
// Copyright (c) 2009-2020 The Bitcoin Core developers
2014-12-13 01:09:33 -03:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 10:02:28 -04:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2010-08-29 12:58:15 -04:00
2013-05-27 19:55:01 -04:00
# if defined(HAVE_CONFIG_H)
2017-11-09 21:57:53 -03:00
# include <config/bitcoin-config.h>
2013-05-27 19:55:01 -04:00
# endif
2017-11-09 21:57:53 -03:00
# include <net.h>
2017-10-05 17:40:43 -03:00
# include <banman.h>
2017-11-09 21:57:53 -03:00
# include <clientversion.h>
# include <consensus/consensus.h>
# include <crypto/sha256.h>
2019-06-20 05:37:51 -04:00
# include <net_permissions.h>
2020-06-19 18:14:17 -04:00
# include <netbase.h>
# include <node/ui_interface.h>
2020-09-18 09:47:08 -03:00
# include <optional.h>
2020-05-10 09:47:32 -04:00
# include <protocol.h>
2019-11-23 13:42:23 -03:00
# include <random.h>
2017-11-09 21:57:53 -03:00
# include <scheduler.h>
2018-10-22 19:51:11 -03:00
# include <util/strencodings.h>
2019-06-17 03:56:52 -04:00
# include <util/translation.h>
2013-04-13 02:13:08 -03:00
2011-10-07 12:02:21 -03:00
# ifdef WIN32
2011-07-01 21:59:37 -04:00
# include <string.h>
2013-04-13 02:13:08 -03:00
# else
2013-07-17 04:51:40 -04:00
# include <fcntl.h>
# endif
2018-09-26 22:54:52 -03:00
# ifdef USE_POLL
# include <poll.h>
# endif
2011-03-26 09:01:27 -03:00
# ifdef USE_UPNP
# include <miniupnpc/miniupnpc.h>
# include <miniupnpc/upnpcommands.h>
# include <miniupnpc/upnperrors.h>
2019-05-06 15:17:31 -04:00
// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
static_assert ( MINIUPNPC_API_VERSION > = 10 , " miniUPnPc API version >= 10 assumed " ) ;
2011-03-26 09:01:27 -03:00
# endif
2020-09-30 13:07:36 -03:00
# include <algorithm>
2019-12-29 18:04:02 -03:00
# include <cstdint>
2018-09-26 22:54:52 -03:00
# include <unordered_map>
2014-01-30 06:55:55 -03:00
2015-04-08 15:20:00 -03:00
# include <math.h>
2020-09-12 12:05:54 -03:00
/** Maximum number of block-relay-only anchor connections */
static constexpr size_t MAX_BLOCK_RELAY_ONLY_ANCHORS = 2 ;
static_assert ( MAX_BLOCK_RELAY_ONLY_ANCHORS < = static_cast < size_t > ( MAX_BLOCK_RELAY_ONLY_CONNECTIONS ) , " MAX_BLOCK_RELAY_ONLY_ANCHORS must not exceed MAX_BLOCK_RELAY_ONLY_CONNECTIONS. " ) ;
/** Anchor IP address database file name */
const char * const ANCHORS_DATABASE_FILENAME = " anchors.dat " ;
2020-03-06 20:06:50 -03:00
// How often to dump addresses to peers.dat
static constexpr std : : chrono : : minutes DUMP_PEERS_INTERVAL { 15 } ;
2017-10-05 13:46:54 -03:00
2019-03-07 20:30:59 -03:00
/** Number of DNS seeds to query when the number of connections is low. */
static constexpr int DNSSEEDS_TO_QUERY_AT_ONCE = 3 ;
2020-02-11 00:20:21 -03:00
/** How long to delay before querying DNS seeds
2020-05-27 20:07:49 -04:00
*
* If we have more than THRESHOLD entries in addrman , then it ' s likely
* that we got those addresses from having previously connected to the P2P
* network , and that we ' ll be able to successfully reconnect to the P2P
* network via contacting one of them . So if that ' s the case , spend a
* little longer trying to connect to known peers before querying the
* DNS seeds .
2020-02-11 00:20:21 -03:00
*/
2020-05-27 20:07:49 -04:00
static constexpr std : : chrono : : seconds DNSSEEDS_DELAY_FEW_PEERS { 11 } ;
static constexpr std : : chrono : : minutes DNSSEEDS_DELAY_MANY_PEERS { 5 } ;
static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000 ; // "many" vs "few" peers
2020-02-11 00:20:21 -03:00
2020-10-24 05:33:26 -03:00
/** The default timeframe for -maxuploadtarget. 1 day. */
2020-10-24 08:13:42 -03:00
static constexpr std : : chrono : : seconds MAX_UPLOAD_TIMEFRAME { 60 * 60 * 24 } ;
2020-10-24 05:33:26 -03:00
2016-06-17 00:10:07 -04:00
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
# define FEELER_SLEEP_WINDOW 1
2018-03-11 16:19:26 -03:00
// MSG_NOSIGNAL is not available on some platforms, if it doesn't exist define it as 0
# if !defined(MSG_NOSIGNAL)
2013-05-27 19:55:01 -04:00
# define MSG_NOSIGNAL 0
# endif
2013-06-23 18:23:28 -04:00
2017-03-05 06:32:00 -03:00
// MSG_DONTWAIT is not available on some platforms, if it doesn't exist define it as 0
2018-03-11 16:19:26 -03:00
# if !defined(MSG_DONTWAIT)
2017-03-05 06:32:00 -03:00
# define MSG_DONTWAIT 0
# endif
2017-06-01 06:34:02 -04:00
/** Used to pass flags to the Bind() function */
enum BindFlags {
BF_NONE = 0 ,
BF_EXPLICIT = ( 1U < < 0 ) ,
BF_REPORT_ERROR = ( 1U < < 1 ) ,
2020-09-29 12:03:43 -03:00
/**
* Do not call AddLocal ( ) for our special addresses , e . g . , for incoming
* Tor connections , to prevent gossiping them over the network .
*/
BF_DONT_ADVERTISE = ( 1U < < 2 ) ,
2017-06-01 06:34:02 -04:00
} ;
2018-10-29 17:30:30 -03:00
// The set of sockets cannot be modified while waiting
// The sleep time needs to be small to avoid new sockets stalling
static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50 ;
2019-01-02 09:13:50 -03:00
const std : : string NET_MESSAGE_COMMAND_OTHER = " *other* " ;
2015-08-25 11:30:31 -03:00
2016-09-09 07:48:10 -03:00
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL ; // SHA256("netgroup")[0:8]
2016-10-26 16:10:15 -03:00
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL ; // SHA256("localhostnonce")[0:8]
2020-08-11 05:41:26 -04:00
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL ; // SHA256("addrcache")[0:8]
2010-08-29 12:58:15 -04:00
//
// Global state variables
//
2012-05-24 13:02:21 -04:00
bool fDiscover = true ;
2014-05-29 06:33:17 -04:00
bool fListen = true ;
2020-01-07 13:14:15 -03:00
RecursiveMutex cs_mapLocalHost ;
2018-10-08 10:34:39 -03:00
std : : map < CNetAddr , LocalServiceInfo > mapLocalHost GUARDED_BY ( cs_mapLocalHost ) ;
static bool vfLimited [ NET_MAX ] GUARDED_BY ( cs_mapLocalHost ) = { } ;
2015-07-31 13:05:42 -03:00
std : : string strSubVersion ;
2010-08-29 12:58:15 -04:00
2020-07-17 17:56:34 -04:00
void CConnman : : AddAddrFetch ( const std : : string & strDest )
2012-04-23 21:15:00 -03:00
{
2020-07-17 17:56:34 -04:00
LOCK ( m_addr_fetches_mutex ) ;
m_addr_fetches . push_back ( strDest ) ;
2012-04-23 21:15:00 -03:00
}
2019-12-29 18:04:02 -03:00
uint16_t GetListenPort ( )
2011-04-21 11:45:08 -03:00
{
2019-12-29 18:04:02 -03:00
return ( uint16_t ) ( gArgs . GetArg ( " -port " , Params ( ) . GetDefaultPort ( ) ) ) ;
2011-04-21 11:45:08 -03:00
}
2010-08-29 12:58:15 -04:00
2012-02-12 09:45:24 -03:00
// find 'best' local address for a particular peer
2012-05-10 14:35:13 -04:00
bool GetLocal ( CService & addr , const CNetAddr * paddrPeer )
2012-02-12 09:45:24 -03:00
{
2014-05-29 06:33:17 -04:00
if ( ! fListen )
2012-02-12 09:45:24 -03:00
return false ;
2010-08-29 12:58:15 -04:00
2012-05-12 18:41:24 -04:00
int nBestScore = - 1 ;
2012-02-12 09:45:24 -03:00
int nBestReachability = - 1 ;
{
LOCK ( cs_mapLocalHost ) ;
2017-06-04 16:02:43 -04:00
for ( const auto & entry : mapLocalHost )
2012-02-12 09:45:24 -03:00
{
2017-06-04 16:02:43 -04:00
int nScore = entry . second . nScore ;
int nReachability = entry . first . GetReachabilityFrom ( paddrPeer ) ;
2012-05-12 18:41:24 -04:00
if ( nReachability > nBestReachability | | ( nReachability = = nBestReachability & & nScore > nBestScore ) )
2012-02-12 09:45:24 -03:00
{
2017-06-04 16:02:43 -04:00
addr = CService ( entry . first , entry . second . nPort ) ;
2012-02-12 09:45:24 -03:00
nBestReachability = nReachability ;
2012-05-12 18:41:24 -04:00
nBestScore = nScore ;
2012-02-12 09:45:24 -03:00
}
}
}
2012-05-12 18:41:24 -04:00
return nBestScore > = 0 ;
2012-02-12 09:45:24 -03:00
}
2010-08-29 12:58:15 -04:00
2018-04-14 20:19:40 -03:00
//! Convert the pnSeed6 array into usable address objects.
2015-01-24 01:40:50 -03:00
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 ( ) ) ;
2018-10-31 19:02:24 -03:00
FastRandomContext rng ;
2017-07-20 05:32:47 -04:00
for ( const auto & seed_in : vSeedsIn ) {
2015-01-24 01:40:50 -03:00
struct in6_addr ip ;
2017-07-20 05:32:47 -04:00
memcpy ( & ip , seed_in . addr , sizeof ( ip ) ) ;
2017-10-19 18:32:33 -03:00
CAddress addr ( CService ( ip , seed_in . port ) , GetDesirableServiceFlags ( NODE_NONE ) ) ;
2018-10-31 19:02:24 -03:00
addr . nTime = GetTime ( ) - rng . randrange ( nOneWeek ) - nOneWeek ;
2015-01-24 01:40:50 -03:00
vSeedsOut . push_back ( addr ) ;
}
return vSeedsOut ;
}
2012-02-12 09:45:24 -03:00
// get best local address for a particular peer as a CAddress
2014-07-21 02:32:25 -04: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 01:04:58 -03:00
CAddress GetLocalAddress ( const CNetAddr * paddrPeer , ServiceFlags nLocalServices )
2012-02-12 09:45:24 -03:00
{
2017-05-18 16:57:53 -04:00
CAddress ret ( CService ( CNetAddr ( ) , GetListenPort ( ) ) , nLocalServices ) ;
2012-05-10 14:35:13 -04:00
CService addr ;
2012-02-12 09:45:24 -03:00
if ( GetLocal ( addr , paddrPeer ) )
{
2016-05-25 11:18:37 -04:00
ret = CAddress ( addr , nLocalServices ) ;
2012-02-12 09:45:24 -03:00
}
2014-07-21 02:32:25 -04:00
ret . nTime = GetAdjustedTime ( ) ;
2012-02-12 09:45:24 -03:00
return ret ;
}
2010-08-29 12:58:15 -04:00
2018-05-02 12:14:48 -03:00
static int GetnScore ( const CService & addr )
2012-02-12 09:45:24 -03:00
{
2014-07-21 02:32:25 -04:00
LOCK ( cs_mapLocalHost ) ;
2019-02-04 15:12:20 -03:00
if ( mapLocalHost . count ( addr ) = = 0 ) return 0 ;
2014-07-21 02:32:25 -04:00
return mapLocalHost [ addr ] . nScore ;
}
// Is our peer's addrLocal potentially useful as an external IP source?
bool IsPeerAddrLocalGood ( CNode * pnode )
{
2017-02-06 14:18:51 -03:00
CService addrLocal = pnode - > GetAddrLocal ( ) ;
return fDiscover & & pnode - > addr . IsRoutable ( ) & & addrLocal . IsRoutable ( ) & &
2019-01-09 21:41:37 -03:00
IsReachable ( addrLocal . GetNetwork ( ) ) ;
2014-07-21 02:32:25 -04:00
}
// pushes our own address to a peer
2016-02-12 15:35:32 -03:00
void AdvertiseLocal ( CNode * pnode )
2014-07-21 02:32:25 -04:00
{
if ( fListen & & pnode - > fSuccessfullyConnected )
2012-02-12 09:45:24 -03:00
{
2016-04-19 01:04:58 -03:00
CAddress addrLocal = GetLocalAddress ( & pnode - > addr , pnode - > GetLocalServices ( ) ) ;
2017-05-11 09:59:57 -03:00
if ( gArgs . GetBoolArg ( " -addrmantest " , false ) ) {
// use IPv4 loopback during addrmantest
addrLocal = CAddress ( CService ( LookupNumeric ( " 127.0.0.1 " , GetListenPort ( ) ) ) , pnode - > GetLocalServices ( ) ) ;
}
2014-07-21 02:32:25 -04: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.
2018-10-31 19:02:24 -03:00
FastRandomContext rng ;
2014-07-21 02:32:25 -04:00
if ( IsPeerAddrLocalGood ( pnode ) & & ( ! addrLocal . IsRoutable ( ) | |
2018-10-31 19:02:24 -03:00
rng . randbits ( ( GetnScore ( addrLocal ) > LOCAL_MANUAL ) ? 3 : 1 ) = = 0 ) )
2012-02-12 09:45:24 -03:00
{
2017-02-06 14:18:51 -03:00
addrLocal . SetIP ( pnode - > GetAddrLocal ( ) ) ;
2014-07-21 02:32:25 -04:00
}
2017-05-11 09:59:57 -03:00
if ( addrLocal . IsRoutable ( ) | | gArgs . GetBoolArg ( " -addrmantest " , false ) )
2014-07-21 02:32:25 -04:00
{
2016-12-25 17:19:40 -03:00
LogPrint ( BCLog : : NET , " AdvertiseLocal: advertising address %s \n " , addrLocal . ToString ( ) ) ;
2018-10-31 19:02:24 -03:00
pnode - > PushAddress ( addrLocal , rng ) ;
2012-02-12 09:45:24 -03:00
}
}
}
// learn a new local address
2012-05-10 14:35:13 -04:00
bool AddLocal ( const CService & addr , int nScore )
2012-02-12 09:45:24 -03:00
{
if ( ! addr . IsRoutable ( ) )
return false ;
2012-05-24 13:02:21 -04:00
if ( ! fDiscover & & nScore < LOCAL_MANUAL )
2012-05-13 08:11:53 -04:00
return false ;
2019-01-09 21:41:37 -03:00
if ( ! IsReachable ( addr ) )
2012-05-13 09:11:51 -04:00
return false ;
2014-01-16 12:15:27 -03:00
LogPrintf ( " AddLocal(%s,%i) \n " , addr . ToString ( ) , nScore ) ;
2012-02-12 09:45:24 -03:00
{
LOCK ( cs_mapLocalHost ) ;
2012-05-12 18:41:24 -04:00
bool fAlready = mapLocalHost . count ( addr ) > 0 ;
LocalServiceInfo & info = mapLocalHost [ addr ] ;
if ( ! fAlready | | nScore > = info . nScore ) {
2012-08-28 20:33:25 -04:00
info . nScore = nScore + ( fAlready ? 1 : 0 ) ;
info . nPort = addr . GetPort ( ) ;
2012-05-12 18:41:24 -04:00
}
2012-02-12 09:45:24 -03:00
}
return true ;
}
2012-05-12 19:26:14 -04:00
bool AddLocal ( const CNetAddr & addr , int nScore )
2012-05-10 14:35:13 -04:00
{
2012-05-12 19:26:14 -04:00
return AddLocal ( CService ( addr , GetListenPort ( ) ) , nScore ) ;
2012-05-10 14:35:13 -04:00
}
2018-07-27 02:22:42 -04:00
void RemoveLocal ( const CService & addr )
2015-09-08 12:48:45 -03:00
{
LOCK ( cs_mapLocalHost ) ;
LogPrintf ( " RemoveLocal(%s) \n " , addr . ToString ( ) ) ;
mapLocalHost . erase ( addr ) ;
}
2019-01-09 21:41:37 -03:00
void SetReachable ( enum Network net , bool reachable )
2012-05-04 10:46:22 -04:00
{
2017-05-23 20:04:38 -04:00
if ( net = = NET_UNROUTABLE | | net = = NET_INTERNAL )
2012-05-14 11:15:58 -04:00
return ;
2012-05-04 10:46:22 -04:00
LOCK ( cs_mapLocalHost ) ;
2019-01-09 21:41:37 -03:00
vfLimited [ net ] = ! reachable ;
2012-05-04 10:46:22 -04:00
}
2019-01-09 21:41:37 -03:00
bool IsReachable ( enum Network net )
2012-05-04 10:46:22 -04:00
{
LOCK ( cs_mapLocalHost ) ;
2019-01-09 21:41:37 -03:00
return ! vfLimited [ net ] ;
2012-05-14 11:15:58 -04:00
}
2019-01-09 21:41:37 -03:00
bool IsReachable ( const CNetAddr & addr )
2012-05-14 11:15:58 -04:00
{
2019-01-09 21:41:37 -03:00
return IsReachable ( addr . GetNetwork ( ) ) ;
2012-05-04 10:46:22 -04:00
}
/** vote for a local address */
2012-05-10 14:35:13 -04:00
bool SeenLocal ( const CService & addr )
2012-02-12 09:45:24 -03:00
{
{
LOCK ( cs_mapLocalHost ) ;
if ( mapLocalHost . count ( addr ) = = 0 )
return false ;
2012-05-12 18:41:24 -04:00
mapLocalHost [ addr ] . nScore + + ;
2012-02-12 09:45:24 -03:00
}
return true ;
}
2014-07-21 02:32:25 -04:00
2012-05-04 10:46:22 -04:00
/** check whether a given address is potentially local */
2012-05-10 14:35:13 -04:00
bool IsLocal ( const CService & addr )
2012-02-12 09:45:24 -03:00
{
LOCK ( cs_mapLocalHost ) ;
return mapLocalHost . count ( addr ) > 0 ;
}
2010-08-29 12:58:15 -04:00
2016-04-16 20:13:12 -03:00
CNode * CConnman : : FindNode ( const CNetAddr & ip )
2010-08-29 12:58:15 -04:00
{
2013-04-04 06:30:55 -03:00
LOCK ( cs_vNodes ) ;
2017-07-20 05:32:47 -04:00
for ( CNode * pnode : vNodes ) {
2017-06-01 10:13:35 -04:00
if ( static_cast < CNetAddr > ( pnode - > addr ) = = ip ) {
2017-07-20 05:32:47 -04:00
return pnode ;
}
}
2017-08-07 01:36:37 -04:00
return nullptr ;
2010-08-29 12:58:15 -04:00
}
2016-04-16 20:13:12 -03:00
CNode * CConnman : : FindNode ( const CSubNet & subNet )
2015-05-25 15:03:51 -03:00
{
LOCK ( cs_vNodes ) ;
2017-07-20 05:32:47 -04:00
for ( CNode * pnode : vNodes ) {
2017-06-01 10:13:35 -04:00
if ( subNet . Match ( static_cast < CNetAddr > ( pnode - > addr ) ) ) {
2017-07-20 05:32:47 -04:00
return pnode ;
}
}
2017-08-07 01:36:37 -04:00
return nullptr ;
2015-05-25 15:03:51 -03:00
}
2016-04-16 20:13:12 -03:00
CNode * CConnman : : FindNode ( const std : : string & addrName )
2012-04-19 12:38:03 -03:00
{
LOCK ( cs_vNodes ) ;
2017-06-01 21:18:57 -04:00
for ( CNode * pnode : vNodes ) {
2017-02-06 14:04:34 -03:00
if ( pnode - > GetAddrName ( ) = = addrName ) {
2017-07-20 05:32:47 -04:00
return pnode ;
2017-02-06 14:04:34 -03:00
}
}
2017-08-07 01:36:37 -04:00
return nullptr ;
2012-04-19 12:38:03 -03:00
}
2016-04-16 20:13:12 -03:00
CNode * CConnman : : FindNode ( const CService & addr )
2010-08-29 12:58:15 -04:00
{
2013-04-04 06:30:55 -03:00
LOCK ( cs_vNodes ) ;
2017-07-20 05:32:47 -04:00
for ( CNode * pnode : vNodes ) {
2017-06-01 10:13:35 -04:00
if ( static_cast < CService > ( pnode - > addr ) = = addr ) {
2017-07-20 05:32:47 -04:00
return pnode ;
}
}
2017-08-07 01:36:37 -04:00
return nullptr ;
2010-08-29 12:58:15 -04:00
}
2020-10-16 12:10:17 -03:00
bool CConnman : : AlreadyConnectedToAddress ( const CAddress & addr )
{
return FindNode ( static_cast < CNetAddr > ( addr ) ) | | FindNode ( addr . ToStringIPPort ( ) ) ;
}
2016-04-17 21:21:58 -03:00
bool CConnman : : CheckIncomingNonce ( uint64_t nonce )
{
LOCK ( cs_vNodes ) ;
2018-06-18 01:58:28 -04:00
for ( const CNode * pnode : vNodes ) {
2020-07-28 16:39:38 -04:00
if ( ! pnode - > fSuccessfullyConnected & & ! pnode - > IsInboundConn ( ) & & pnode - > GetLocalNonce ( ) = = nonce )
2016-04-17 21:21:58 -03:00
return false ;
}
return true ;
}
2017-05-30 05:59:42 -04: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 ;
}
2020-04-29 20:33:06 -04:00
CNode * CConnman : : ConnectNode ( CAddress addrConnect , const char * pszDest , bool fCountFailure , ConnectionType conn_type )
2010-08-29 12:58:15 -04:00
{
2020-04-29 17:55:59 -04:00
assert ( conn_type ! = ConnectionType : : INBOUND ) ;
2017-08-07 01:36:37 -04:00
if ( pszDest = = nullptr ) {
2012-02-12 09:45:24 -03:00
if ( IsLocal ( addrConnect ) )
2017-08-07 01:36:37 -04:00
return nullptr ;
2010-08-29 12:58:15 -04:00
2012-04-19 12:38:03 -03:00
// Look for an existing connection
2017-06-01 10:13:35 -04:00
CNode * pnode = FindNode ( static_cast < CService > ( addrConnect ) ) ;
2012-04-19 12:38:03 -03:00
if ( pnode )
{
2017-01-24 18:51:22 -03:00
LogPrintf ( " Failed to open new connection, already connected \n " ) ;
2017-08-07 01:36:37 -04:00
return nullptr ;
2012-04-19 12:38:03 -03:00
}
2010-08-29 12:58:15 -04:00
}
/// debug print
2016-12-25 17:19:40 -03:00
LogPrint ( BCLog : : NET , " trying connection %s lastseen=%.1fhrs \n " ,
2014-01-16 12:15:27 -03:00
pszDest ? pszDest : addrConnect . ToString ( ) ,
2014-05-24 05:14:52 -04:00
pszDest ? 0.0 : ( double ) ( GetAdjustedTime ( ) - addrConnect . nTime ) / 3600.0 ) ;
2010-08-29 12:58:15 -04:00
2017-06-22 14:01:04 -04: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 ( ) ) {
2018-05-02 09:50:38 -03:00
LogPrint ( BCLog : : NET , " Resolver returned invalid address %s for %s \n " , addrConnect . ToString ( ) , pszDest ) ;
2017-06-22 14:01:04 -04:00
return nullptr ;
}
2016-05-28 10:22:02 -04: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 18:50:27 -03:00
LOCK ( cs_vNodes ) ;
2017-06-01 10:13:35 -04:00
CNode * pnode = FindNode ( static_cast < CService > ( addrConnect ) ) ;
2016-05-28 10:22:02 -04:00
if ( pnode )
{
2017-02-06 14:04:34 -03:00
pnode - > MaybeSetAddrName ( std : : string ( pszDest ) ) ;
2017-01-24 18:51:22 -03:00
LogPrintf ( " Failed to open new connection, already connected \n " ) ;
2017-08-07 01:36:37 -04:00
return nullptr ;
2016-05-28 10:22:02 -04:00
}
}
2017-06-22 14:01:04 -04:00
}
2016-05-28 10:22:02 -04:00
2017-06-22 14:01:04 -04:00
// Connect
bool connected = false ;
2018-02-01 12:29:15 -03:00
SOCKET hSocket = INVALID_SOCKET ;
2017-06-22 14:01:04 -04:00
proxyType proxy ;
if ( addrConnect . IsValid ( ) ) {
bool proxyConnectionFailed = false ;
2017-09-18 19:45:51 -03:00
if ( GetProxy ( addrConnect . GetNetwork ( ) , proxy ) ) {
hSocket = CreateSocket ( proxy . proxy ) ;
if ( hSocket = = INVALID_SOCKET ) {
return nullptr ;
}
2019-12-11 13:39:29 -03:00
connected = ConnectThroughProxy ( proxy , addrConnect . ToStringIP ( ) , addrConnect . GetPort ( ) , hSocket , nConnectTimeout , proxyConnectionFailed ) ;
2017-09-18 19:45:51 -03:00
} else {
// no proxy needed (none set for target network)
hSocket = CreateSocket ( addrConnect ) ;
if ( hSocket = = INVALID_SOCKET ) {
return nullptr ;
}
2020-04-29 17:55:59 -04:00
connected = ConnectSocketDirectly ( addrConnect , hSocket , nConnectTimeout , conn_type = = ConnectionType : : MANUAL ) ;
2017-09-18 19:45:51 -03:00
}
2017-06-22 14:01:04 -04: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-18 19:45:51 -03:00
hSocket = CreateSocket ( proxy . proxy ) ;
if ( hSocket = = INVALID_SOCKET ) {
return nullptr ;
}
2017-06-22 14:01:04 -04:00
std : : string host ;
int port = default_port ;
SplitHostPort ( std : : string ( pszDest ) , port , host ) ;
2019-12-11 13:39:29 -03:00
bool proxyConnectionFailed ;
connected = ConnectThroughProxy ( proxy , host , port , hSocket , nConnectTimeout , proxyConnectionFailed ) ;
2017-06-22 14:01:04 -04:00
}
2017-10-02 15:18:32 -03:00
if ( ! connected ) {
CloseSocket ( hSocket ) ;
return nullptr ;
2010-08-29 12:58:15 -04:00
}
2014-05-24 05:14:52 -04:00
2017-10-02 15:18:32 -03:00
// Add node
NodeId id = GetNewNodeId ( ) ;
uint64_t nonce = GetDeterministicRandomizer ( RANDOMIZER_ID_LOCALHOSTNONCE ) . Write ( id ) . Finalize ( ) ;
CAddress addr_bind = GetBindAddress ( hSocket ) ;
2021-01-02 06:25:05 -03:00
CNode * pnode = new CNode ( id , nLocalServices , hSocket , addrConnect , CalculateKeyedNetGroup ( addrConnect ) , nonce , addr_bind , pszDest ? pszDest : " " , conn_type ) ;
2017-10-02 15:18:32 -03:00
pnode - > AddRef ( ) ;
2019-11-23 13:42:23 -03:00
// We're making a new connection, harvest entropy from the time (and our peer count)
RandAddEvent ( ( uint32_t ) id ) ;
2017-10-02 15:18:32 -03:00
return pnode ;
2010-08-29 12:58:15 -04:00
}
void CNode : : CloseSocketDisconnect ( )
{
fDisconnect = true ;
2017-02-06 16:05:45 -03:00
LOCK ( cs_hSocket ) ;
2010-08-29 12:58:15 -04:00
if ( hSocket ! = INVALID_SOCKET )
{
2016-12-25 17:19:40 -03:00
LogPrint ( BCLog : : NET , " disconnecting peer=%d \n " , id ) ;
2014-07-10 06:13:03 -04:00
CloseSocket ( hSocket ) ;
2010-08-29 12:58:15 -04:00
}
}
2019-06-20 05:37:51 -04:00
void CConnman : : AddWhitelistPermissionFlags ( NetPermissionFlags & flags , const CNetAddr & addr ) const {
for ( const auto & subnet : vWhitelistedRange ) {
if ( subnet . m_subnet . Match ( addr ) ) NetPermissions : : AddFlag ( flags , subnet . m_flags ) ;
2014-06-21 07:34:36 -04:00
}
}
2020-08-10 21:30:04 -04:00
std : : string CNode : : ConnectionTypeAsString ( ) const
{
switch ( m_conn_type ) {
case ConnectionType : : INBOUND :
return " inbound " ;
case ConnectionType : : MANUAL :
return " manual " ;
case ConnectionType : : FEELER :
return " feeler " ;
case ConnectionType : : OUTBOUND_FULL_RELAY :
return " outbound-full-relay " ;
case ConnectionType : : BLOCK_RELAY :
return " block-relay-only " ;
case ConnectionType : : ADDR_FETCH :
return " addr-fetch " ;
} // no default case, so the compiler can warn about missing cases
assert ( false ) ;
}
2017-02-06 14:04:34 -03: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 14:18:51 -03: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 ;
}
}
2020-09-30 13:19:19 -03:00
Network CNode : : ConnectedThroughNetwork ( ) const
{
2020-10-21 06:52:19 -03:00
return m_inbound_onion ? NET_ONION : addr . GetNetClass ( ) ;
2020-09-30 13:19:19 -03:00
}
2012-06-29 17:24:53 -04:00
# undef X
# define X(name) stats.name = name
2020-01-29 18:57:58 -03:00
void CNode : : copyStats ( CNodeStats & stats , const std : : vector < bool > & m_asmap )
2012-06-29 17:24:53 -04:00
{
2013-11-17 21:25:17 -03:00
stats . nodeid = this - > GetId ( ) ;
2012-06-29 17:24:53 -04:00
X ( nServices ) ;
2016-10-04 20:27:11 -03:00
X ( addr ) ;
2017-05-30 05:59:42 -04:00
X ( addrBind ) ;
2020-12-25 10:25:45 -03:00
stats . m_network = ConnectedThroughNetwork ( ) ;
2019-12-24 15:26:46 -03:00
stats . m_mapped_as = addr . GetMappedAS ( m_asmap ) ;
2019-03-08 17:48:41 -03:00
if ( m_tx_relay ! = nullptr ) {
2019-03-08 17:30:36 -03:00
LOCK ( m_tx_relay - > cs_filter ) ;
stats . fRelayTxes = m_tx_relay - > fRelayTxes ;
2019-03-08 17:48:41 -03:00
} else {
stats . fRelayTxes = false ;
2017-02-06 13:53:34 -03:00
}
2012-06-29 17:24:53 -04:00
X ( nLastSend ) ;
X ( nLastRecv ) ;
2020-08-09 15:49:31 -04:00
X ( nLastTXTime ) ;
X ( nLastBlockTime ) ;
2012-06-29 17:24:53 -04:00
X ( nTimeConnected ) ;
2014-12-15 07:06:15 -03:00
X ( nTimeOffset ) ;
2017-02-06 14:04:34 -03:00
stats . addrName = GetAddrName ( ) ;
2012-06-29 17:24:53 -04:00
X ( nVersion ) ;
2017-02-06 14:08:31 -03:00
{
LOCK ( cs_SubVer ) ;
X ( cleanSubVer ) ;
}
2020-07-28 16:39:38 -04:00
stats . fInbound = IsInboundConn ( ) ;
2020-08-21 09:17:42 -04:00
X ( m_bip152_highbandwidth_to ) ;
X ( m_bip152_highbandwidth_from ) ;
2017-02-06 04:34:57 -03:00
{
LOCK ( cs_vSend ) ;
X ( mapSendBytesPerMsgCmd ) ;
X ( nSendBytes ) ;
}
{
LOCK ( cs_vRecv ) ;
X ( mapRecvBytesPerMsgCmd ) ;
X ( nRecvBytes ) ;
}
2019-06-20 05:37:51 -04:00
X ( m_permissionFlags ) ;
2019-03-08 17:48:41 -03:00
if ( m_tx_relay ! = nullptr ) {
2019-03-08 17:30:36 -03:00
LOCK ( m_tx_relay - > cs_feeFilter ) ;
stats . minFeeFilter = m_tx_relay - > minFeeFilter ;
2019-03-08 17:48:41 -03:00
} else {
stats . minFeeFilter = 0 ;
2018-10-08 10:33:39 -03:00
}
2013-11-15 08:24:34 -03:00
2013-08-22 07:34:33 -04: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.
2020-04-14 13:24:18 -04:00
std : : chrono : : microseconds ping_wait { 0 } ;
if ( ( 0 ! = nPingNonceSent ) & & ( 0 ! = m_ping_start . load ( ) . count ( ) ) ) {
ping_wait = GetTime < std : : chrono : : microseconds > ( ) - m_ping_start . load ( ) ;
2013-08-22 07:34:33 -04:00
}
2013-11-15 08:24:34 -03:00
2013-08-22 07:34:33 -04: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 :)
2020-03-03 10:35:01 -03:00
stats . m_ping_usec = nPingUsecTime ;
2020-03-03 10:40:29 -03:00
stats . m_min_ping_usec = nMinPingUsecTime ;
2020-04-14 13:24:18 -04:00
stats . m_ping_wait_usec = count_microseconds ( ping_wait ) ;
2013-11-15 08:24:34 -03:00
2013-08-22 01:50:19 -04:00
// Leave string empty if addrLocal invalid (not filled in yet)
2017-02-06 14:18:51 -03:00
CService addrLocalUnlocked = GetAddrLocal ( ) ;
stats . addrLocal = addrLocalUnlocked . IsValid ( ) ? addrLocalUnlocked . ToString ( ) : " " ;
2020-08-12 16:57:13 -04:00
stats . m_conn_type_string = ConnectionTypeAsString ( ) ;
2012-06-29 17:24:53 -04:00
}
# undef X
2010-08-29 12:58:15 -04:00
2020-11-20 06:16:10 -03:00
bool CNode : : ReceiveMsgBytes ( Span < const uint8_t > msg_bytes , bool & complete )
2012-11-15 21:41:12 -03:00
{
2016-04-18 22:33:54 -03:00
complete = false ;
2020-04-14 13:24:18 -04:00
const auto time = GetTime < std : : chrono : : microseconds > ( ) ;
2017-02-06 04:34:57 -03:00
LOCK ( cs_vRecv ) ;
2020-04-14 13:24:18 -04:00
nLastRecv = std : : chrono : : duration_cast < std : : chrono : : seconds > ( time ) . count ( ) ;
2020-09-30 12:08:26 -03:00
nRecvBytes + = msg_bytes . size ( ) ;
while ( msg_bytes . size ( ) > 0 ) {
2012-11-15 21:41:12 -03:00
// absorb network data
2020-09-30 12:08:26 -03:00
int handled = m_deserializer - > Read ( msg_bytes ) ;
2020-06-29 14:15:06 -04:00
if ( handled < 0 ) {
2020-05-26 17:01:57 -04:00
// Serious header problem, disconnect from the peer.
2020-06-29 14:15:06 -04:00
return false ;
}
2015-03-05 09:01:22 -03:00
2019-06-13 05:25:54 -04:00
if ( m_deserializer - > Complete ( ) ) {
2019-06-13 04:39:44 -04:00
// decompose a transport agnostic CNetMessage from the deserializer
2020-06-29 14:15:06 -04:00
uint32_t out_err_raw_size { 0 } ;
2020-06-08 22:26:22 -04:00
Optional < CNetMessage > result { m_deserializer - > GetMessage ( time , out_err_raw_size ) } ;
2020-06-29 14:15:06 -04:00
if ( ! result ) {
2020-05-26 17:01:57 -04:00
// Message deserialization failed. Drop the message but don't disconnect the peer.
2020-06-29 14:15:06 -04:00
// store the size of the corrupt message
mapRecvBytesPerMsgCmd . find ( NET_MESSAGE_COMMAND_OTHER ) - > second + = out_err_raw_size ;
continue ;
}
2019-06-13 04:39:44 -04:00
2015-08-25 11:30:31 -03:00
//store received bytes per message command
//to prevent a memory DOS, only allow valid commands
2020-06-29 14:15:06 -04:00
mapMsgCmdSize : : iterator i = mapRecvBytesPerMsgCmd . find ( result - > m_command ) ;
2015-08-25 11:30:31 -03:00
if ( i = = mapRecvBytesPerMsgCmd . end ( ) )
i = mapRecvBytesPerMsgCmd . find ( NET_MESSAGE_COMMAND_OTHER ) ;
assert ( i ! = mapRecvBytesPerMsgCmd . end ( ) ) ;
2020-06-29 14:15:06 -04:00
i - > second + = result - > m_raw_message_size ;
2019-06-13 04:39:44 -04:00
// push the message to the process queue,
2020-06-29 14:15:06 -04:00
vRecvMsg . push_back ( std : : move ( * result ) ) ;
2015-08-25 11:30:31 -03:00
2016-04-18 22:33:54 -03:00
complete = true ;
2015-04-05 06:35:37 -03:00
}
2012-11-15 21:41:12 -03:00
}
return true ;
}
2020-11-20 06:16:10 -03:00
int V1TransportDeserializer : : readHeader ( Span < const uint8_t > msg_bytes )
2012-11-15 21:41:12 -03:00
{
// copy data to temporary parsing buffer
2020-05-10 09:47:32 -04:00
unsigned int nRemaining = CMessageHeader : : HEADER_SIZE - nHdrPos ;
2020-09-30 12:08:26 -03:00
unsigned int nCopy = std : : min < unsigned int > ( nRemaining , msg_bytes . size ( ) ) ;
2012-11-15 21:41:12 -03:00
2020-09-30 12:08:26 -03:00
memcpy ( & hdrbuf [ nHdrPos ] , msg_bytes . data ( ) , nCopy ) ;
2012-11-15 21:41:12 -03:00
nHdrPos + = nCopy ;
// if header incomplete, exit
2020-05-10 09:47:32 -04:00
if ( nHdrPos < CMessageHeader : : HEADER_SIZE )
2012-11-15 21:41:12 -03:00
return nCopy ;
// deserialize to CMessageHeader
try {
hdrbuf > > hdr ;
}
2014-12-07 09:29:06 -03:00
catch ( const std : : exception & ) {
2020-05-26 17:01:57 -04:00
LogPrint ( BCLog : : NET , " HEADER ERROR - UNABLE TO DESERIALIZE, peer=%d \n " , m_node_id ) ;
return - 1 ;
}
// Check start string, network magic
if ( memcmp ( hdr . pchMessageStart , m_chain_params . MessageStart ( ) , CMessageHeader : : MESSAGE_START_SIZE ) ! = 0 ) {
LogPrint ( BCLog : : NET , " HEADER ERROR - MESSAGESTART (%s, %u bytes), received %s, peer=%d \n " , hdr . GetCommand ( ) , hdr . nMessageSize , HexStr ( hdr . pchMessageStart ) , m_node_id ) ;
2012-11-15 21:41:12 -03:00
return - 1 ;
}
2019-10-18 15:57:10 -03:00
// reject messages larger than MAX_SIZE or MAX_PROTOCOL_MESSAGE_LENGTH
if ( hdr . nMessageSize > MAX_SIZE | | hdr . nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH ) {
2020-05-26 17:01:57 -04:00
LogPrint ( BCLog : : NET , " HEADER ERROR - SIZE (%s, %u bytes), peer=%d \n " , hdr . GetCommand ( ) , hdr . nMessageSize , m_node_id ) ;
2017-03-06 13:54:08 -03:00
return - 1 ;
2019-10-18 15:57:10 -03:00
}
2012-11-15 21:41:12 -03:00
// switch state to reading message data
in_data = true ;
return nCopy ;
}
2020-11-20 06:16:10 -03:00
int V1TransportDeserializer : : readData ( Span < const uint8_t > msg_bytes )
2012-11-15 21:41:12 -03:00
{
unsigned int nRemaining = hdr . nMessageSize - nDataPos ;
2020-09-30 12:08:26 -03:00
unsigned int nCopy = std : : min < unsigned int > ( nRemaining , msg_bytes . size ( ) ) ;
2012-11-15 21:41:12 -03:00
2014-06-21 11:00:38 -04: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 ) ) ;
}
2020-11-20 06:16:10 -03:00
hasher . Write ( msg_bytes . first ( nCopy ) ) ;
2020-09-30 12:08:26 -03:00
memcpy ( & vRecv [ nDataPos ] , msg_bytes . data ( ) , nCopy ) ;
2012-11-15 21:41:12 -03:00
nDataPos + = nCopy ;
return nCopy ;
}
2019-06-13 05:25:54 -04:00
const uint256 & V1TransportDeserializer : : GetMessageHash ( ) const
2016-10-30 19:02:16 -03:00
{
2019-06-13 05:25:54 -04:00
assert ( Complete ( ) ) ;
2016-10-30 19:02:16 -03:00
if ( data_hash . IsNull ( ) )
2020-06-18 20:19:46 -04:00
hasher . Finalize ( data_hash ) ;
2016-10-30 19:02:16 -03:00
return data_hash ;
}
2020-06-08 22:26:22 -04:00
Optional < CNetMessage > V1TransportDeserializer : : GetMessage ( const std : : chrono : : microseconds time , uint32_t & out_err_raw_size )
2020-04-14 13:24:18 -04:00
{
2019-06-13 04:39:44 -04:00
// decompose a single CNetMessage from the TransportDeserializer
2020-06-29 14:15:06 -04:00
Optional < CNetMessage > msg ( std : : move ( vRecv ) ) ;
2019-06-13 04:39:44 -04:00
2020-06-29 14:15:06 -04:00
// store command string, time, and sizes
msg - > m_command = hdr . GetCommand ( ) ;
msg - > m_time = time ;
msg - > m_message_size = hdr . nMessageSize ;
msg - > m_raw_message_size = hdr . nMessageSize + CMessageHeader : : HEADER_SIZE ;
2019-06-13 04:39:44 -04:00
2020-06-08 22:26:22 -04:00
uint256 hash = GetMessageHash ( ) ;
2019-06-13 04:39:44 -04:00
2019-11-23 13:42:23 -03:00
// We just received a message off the wire, harvest entropy from the time (and the message checksum)
RandAddEvent ( ReadLE32 ( hash . begin ( ) ) ) ;
2020-05-26 17:01:57 -04:00
// Check checksum and header command string
2020-06-29 14:15:06 -04:00
if ( memcmp ( hash . begin ( ) , hdr . pchChecksum , CMessageHeader : : CHECKSUM_SIZE ) ! = 0 ) {
2020-06-29 14:09:42 -04:00
LogPrint ( BCLog : : NET , " CHECKSUM ERROR (%s, %u bytes), expected %s was %s, peer=%d \n " ,
2020-06-29 14:15:06 -04:00
SanitizeString ( msg - > m_command ) , msg - > m_message_size ,
2020-06-24 11:26:47 -04:00
HexStr ( Span < uint8_t > ( hash . begin ( ) , hash . begin ( ) + CMessageHeader : : CHECKSUM_SIZE ) ) ,
2020-06-29 14:09:42 -04:00
HexStr ( hdr . pchChecksum ) ,
m_node_id ) ;
2020-06-29 14:15:06 -04:00
out_err_raw_size = msg - > m_raw_message_size ;
msg = nullopt ;
2020-05-26 17:01:57 -04:00
} else if ( ! hdr . IsCommandValid ( ) ) {
LogPrint ( BCLog : : NET , " HEADER ERROR - COMMAND (%s, %u bytes), peer=%d \n " ,
hdr . GetCommand ( ) , msg - > m_message_size , m_node_id ) ;
out_err_raw_size = msg - > m_raw_message_size ;
msg = nullopt ;
2019-06-13 04:39:44 -04:00
}
2020-06-29 14:15:06 -04:00
// Always reset the network deserializer (prepare for the next message)
2019-06-13 04:39:44 -04:00
Reset ( ) ;
return msg ;
}
2019-08-07 09:56:24 -04:00
void V1TransportSerializer : : prepareForTransport ( CSerializedNetMsg & msg , std : : vector < unsigned char > & header ) {
// create dbl-sha256 checksum
2020-06-26 16:36:41 -04:00
uint256 hash = Hash ( msg . data ) ;
2019-08-07 09:56:24 -04:00
// create header
2020-05-10 13:48:11 -04:00
CMessageHeader hdr ( Params ( ) . MessageStart ( ) , msg . m_type . c_str ( ) , msg . data . size ( ) ) ;
2019-08-07 09:56:24 -04:00
memcpy ( hdr . pchChecksum , hash . begin ( ) , CMessageHeader : : CHECKSUM_SIZE ) ;
// serialize header
header . reserve ( CMessageHeader : : HEADER_SIZE ) ;
CVectorWriter { SER_NETWORK , INIT_PROTO_VERSION , header , 0 , hdr } ;
}
2018-10-08 10:34:39 -03:00
size_t CConnman : : SocketSendData ( CNode * pnode ) const EXCLUSIVE_LOCKS_REQUIRED ( pnode - > cs_vSend )
2012-11-15 20:04:52 -03:00
{
2016-11-10 22:17:30 -03:00
auto it = pnode - > vSendMsg . begin ( ) ;
2016-05-21 06:04:02 -04:00
size_t nSentSize = 0 ;
2013-03-24 12:52:24 -03:00
while ( it ! = pnode - > vSendMsg . end ( ) ) {
2016-11-10 22:17:30 -03:00
const auto & data = * it ;
2013-03-24 12:52:24 -03:00
assert ( data . size ( ) > pnode - > nSendOffset ) ;
2017-02-06 16:05:45 -03: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 12:52:24 -03:00
if ( nBytes > 0 ) {
2017-01-19 15:01:18 -03:00
pnode - > nLastSend = GetSystemTimeInSeconds ( ) ;
2013-04-07 14:31:13 -03:00
pnode - > nSendBytes + = nBytes ;
2013-03-24 12:52:24 -03:00
pnode - > nSendOffset + = nBytes ;
2016-05-21 06:04:02 -04:00
nSentSize + = nBytes ;
2013-03-24 12:52:24 -03:00
if ( pnode - > nSendOffset = = data . size ( ) ) {
pnode - > nSendOffset = 0 ;
pnode - > nSendSize - = data . size ( ) ;
2016-12-31 04:05:32 -03:00
pnode - > fPauseSend = pnode - > nSendSize > nSendBufferMaxSize ;
2013-03-24 12:52:24 -03: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 08:15:19 -04:00
LogPrintf ( " socket send error %s \n " , NetworkErrorString ( nErr ) ) ;
2013-03-24 12:52:24 -03:00
pnode - > CloseSocketDisconnect ( ) ;
}
}
// couldn't send anything at all
break ;
2012-11-15 20:04:52 -03:00
}
}
2013-03-24 12:52:24 -03:00
if ( it = = pnode - > vSendMsg . end ( ) ) {
assert ( pnode - > nSendOffset = = 0 ) ;
assert ( pnode - > nSendSize = = 0 ) ;
}
pnode - > vSendMsg . erase ( pnode - > vSendMsg . begin ( ) , it ) ;
2016-05-21 06:04:02 -04:00
return nSentSize ;
2012-11-15 20:04:52 -03:00
}
2010-08-29 12:58:15 -04:00
2016-04-18 16:58:19 -03:00
static bool ReverseCompareNodeMinPingTime ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
2015-08-13 06:58:58 -03:00
{
2016-04-18 16:58:19 -03:00
return a . nMinPingUsecTime > b . nMinPingUsecTime ;
2015-08-13 06:58:58 -03:00
}
2016-04-18 16:58:19 -03:00
static bool ReverseCompareNodeTimeConnected ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
2015-08-13 06:58:58 -03:00
{
2016-04-18 16:58:19 -03:00
return a . nTimeConnected > b . nTimeConnected ;
2015-08-13 06:58:58 -03:00
}
2020-08-05 14:31:50 -04:00
static bool CompareLocalHostTimeConnected ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
{
if ( a . m_is_local ! = b . m_is_local ) return b . m_is_local ;
return a . nTimeConnected > b . nTimeConnected ;
}
2016-05-23 03:21:05 -04:00
static bool CompareNetGroupKeyed ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b ) {
2016-05-25 09:38:32 -04:00
return a . nKeyedNetGroup < b . nKeyedNetGroup ;
2016-05-22 01:55:15 -04: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-10-31 21:08:47 -03:00
if ( a . fRelevantServices ! = b . fRelevantServices ) return b . fRelevantServices ;
2016-05-22 01:55:15 -04: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 06:58:58 -03:00
2020-08-05 14:31:50 -04:00
// Pick out the potential block-relay only peers, and sort them by last block time.
static bool CompareNodeBlockRelayOnlyTime ( const NodeEvictionCandidate & a , const NodeEvictionCandidate & b )
{
if ( a . fRelayTxes ! = b . fRelayTxes ) return a . fRelayTxes ;
if ( a . nLastBlockTime ! = b . nLastBlockTime ) return a . nLastBlockTime < b . nLastBlockTime ;
if ( a . fRelevantServices ! = b . fRelevantServices ) return b . fRelevantServices ;
return a . nTimeConnected > b . nTimeConnected ;
}
2017-10-19 04:53:01 -03: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 ( ) ) ;
}
2020-09-18 09:47:08 -03:00
[[nodiscard]] Optional < NodeId > SelectNodeToEvict ( std : : vector < NodeEvictionCandidate > & & vEvictionCandidates )
2016-04-16 20:13:12 -03:00
{
2015-08-13 06:58:58 -03:00
// Protect connections with certain characteristics
2015-08-20 20:47:49 -03:00
// Deterministically select 4 peers to protect by netgroup.
2016-05-23 03:21:05 -04:00
// An attacker cannot predict which netgroups will be protected
2017-10-19 04:53:01 -03:00
EraseLastKElements ( vEvictionCandidates , CompareNetGroupKeyed , 4 ) ;
2016-04-29 11:23:51 -03:00
// Protect the 8 nodes with the lowest minimum ping time.
2015-08-20 20:47:49 -03:00
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
2017-10-19 04:53:01 -03:00
EraseLastKElements ( vEvictionCandidates , ReverseCompareNodeMinPingTime , 8 ) ;
2020-09-01 11:40:32 -04:00
// Protect 4 nodes that most recently sent us novel transactions accepted into our mempool.
2016-05-22 01:55:15 -04:00
// An attacker cannot manipulate this metric without performing useful work.
2017-10-19 04:53:01 -03:00
EraseLastKElements ( vEvictionCandidates , CompareNodeTXTime , 4 ) ;
2020-08-05 14:31:50 -04:00
// Protect up to 8 non-tx-relay peers that have sent us novel blocks.
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , CompareNodeBlockRelayOnlyTime ) ;
size_t erase_size = std : : min ( size_t ( 8 ) , vEvictionCandidates . size ( ) ) ;
vEvictionCandidates . erase ( std : : remove_if ( vEvictionCandidates . end ( ) - erase_size , vEvictionCandidates . end ( ) , [ ] ( NodeEvictionCandidate const & n ) { return ! n . fRelayTxes & & n . fRelevantServices ; } ) , vEvictionCandidates . end ( ) ) ;
2020-09-01 11:40:32 -04:00
// Protect 4 nodes that most recently sent us novel blocks.
2016-05-22 01:55:15 -04:00
// An attacker cannot manipulate this metric without performing useful work.
2017-10-19 04:53:01 -03:00
EraseLastKElements ( vEvictionCandidates , CompareNodeBlockTime , 4 ) ;
2020-08-05 14:31:50 -04:00
2015-08-25 20:31:13 -03:00
// Protect the half of the remaining nodes which have been connected the longest.
2016-04-29 11:23:51 -03:00
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
2020-08-05 14:31:50 -04:00
// Reserve half of these protected spots for localhost peers, even if
// they're not longest-uptime overall. This helps protect tor peers, which
// tend to be otherwise disadvantaged under our eviction criteria.
size_t initial_size = vEvictionCandidates . size ( ) ;
size_t total_protect_size = initial_size / 2 ;
// Pick out up to 1/4 peers that are localhost, sorted by longest uptime.
std : : sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , CompareLocalHostTimeConnected ) ;
size_t local_erase_size = total_protect_size / 2 ;
vEvictionCandidates . erase ( std : : remove_if ( vEvictionCandidates . end ( ) - local_erase_size , vEvictionCandidates . end ( ) , [ ] ( NodeEvictionCandidate const & n ) { return n . m_is_local ; } ) , vEvictionCandidates . end ( ) ) ;
// Calculate how many we removed, and update our total number of peers that
// we want to protect based on uptime accordingly.
total_protect_size - = initial_size - vEvictionCandidates . size ( ) ;
EraseLastKElements ( vEvictionCandidates , ReverseCompareNodeTimeConnected , total_protect_size ) ;
2015-08-13 06:58:58 -03:00
2020-09-18 09:47:08 -03:00
if ( vEvictionCandidates . empty ( ) ) return nullopt ;
2015-08-13 06:58:58 -03:00
2018-12-11 18:07:36 -03:00
// If any remaining peers are preferred for eviction consider only them.
// This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
// then we probably don't want to evict it no matter what.
if ( std : : any_of ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , [ ] ( NodeEvictionCandidate const & n ) { return n . prefer_evict ; } ) ) {
vEvictionCandidates . erase ( std : : remove_if ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) ,
[ ] ( NodeEvictionCandidate const & n ) { return ! n . prefer_evict ; } ) , vEvictionCandidates . end ( ) ) ;
}
2015-11-23 00:48:54 -03:00
// Identify the network group with the most connections and youngest member.
// (vEvictionCandidates is already sorted by reverse connect time)
2016-05-25 09:38:32 -04:00
uint64_t naMostConnections ;
2015-08-13 06:58:58 -03:00
unsigned int nMostConnections = 0 ;
2015-11-23 00:48:54 -03:00
int64_t nMostConnectionsTime = 0 ;
2016-06-10 10:09:06 -04:00
std : : map < uint64_t , std : : vector < NodeEvictionCandidate > > mapNetGroupNodes ;
2017-06-01 21:18:57 -04:00
for ( const NodeEvictionCandidate & node : vEvictionCandidates ) {
2017-10-19 04:53:01 -03:00
std : : vector < NodeEvictionCandidate > & group = mapNetGroupNodes [ node . nKeyedNetGroup ] ;
group . push_back ( node ) ;
int64_t grouptime = group [ 0 ] . nTimeConnected ;
2015-08-13 06:58:58 -03:00
2017-10-19 04:53:01 -03:00
if ( group . size ( ) > nMostConnections | | ( group . size ( ) = = nMostConnections & & grouptime > nMostConnectionsTime ) ) {
nMostConnections = group . size ( ) ;
2015-11-23 00:48:54 -03:00
nMostConnectionsTime = grouptime ;
2016-05-25 09:38:32 -04:00
naMostConnections = node . nKeyedNetGroup ;
2015-08-13 06:58:58 -03:00
}
}
2015-08-25 21:06:15 -03:00
// Reduce to the network group with the most connections
2016-06-10 10:09:06 -04:00
vEvictionCandidates = std : : move ( mapNetGroupNodes [ naMostConnections ] ) ;
2015-08-13 06:58:58 -03:00
2015-11-23 00:48:54 -03:00
// Disconnect from the network group with the most connections
2020-09-18 09:47:08 -03:00
return vEvictionCandidates . front ( ) . id ;
}
/** 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 .
*/
bool CConnman : : AttemptToEvictConnection ( )
{
std : : vector < NodeEvictionCandidate > vEvictionCandidates ;
{
LOCK ( cs_vNodes ) ;
for ( const CNode * node : vNodes ) {
if ( node - > HasPermission ( PF_NOBAN ) )
continue ;
if ( ! node - > IsInboundConn ( ) )
continue ;
if ( node - > fDisconnect )
continue ;
bool peer_relay_txes = false ;
bool peer_filter_not_null = false ;
if ( node - > m_tx_relay ! = nullptr ) {
LOCK ( node - > m_tx_relay - > cs_filter ) ;
peer_relay_txes = node - > m_tx_relay - > fRelayTxes ;
peer_filter_not_null = node - > m_tx_relay - > pfilter ! = nullptr ;
}
NodeEvictionCandidate candidate = { node - > GetId ( ) , node - > nTimeConnected , node - > nMinPingUsecTime ,
node - > nLastBlockTime , node - > nLastTXTime ,
HasAllDesirableServiceFlags ( node - > nServices ) ,
peer_relay_txes , peer_filter_not_null , node - > nKeyedNetGroup ,
node - > m_prefer_evict , node - > addr . IsLocal ( ) } ;
vEvictionCandidates . push_back ( candidate ) ;
}
}
const Optional < NodeId > node_id_to_evict = SelectNodeToEvict ( std : : move ( vEvictionCandidates ) ) ;
if ( ! node_id_to_evict ) {
return false ;
}
2016-04-18 16:58:19 -03:00
LOCK ( cs_vNodes ) ;
2017-07-20 05:32:47 -04:00
for ( CNode * pnode : vNodes ) {
2020-09-18 09:47:08 -03:00
if ( pnode - > GetId ( ) = = * node_id_to_evict ) {
2017-07-20 05:32:47 -04:00
pnode - > fDisconnect = true ;
2016-04-18 16:58:19 -03:00
return true ;
}
}
return false ;
2015-08-13 06:58:58 -03:00
}
2016-04-16 15:47:18 -03:00
void CConnman : : AcceptConnection ( const ListenSocket & hListenSocket ) {
2015-08-13 06:00:10 -03:00
struct sockaddr_storage sockaddr ;
socklen_t len = sizeof ( sockaddr ) ;
SOCKET hSocket = accept ( hListenSocket . socket , ( struct sockaddr * ) & sockaddr , & len ) ;
CAddress addr ;
int nInbound = 0 ;
2019-03-09 14:55:06 -03:00
int nMaxInbound = nMaxConnections - m_max_outbound ;
2015-08-13 06:00:10 -03:00
2017-05-30 05:59:42 -04:00
if ( hSocket ! = INVALID_SOCKET ) {
if ( ! addr . SetSockAddr ( ( const struct sockaddr * ) & sockaddr ) ) {
2015-08-13 06:00:10 -03:00
LogPrintf ( " Warning: Unknown socket family \n " ) ;
2017-05-30 05:59:42 -04:00
}
}
2015-08-13 06:00:10 -03:00
2019-06-20 05:37:51 -04:00
NetPermissionFlags permissionFlags = NetPermissionFlags : : PF_NONE ;
hListenSocket . AddSocketPermissionFlags ( permissionFlags ) ;
AddWhitelistPermissionFlags ( permissionFlags , addr ) ;
if ( NetPermissions : : HasFlag ( permissionFlags , NetPermissionFlags : : PF_ISIMPLICIT ) ) {
NetPermissions : : ClearFlag ( permissionFlags , PF_ISIMPLICIT ) ;
2019-08-16 04:45:13 -04:00
if ( gArgs . GetBoolArg ( " -whitelistforcerelay " , DEFAULT_WHITELISTFORCERELAY ) ) NetPermissions : : AddFlag ( permissionFlags , PF_FORCERELAY ) ;
if ( gArgs . GetBoolArg ( " -whitelistrelay " , DEFAULT_WHITELISTRELAY ) ) NetPermissions : : AddFlag ( permissionFlags , PF_RELAY ) ;
2019-06-20 05:37:51 -04:00
NetPermissions : : AddFlag ( permissionFlags , PF_MEMPOOL ) ;
NetPermissions : : AddFlag ( permissionFlags , PF_NOBAN ) ;
}
2015-08-13 06:00:10 -03:00
{
LOCK ( cs_vNodes ) ;
2017-07-20 05:32:47 -04:00
for ( const CNode * pnode : vNodes ) {
2020-07-28 16:39:38 -04:00
if ( pnode - > IsInboundConn ( ) ) nInbound + + ;
2017-07-20 05:32:47 -04:00
}
2015-08-13 06:00:10 -03:00
}
if ( hSocket = = INVALID_SOCKET )
{
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK )
LogPrintf ( " socket error accept failed: %s \n " , NetworkErrorString ( nErr ) ) ;
2015-08-13 06:16:46 -03:00
return ;
2015-08-13 06:00:10 -03:00
}
2015-08-13 06:16:46 -03:00
2013-03-25 22:33:25 -03:00
if ( ! fNetworkActive ) {
LogPrintf ( " connection from %s dropped: not accepting new connections \n " , addr . ToString ( ) ) ;
CloseSocket ( hSocket ) ;
return ;
}
2015-08-13 06:16:46 -03:00
if ( ! IsSelectableSocket ( hSocket ) )
2015-08-13 06:00:10 -03:00
{
LogPrintf ( " connection from %s dropped: non-selectable socket \n " , addr . ToString ( ) ) ;
CloseSocket ( hSocket ) ;
2015-08-13 06:16:46 -03:00
return ;
2015-08-13 06:00:10 -03:00
}
2015-08-13 06:16:46 -03:00
2015-10-21 20:52:29 -03: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 02:02:02 -03:00
SetSocketNoDelay ( hSocket ) ;
2015-10-21 20:52:29 -03:00
2020-06-08 21:46:53 -04:00
// Don't accept connections from banned peers.
2020-07-14 05:24:43 -04:00
bool banned = m_banman & & m_banman - > IsBanned ( addr ) ;
2020-06-10 20:11:38 -04:00
if ( ! NetPermissions : : HasFlag ( permissionFlags , NetPermissionFlags : : PF_NOBAN ) & & banned )
2015-08-13 06:00:10 -03:00
{
2017-10-30 19:56:37 -03:00
LogPrint ( BCLog : : NET , " connection from %s dropped (banned) \n " , addr . ToString ( ) ) ;
2015-08-13 06:00:10 -03:00
CloseSocket ( hSocket ) ;
2015-08-13 06:16:46 -03:00
return ;
2015-08-13 06:00:10 -03:00
}
2015-08-13 06:16:46 -03:00
2020-06-08 21:46:53 -04:00
// Only accept connections from discouraged peers if our inbound slots aren't (almost) full.
2020-07-14 05:24:43 -04:00
bool discouraged = m_banman & & m_banman - > IsDiscouraged ( addr ) ;
2020-06-10 20:11:38 -04:00
if ( ! NetPermissions : : HasFlag ( permissionFlags , NetPermissionFlags : : PF_NOBAN ) & & nInbound + 1 > = nMaxInbound & & discouraged )
2020-06-08 21:46:53 -04:00
{
LogPrint ( BCLog : : NET , " connection from %s dropped (discouraged) \n " , addr . ToString ( ) ) ;
CloseSocket ( hSocket ) ;
return ;
}
2015-08-13 06:19:17 -03:00
if ( nInbound > = nMaxInbound )
2015-08-13 06:00:10 -03:00
{
2016-05-22 01:55:15 -04:00
if ( ! AttemptToEvictConnection ( ) ) {
2015-08-13 06:58:58 -03:00
// No connection to evict, disconnect the new connection
2016-12-25 17:19:40 -03:00
LogPrint ( BCLog : : NET , " failed to find an eviction candidate - connection dropped (full) \n " ) ;
2015-08-13 06:58:58 -03:00
CloseSocket ( hSocket ) ;
return ;
}
2015-08-13 06:00:10 -03:00
}
2016-10-26 16:10:15 -03:00
NodeId id = GetNewNodeId ( ) ;
uint64_t nonce = GetDeterministicRandomizer ( RANDOMIZER_ID_LOCALHOSTNONCE ) . Write ( id ) . Finalize ( ) ;
2017-05-30 05:59:42 -04:00
CAddress addr_bind = GetBindAddress ( hSocket ) ;
2016-10-26 16:10:15 -03:00
2019-06-20 05:37:51 -04:00
ServiceFlags nodeServices = nLocalServices ;
if ( NetPermissions : : HasFlag ( permissionFlags , PF_BLOOMFILTER ) ) {
nodeServices = static_cast < ServiceFlags > ( nodeServices | NODE_BLOOM ) ;
}
2020-09-30 13:07:36 -03:00
const bool inbound_onion = std : : find ( m_onion_binds . begin ( ) , m_onion_binds . end ( ) , addr_bind ) ! = m_onion_binds . end ( ) ;
2021-01-02 06:25:05 -03:00
CNode * pnode = new CNode ( id , nodeServices , hSocket , addr , CalculateKeyedNetGroup ( addr ) , nonce , addr_bind , " " , ConnectionType : : INBOUND , inbound_onion ) ;
2015-08-13 06:16:46 -03:00
pnode - > AddRef ( ) ;
2019-06-20 05:37:51 -04:00
pnode - > m_permissionFlags = permissionFlags ;
2020-06-10 20:11:38 -04:00
pnode - > m_prefer_evict = discouraged ;
2017-07-06 14:08:23 -04:00
m_msgproc - > InitializeNode ( pnode ) ;
2015-08-13 06:00:10 -03:00
2016-12-25 17:19:40 -03:00
LogPrint ( BCLog : : NET , " connection from %s accepted \n " , addr . ToString ( ) ) ;
2015-08-13 06:16:46 -03:00
{
LOCK ( cs_vNodes ) ;
vNodes . push_back ( pnode ) ;
2015-08-13 06:00:10 -03:00
}
2019-11-23 13:42:23 -03:00
// We received a new connection, harvest entropy from the time (and our peer count)
RandAddEvent ( ( uint32_t ) id ) ;
2015-08-13 06:00:10 -03:00
}
2018-09-24 17:36:58 -03:00
void CConnman : : DisconnectNodes ( )
2010-08-29 12:58:15 -04:00
{
{
2018-09-24 17:30:53 -03:00
LOCK ( cs_vNodes ) ;
2018-05-10 13:23:22 -03:00
2018-09-24 17:36:58 -03:00
if ( ! fNetworkActive ) {
// Disconnect any connected nodes
for ( CNode * pnode : vNodes ) {
if ( ! pnode - > fDisconnect ) {
LogPrint ( BCLog : : NET , " Network not active, dropping peer=%d \n " , pnode - > GetId ( ) ) ;
pnode - > fDisconnect = true ;
2018-05-10 13:23:22 -03:00
}
}
2018-09-24 17:36:58 -03:00
}
2018-05-10 13:23:22 -03:00
2018-09-24 17:36:58 -03:00
// Disconnect unused nodes
std : : vector < CNode * > vNodesCopy = vNodes ;
for ( CNode * pnode : vNodesCopy )
{
if ( pnode - > fDisconnect )
2010-08-29 12:58:15 -04:00
{
2018-09-24 17:36:58 -03:00
// remove from vNodes
vNodes . erase ( remove ( vNodes . begin ( ) , vNodes . end ( ) , pnode ) , vNodes . end ( ) ) ;
2010-08-29 12:58:15 -04:00
2018-09-24 17:36:58 -03:00
// release outbound grant (if any)
pnode - > grantOutbound . Release ( ) ;
2012-04-04 11:01:57 -03:00
2018-09-24 17:36:58 -03:00
// close socket and cleanup
pnode - > CloseSocketDisconnect ( ) ;
2010-08-29 12:58:15 -04:00
2018-09-24 17:36:58 -03:00
// hold in disconnected pool until all refs are released
pnode - > Release ( ) ;
vNodesDisconnected . push_back ( pnode ) ;
2010-08-29 12:58:15 -04:00
}
2013-07-24 20:25:25 -04:00
}
2018-09-24 17:36:58 -03:00
}
{
// Delete disconnected nodes
std : : list < CNode * > vNodesDisconnectedCopy = vNodesDisconnected ;
for ( CNode * pnode : vNodesDisconnectedCopy )
2013-07-24 20:25:25 -04:00
{
2018-09-24 17:36:58 -03:00
// wait until threads are done using it
if ( pnode - > GetRefCount ( ) < = 0 ) {
bool fDelete = false ;
{
2020-06-20 23:23:14 -04:00
TRY_LOCK ( pnode - > cs_vSend , lockSend ) ;
if ( lockSend ) {
fDelete = true ;
2012-04-06 13:39:12 -03:00
}
2018-09-24 17:36:58 -03:00
}
if ( fDelete ) {
vNodesDisconnected . remove ( pnode ) ;
DeleteNode ( pnode ) ;
2010-08-29 12:58:15 -04:00
}
}
}
2018-09-24 17:36:58 -03:00
}
}
void CConnman : : NotifyNumConnectionsChanged ( )
{
size_t vNodesSize ;
{
LOCK ( cs_vNodes ) ;
vNodesSize = vNodes . size ( ) ;
}
if ( vNodesSize ! = nPrevNodeCount ) {
nPrevNodeCount = vNodesSize ;
if ( clientInterface )
clientInterface - > NotifyNumConnectionsChanged ( vNodesSize ) ;
}
}
2020-12-06 12:51:22 -03:00
void CConnman : : InactivityCheck ( CNode * pnode ) const
2018-09-24 17:43:00 -03:00
{
int64_t nTime = GetSystemTimeInSeconds ( ) ;
2018-11-15 20:30:26 -03:00
if ( nTime - pnode - > nTimeConnected > m_peer_connect_timeout )
2018-09-24 17:43:00 -03:00
{
if ( pnode - > nLastRecv = = 0 | | pnode - > nLastSend = = 0 )
{
2018-11-15 20:30:26 -03:00
LogPrint ( BCLog : : NET , " socket no message in first %i seconds, %d %d from %d \n " , m_peer_connect_timeout , pnode - > nLastRecv ! = 0 , pnode - > nLastSend ! = 0 , pnode - > GetId ( ) ) ;
2018-09-24 17:43:00 -03:00
pnode - > fDisconnect = true ;
}
else if ( nTime - pnode - > nLastSend > TIMEOUT_INTERVAL )
2016-11-26 00:29:55 -03:00
{
2018-09-24 17:43:00 -03:00
LogPrintf ( " socket sending timeout: %is \n " , nTime - pnode - > nLastSend ) ;
pnode - > fDisconnect = true ;
}
[net] Make p2p recv buffer timeout 20 minutes for all peers
The timeout interval for the send and recv buffers was changed from 90
minutes to 20 minutes in commit f1920e86 in 2013, except for peers that
did not support the pong message (where the recv buffer timeout remained
at 90 minutes). A few observations:
- for peers that support BIP 31 (pong messages), this recv buffer
timeout is almost redundant with the ping timeout. We send a ping
message every two minutes, and set a timeout of twenty minutes to
receive the pong response. If the recv buffer was really timing out,
then the pong response would also time out.
- BIP 31 is supported by all nodes of p2p version 60000 and higher, and
has been in widespread use since 2013. I'd be very surprised if there
are many nodes on the network that don't support pong messages.
- The recv buffer timeout is not specified in any p2p BIP. We're free to
set it at any value we want.
- A peer that doesn't support BIP 31 and hasn't sent any message to us
at all in 90 minutes is unlikely to be useful for us, and is more likely
to be evicted AttemptToEvictConnection() since it'll have the worst
possible ping time and isn't providing blocks/transactions.
Therefore, we remove this check, and sent the recv buffer timeout to 20
minutes for all peers. This removes the final p2p version dependent
logic from the net layer, so all p2p version data can move into the
net_processing layer.
Alternative approaches:
- Set the recv buffer timeout to 90 minutes for all peers. This almost
wouldn't be a behaviour change at all (pre-BIP 31 peers would still
have the same recv buffer timeout, and we can't ever reach a recv buffer
timeout higher than 21 minutes for post-BIP31 peers, because the pong
timeout would be hit first).
- Stop supporting peers that don't support BIP 31. BIP 31 has been in
use since 2012, and implementing it is trivial.
2020-12-14 09:59:30 -03:00
else if ( nTime - pnode - > nLastRecv > TIMEOUT_INTERVAL )
2018-09-24 17:43:00 -03:00
{
LogPrintf ( " socket receive timeout: %is \n " , nTime - pnode - > nLastRecv ) ;
pnode - > fDisconnect = true ;
}
2020-04-14 13:24:18 -04:00
else if ( pnode - > nPingNonceSent & & pnode - > m_ping_start . load ( ) + std : : chrono : : seconds { TIMEOUT_INTERVAL } < GetTime < std : : chrono : : microseconds > ( ) )
2018-09-24 17:43:00 -03:00
{
2020-04-14 13:24:18 -04:00
LogPrintf ( " ping timeout: %fs \n " , 0.000001 * count_microseconds ( GetTime < std : : chrono : : microseconds > ( ) - pnode - > m_ping_start . load ( ) ) ) ;
2018-09-24 17:43:00 -03:00
pnode - > fDisconnect = true ;
2016-11-26 00:29:55 -03:00
}
2018-09-24 17:43:00 -03:00
else if ( ! pnode - > fSuccessfullyConnected )
{
LogPrint ( BCLog : : NET , " version handshake timeout from %d \n " , pnode - > GetId ( ) ) ;
pnode - > fDisconnect = true ;
2010-08-29 12:58:15 -04:00
}
2018-09-24 17:43:00 -03:00
}
}
2010-08-29 12:58:15 -04:00
2018-09-25 16:32:07 -03:00
bool CConnman : : GenerateSelectSet ( std : : set < SOCKET > & recv_set , std : : set < SOCKET > & send_set , std : : set < SOCKET > & error_set )
2018-09-24 17:36:58 -03:00
{
2018-09-24 18:03:17 -03:00
for ( const ListenSocket & hListenSocket : vhListenSocket ) {
2018-09-25 16:32:07 -03:00
recv_set . insert ( hListenSocket . socket ) ;
2018-09-24 18:03:17 -03:00
}
2014-06-24 03:09:45 -04:00
2018-09-24 18:03:17 -03:00
{
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes )
2010-08-29 12:58:15 -04:00
{
2018-09-24 18:03:17 -03: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.
// * 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.
bool select_recv = ! pnode - > fPauseRecv ;
bool select_send ;
2010-08-29 12:58:15 -04:00
{
2018-09-24 18:03:17 -03:00
LOCK ( pnode - > cs_vSend ) ;
select_send = ! pnode - > vSendMsg . empty ( ) ;
}
2017-02-06 15:47:24 -03:00
2018-09-24 18:03:17 -03:00
LOCK ( pnode - > cs_hSocket ) ;
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
2017-02-06 16:05:45 -03:00
2018-09-25 16:32:07 -03:00
error_set . insert ( pnode - > hSocket ) ;
2018-09-24 18:03:17 -03:00
if ( select_send ) {
2018-09-25 16:32:07 -03:00
send_set . insert ( pnode - > hSocket ) ;
2018-09-24 18:03:17 -03:00
continue ;
}
if ( select_recv ) {
2018-09-25 16:32:07 -03:00
recv_set . insert ( pnode - > hSocket ) ;
2010-08-29 12:58:15 -04:00
}
}
2018-09-24 18:03:17 -03:00
}
2010-08-29 12:58:15 -04:00
2018-09-25 16:32:07 -03:00
return ! recv_set . empty ( ) | | ! send_set . empty ( ) | | ! error_set . empty ( ) ;
}
2018-09-26 22:54:52 -03:00
# ifdef USE_POLL
void CConnman : : SocketEvents ( std : : set < SOCKET > & recv_set , std : : set < SOCKET > & send_set , std : : set < SOCKET > & error_set )
{
std : : set < SOCKET > recv_select_set , send_select_set , error_select_set ;
if ( ! GenerateSelectSet ( recv_select_set , send_select_set , error_select_set ) ) {
interruptNet . sleep_for ( std : : chrono : : milliseconds ( SELECT_TIMEOUT_MILLISECONDS ) ) ;
return ;
}
std : : unordered_map < SOCKET , struct pollfd > pollfds ;
for ( SOCKET socket_id : recv_select_set ) {
pollfds [ socket_id ] . fd = socket_id ;
pollfds [ socket_id ] . events | = POLLIN ;
}
for ( SOCKET socket_id : send_select_set ) {
pollfds [ socket_id ] . fd = socket_id ;
pollfds [ socket_id ] . events | = POLLOUT ;
}
for ( SOCKET socket_id : error_select_set ) {
pollfds [ socket_id ] . fd = socket_id ;
// These flags are ignored, but we set them for clarity
pollfds [ socket_id ] . events | = POLLERR | POLLHUP ;
}
std : : vector < struct pollfd > vpollfds ;
vpollfds . reserve ( pollfds . size ( ) ) ;
for ( auto it : pollfds ) {
vpollfds . push_back ( std : : move ( it . second ) ) ;
}
if ( poll ( vpollfds . data ( ) , vpollfds . size ( ) , SELECT_TIMEOUT_MILLISECONDS ) < 0 ) return ;
if ( interruptNet ) return ;
for ( struct pollfd pollfd_entry : vpollfds ) {
if ( pollfd_entry . revents & POLLIN ) recv_set . insert ( pollfd_entry . fd ) ;
if ( pollfd_entry . revents & POLLOUT ) send_set . insert ( pollfd_entry . fd ) ;
if ( pollfd_entry . revents & ( POLLERR | POLLHUP ) ) error_set . insert ( pollfd_entry . fd ) ;
}
}
# else
2018-09-26 22:51:46 -03:00
void CConnman : : SocketEvents ( std : : set < SOCKET > & recv_set , std : : set < SOCKET > & send_set , std : : set < SOCKET > & error_set )
2018-09-25 16:32:07 -03:00
{
std : : set < SOCKET > recv_select_set , send_select_set , error_select_set ;
if ( ! GenerateSelectSet ( recv_select_set , send_select_set , error_select_set ) ) {
interruptNet . sleep_for ( std : : chrono : : milliseconds ( SELECT_TIMEOUT_MILLISECONDS ) ) ;
return ;
}
//
// Find which sockets have data to receive
//
struct timeval timeout ;
timeout . tv_sec = 0 ;
timeout . tv_usec = SELECT_TIMEOUT_MILLISECONDS * 1000 ; // 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 ;
for ( SOCKET hSocket : recv_select_set ) {
FD_SET ( hSocket , & fdsetRecv ) ;
hSocketMax = std : : max ( hSocketMax , hSocket ) ;
}
for ( SOCKET hSocket : send_select_set ) {
FD_SET ( hSocket , & fdsetSend ) ;
hSocketMax = std : : max ( hSocketMax , hSocket ) ;
}
for ( SOCKET hSocket : error_select_set ) {
FD_SET ( hSocket , & fdsetError ) ;
hSocketMax = std : : max ( hSocketMax , hSocket ) ;
}
int nSelect = select ( hSocketMax + 1 , & fdsetRecv , & fdsetSend , & fdsetError , & timeout ) ;
2018-09-24 18:03:17 -03:00
if ( interruptNet )
return ;
2013-03-07 00:31:26 -03:00
2018-09-24 18:03:17 -03:00
if ( nSelect = = SOCKET_ERROR )
{
2018-09-25 16:32:07 -03:00
int nErr = WSAGetLastError ( ) ;
LogPrintf ( " socket select error %s \n " , NetworkErrorString ( nErr ) ) ;
for ( unsigned int i = 0 ; i < = hSocketMax ; i + + )
FD_SET ( i , & fdsetRecv ) ;
2018-09-24 18:03:17 -03:00
FD_ZERO ( & fdsetSend ) ;
FD_ZERO ( & fdsetError ) ;
2018-10-29 17:30:30 -03:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( SELECT_TIMEOUT_MILLISECONDS ) ) )
2018-09-24 18:03:17 -03:00
return ;
}
2010-08-29 12:58:15 -04:00
2018-09-26 22:51:46 -03:00
for ( SOCKET hSocket : recv_select_set ) {
if ( FD_ISSET ( hSocket , & fdsetRecv ) ) {
recv_set . insert ( hSocket ) ;
}
}
for ( SOCKET hSocket : send_select_set ) {
if ( FD_ISSET ( hSocket , & fdsetSend ) ) {
send_set . insert ( hSocket ) ;
}
}
for ( SOCKET hSocket : error_select_set ) {
if ( FD_ISSET ( hSocket , & fdsetError ) ) {
error_set . insert ( hSocket ) ;
}
}
}
2018-09-26 22:54:52 -03:00
# endif
2018-09-26 22:51:46 -03:00
void CConnman : : SocketHandler ( )
{
std : : set < SOCKET > recv_set , send_set , error_set ;
SocketEvents ( recv_set , send_set , error_set ) ;
if ( interruptNet ) return ;
2018-09-24 18:03:17 -03:00
//
// Accept new connections
//
for ( const ListenSocket & hListenSocket : vhListenSocket )
{
2018-09-26 22:51:46 -03:00
if ( hListenSocket . socket ! = INVALID_SOCKET & & recv_set . count ( hListenSocket . socket ) > 0 )
2010-08-29 12:58:15 -04:00
{
2018-09-24 18:03:17 -03:00
AcceptConnection ( hListenSocket ) ;
2010-08-29 12:58:15 -04:00
}
2018-09-24 18:03:17 -03:00
}
//
// Service each socket
//
std : : vector < CNode * > vNodesCopy ;
{
LOCK ( cs_vNodes ) ;
vNodesCopy = vNodes ;
for ( CNode * pnode : vNodesCopy )
pnode - > AddRef ( ) ;
}
for ( CNode * pnode : vNodesCopy )
{
if ( interruptNet )
return ;
2010-08-29 12:58:15 -04:00
//
2018-09-24 18:03:17 -03:00
// Receive
2010-08-29 12:58:15 -04:00
//
2018-09-24 18:03:17 -03:00
bool recvSet = false ;
bool sendSet = false ;
bool errorSet = false ;
2010-08-29 12:58:15 -04:00
{
2018-09-24 18:03:17 -03:00
LOCK ( pnode - > cs_hSocket ) ;
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
2018-09-26 22:51:46 -03:00
recvSet = recv_set . count ( pnode - > hSocket ) > 0 ;
sendSet = send_set . count ( pnode - > hSocket ) > 0 ;
errorSet = error_set . count ( pnode - > hSocket ) > 0 ;
2010-08-29 12:58:15 -04:00
}
2018-09-24 18:03:17 -03:00
if ( recvSet | | errorSet )
2010-08-29 12:58:15 -04:00
{
2018-09-24 18:03:17 -03:00
// typical socket buffer is 8K-64K
2020-11-20 06:16:10 -03:00
uint8_t pchBuf [ 0x10000 ] ;
2018-09-24 18:03:17 -03:00
int nBytes = 0 ;
2017-02-06 16:05:45 -03:00
{
LOCK ( pnode - > cs_hSocket ) ;
if ( pnode - > hSocket = = INVALID_SOCKET )
continue ;
2020-11-20 06:16:10 -03:00
nBytes = recv ( pnode - > hSocket , ( char * ) pchBuf , sizeof ( pchBuf ) , MSG_DONTWAIT ) ;
2017-02-06 16:05:45 -03:00
}
2018-09-24 18:03:17 -03:00
if ( nBytes > 0 )
2010-08-29 12:58:15 -04:00
{
2018-09-24 18:03:17 -03:00
bool notify = false ;
2020-11-20 06:16:10 -03:00
if ( ! pnode - > ReceiveMsgBytes ( Span < const uint8_t > ( pchBuf , nBytes ) , notify ) )
2017-03-06 13:54:08 -03:00
pnode - > CloseSocketDisconnect ( ) ;
2018-09-24 18:03:17 -03:00
RecordBytesRecv ( nBytes ) ;
if ( notify ) {
size_t nSizeAdded = 0 ;
auto it ( pnode - > vRecvMsg . begin ( ) ) ;
for ( ; it ! = pnode - > vRecvMsg . end ( ) ; + + it ) {
2019-06-13 04:39:44 -04:00
// vRecvMsg contains only completed CNetMessage
// the single possible partially deserialized message are held by TransportDeserializer
2019-06-13 05:07:50 -04:00
nSizeAdded + = it - > m_raw_message_size ;
2018-09-24 18:03:17 -03:00
}
2017-03-06 13:54:08 -03:00
{
2018-09-24 18:03:17 -03: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 ;
2010-08-29 12:58:15 -04:00
}
2018-09-24 18:03:17 -03:00
WakeMessageHandler ( ) ;
2010-08-29 12:58:15 -04:00
}
}
2018-09-24 18:03:17 -03:00
else if ( nBytes = = 0 )
2010-08-29 12:58:15 -04:00
{
2018-09-24 18:03:17 -03:00
// socket closed gracefully
if ( ! pnode - > fDisconnect ) {
2019-10-25 10:30:35 -03:00
LogPrint ( BCLog : : NET , " socket closed for peer=%d \n " , pnode - > GetId ( ) ) ;
2016-04-18 22:44:42 -03:00
}
2018-09-24 18:03:17 -03:00
pnode - > CloseSocketDisconnect ( ) ;
2010-08-29 12:58:15 -04:00
}
2018-09-24 18:03:17 -03:00
else if ( nBytes < 0 )
2010-08-29 12:58:15 -04:00
{
2018-09-24 18:03:17 -03:00
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
2017-02-07 17:23:17 -03:00
{
2019-10-25 10:30:35 -03:00
if ( ! pnode - > fDisconnect ) {
LogPrint ( BCLog : : NET , " socket recv error for peer=%d: %s \n " , pnode - > GetId ( ) , NetworkErrorString ( nErr ) ) ;
}
2018-09-24 18:03:17 -03:00
pnode - > CloseSocketDisconnect ( ) ;
2017-02-07 17:23:17 -03:00
}
2010-08-29 12:58:15 -04:00
}
}
2018-09-24 18:03:17 -03:00
2020-12-27 06:22:04 -03:00
if ( sendSet ) {
// Send data
size_t bytes_sent = WITH_LOCK ( pnode - > cs_vSend , return SocketSendData ( pnode ) ) ;
if ( bytes_sent ) RecordBytesSent ( bytes_sent ) ;
2010-08-29 12:58:15 -04:00
}
2018-09-24 18:03:17 -03:00
InactivityCheck ( pnode ) ;
}
{
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodesCopy )
pnode - > Release ( ) ;
}
}
void CConnman : : ThreadSocketHandler ( )
{
while ( ! interruptNet )
{
DisconnectNodes ( ) ;
NotifyNumConnectionsChanged ( ) ;
SocketHandler ( ) ;
2010-08-29 12:58:15 -04:00
}
}
2016-12-31 04:05:21 -03:00
void CConnman : : WakeMessageHandler ( )
{
2016-12-31 04:05:26 -03:00
{
2019-05-29 23:44:02 -04:00
LOCK ( mutexMsgProc ) ;
2016-12-31 04:05:26 -03:00
fMsgProcWake = true ;
}
2016-12-31 04:05:21 -03:00
condMsgProc . notify_one ( ) ;
}
2010-08-29 12:58:15 -04:00
2011-03-26 09:01:27 -03:00
# ifdef USE_UPNP
2018-02-07 19:20:16 -03:00
static CThreadInterrupt g_upnp_interrupt ;
static std : : thread g_upnp_thread ;
2018-05-02 12:14:48 -03:00
static void ThreadMapPort ( )
2011-03-26 09:01:27 -03:00
{
2012-09-05 18:36:19 -03:00
std : : string port = strprintf ( " %u " , GetListenPort ( ) ) ;
2017-06-21 15:10:00 -04:00
const char * multicastif = nullptr ;
const char * minissdpdpath = nullptr ;
struct UPNPDev * devlist = nullptr ;
2011-03-26 09:01:27 -03:00
char lanaddr [ 64 ] ;
2011-12-10 13:52:50 -03:00
int error = 0 ;
2019-05-06 15:17:31 -04:00
# if MINIUPNPC_API_VERSION < 14
2011-08-11 18:20:07 -04:00
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 , 0 , & error ) ;
2015-08-23 17:53:49 -03:00
# else
devlist = upnpDiscover ( 2000 , multicastif , minissdpdpath , 0 , 0 , 2 , & error ) ;
2011-12-10 13:52:50 -03:00
# endif
2011-03-26 09:01:27 -03:00
struct UPNPUrls urls ;
struct IGDdatas data ;
int r ;
2011-04-16 15:35:45 -03:00
r = UPNP_GetValidIGD ( devlist , & urls , & data , lanaddr , sizeof ( lanaddr ) ) ;
if ( r = = 1 )
2011-03-26 09:01:27 -03:00
{
2012-05-24 13:02:21 -04:00
if ( fDiscover ) {
2012-02-10 00:41:42 -03:00
char externalIPAddress [ 40 ] ;
r = UPNP_GetExternalIPAddress ( urls . controlURL , data . first . servicetype , externalIPAddress ) ;
2019-05-06 16:17:51 -04:00
if ( r ! = UPNPCOMMAND_SUCCESS ) {
2013-09-18 07:38:08 -03:00
LogPrintf ( " UPnP: GetExternalIPAddress() returned %d \n " , r ) ;
2019-05-06 16:17:51 -04:00
} else {
if ( externalIPAddress [ 0 ] ) {
2016-05-31 13:05:52 -04:00
CNetAddr resolved ;
2019-05-06 16:17:51 -04:00
if ( LookupHost ( externalIPAddress , resolved , false ) ) {
2019-10-28 09:30:20 -03:00
LogPrintf ( " UPnP: ExternalIPAddress = %s \n " , resolved . ToString ( ) ) ;
2016-05-31 13:05:52 -04:00
AddLocal ( resolved , LOCAL_UPNP ) ;
}
2019-05-06 16:17:51 -04:00
} else {
2013-09-18 07:38:08 -03:00
LogPrintf ( " UPnP: GetExternalIPAddress failed. \n " ) ;
2019-05-06 16:17:51 -04:00
}
2012-02-10 00:41:42 -03:00
}
}
2019-05-06 15:58:10 -04:00
std : : string strDesc = PACKAGE_NAME " " + FormatFullVersion ( ) ;
2011-08-11 18:20:07 -04:00
2018-02-07 19:20:16 -03:00
do {
2019-05-06 16:17:51 -04:00
r = UPNP_AddPortMapping ( urls . controlURL , data . first . servicetype , port . c_str ( ) , port . c_str ( ) , lanaddr , strDesc . c_str ( ) , " TCP " , 0 , " 0 " ) ;
2012-01-31 19:36:25 -03:00
2019-05-06 16:17:51 -04:00
if ( r ! = UPNPCOMMAND_SUCCESS ) {
LogPrintf ( " AddPortMapping(%s, %s, %s) failed with code %d (%s) \n " , port , port , lanaddr , r , strupnperror ( r ) ) ;
} else {
2018-02-07 19:20:16 -03:00
LogPrintf ( " UPnP Port Mapping successful. \n " ) ;
2019-05-06 16:17:51 -04:00
}
} while ( g_upnp_interrupt . sleep_for ( std : : chrono : : minutes ( 20 ) ) ) ;
2018-02-07 19:20:16 -03:00
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 09:01:27 -03:00
} else {
2013-09-18 07:38:08 -03:00
LogPrintf ( " No valid UPnP IGDs found \n " ) ;
2017-06-21 15:10:00 -04:00
freeUPNPDevlist ( devlist ) ; devlist = nullptr ;
2011-04-16 15:35:45 -03:00
if ( r ! = 0 )
FreeUPNPUrls ( & urls ) ;
2011-03-26 09:01:27 -03:00
}
}
2018-02-07 19:20:16 -03:00
void StartMapPort ( )
2011-03-26 09:01:27 -03:00
{
2018-02-07 19:20:16 -03:00
if ( ! g_upnp_thread . joinable ( ) ) {
assert ( ! g_upnp_interrupt ) ;
g_upnp_thread = std : : thread ( ( std : : bind ( & TraceThread < void ( * ) ( ) > , " upnp " , & ThreadMapPort ) ) ) ;
}
}
2013-03-07 00:31:26 -03:00
2018-02-07 19:20:16 -03:00
void InterruptMapPort ( )
{
if ( g_upnp_thread . joinable ( ) ) {
g_upnp_interrupt ( ) ;
2013-03-07 00:31:26 -03:00
}
2018-02-07 19:20:16 -03:00
}
void StopMapPort ( )
{
if ( g_upnp_thread . joinable ( ) ) {
g_upnp_thread . join ( ) ;
g_upnp_interrupt . reset ( ) ;
2011-03-26 09:01:27 -03:00
}
}
2013-03-07 00:31:26 -03:00
2011-08-09 12:38:17 -04:00
# else
2018-02-07 19:20:16 -03:00
void StartMapPort ( )
{
// Intentionally left blank.
}
void InterruptMapPort ( )
{
// Intentionally left blank.
}
void StopMapPort ( )
2011-08-09 12:38:17 -04:00
{
// Intentionally left blank.
}
2011-03-26 09:01:27 -03:00
# endif
2016-04-16 15:47:18 -03:00
void CConnman : : ThreadDNSAddressSeed ( )
2011-11-21 14:25:00 -03:00
{
2019-03-07 20:30:59 -03:00
FastRandomContext rng ;
std : : vector < std : : string > seeds = Params ( ) . DNSSeeds ( ) ;
Shuffle ( seeds . begin ( ) , seeds . end ( ) , rng ) ;
int seeds_right_now = 0 ; // Number of seeds left before testing if we have enough connections
int found = 0 ;
2014-07-29 11:04:46 -04:00
2019-03-07 20:30:59 -03:00
if ( gArgs . GetBoolArg ( " -forcednsseed " , DEFAULT_FORCEDNSSEED ) ) {
// When -forcednsseed is provided, query all.
seeds_right_now = seeds . size ( ) ;
2020-02-11 00:20:21 -03:00
} else if ( addrman . size ( ) = = 0 ) {
// If we have no known peers, query all.
2020-05-27 20:07:49 -04:00
// This will occur on the first run, or if peers.dat has been
// deleted.
2020-02-11 00:20:21 -03:00
seeds_right_now = seeds . size ( ) ;
2014-07-29 11:04:46 -04:00
}
2020-02-11 00:20:21 -03:00
// goal: only query DNS seed if address need is acute
// * If we have a reasonable number of peers in addrman, spend
// some time trying them first. This 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.
// * When querying DNS seeds query a few at once, this ensures
// that we don't give DNS seeds the ability to eclipse nodes
// that query them.
// * If we continue having problems, eventually query all the
// DNS seeds, and if that fails too, also try the fixed seeds.
// (done in ThreadOpenConnections)
const std : : chrono : : seconds seeds_wait_time = ( addrman . size ( ) > = DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS ) ;
2019-03-07 20:30:59 -03:00
for ( const std : : string & seed : seeds ) {
2020-02-11 00:20:21 -03:00
if ( seeds_right_now = = 0 ) {
seeds_right_now + = DNSSEEDS_TO_QUERY_AT_ONCE ;
2011-03-09 00:40:50 -03:00
2020-02-11 00:20:21 -03:00
if ( addrman . size ( ) > 0 ) {
LogPrintf ( " Waiting %d seconds before querying DNS seeds. \n " , seeds_wait_time . count ( ) ) ;
std : : chrono : : seconds to_wait = seeds_wait_time ;
while ( to_wait . count ( ) > 0 ) {
2020-05-27 20:07:49 -04:00
// if sleeping for the MANY_PEERS interval, wake up
// early to see if we have enough peers and can stop
// this thread entirely freeing up its resources
2020-02-11 00:20:21 -03:00
std : : chrono : : seconds w = std : : min ( DNSSEEDS_DELAY_FEW_PEERS , to_wait ) ;
if ( ! interruptNet . sleep_for ( w ) ) return ;
to_wait - = w ;
int nRelevant = 0 ;
{
LOCK ( cs_vNodes ) ;
for ( const CNode * pnode : vNodes ) {
2020-07-20 17:24:48 -04:00
if ( pnode - > fSuccessfullyConnected & & pnode - > IsOutboundOrBlockRelayConn ( ) ) + + nRelevant ;
2020-02-11 00:20:21 -03:00
}
}
if ( nRelevant > = 2 ) {
if ( found > 0 ) {
LogPrintf ( " %d addresses found from DNS seeds \n " , found ) ;
LogPrintf ( " P2P peers available. Finished DNS seeding. \n " ) ;
} else {
LogPrintf ( " P2P peers available. Skipped DNS seeding. \n " ) ;
}
return ;
}
}
2019-03-07 20:30:59 -03:00
}
}
2013-01-30 01:13:17 -03:00
2020-02-11 12:32:46 -03:00
if ( interruptNet ) return ;
2020-05-27 20:07:49 -04:00
// hold off on querying seeds if P2P network deactivated
2020-02-11 12:32:46 -03:00
if ( ! fNetworkActive ) {
LogPrintf ( " Waiting for network to be reactivated before querying DNS seeds. \n " ) ;
do {
if ( ! interruptNet . sleep_for ( std : : chrono : : seconds { 1 } ) ) return ;
} while ( ! fNetworkActive ) ;
2017-04-14 17:29:57 -03:00
}
2020-02-11 00:20:21 -03:00
2019-03-07 20:30:59 -03:00
LogPrintf ( " Loading addresses from DNS seed %s \n " , seed ) ;
2013-01-30 01:13:17 -03:00
if ( HaveNameProxy ( ) ) {
2020-07-17 17:56:34 -04:00
AddAddrFetch ( seed ) ;
2013-01-30 01:13:17 -03:00
} else {
2016-04-15 20:53:45 -03:00
std : : vector < CNetAddr > vIPs ;
std : : vector < CAddress > vAdd ;
2017-10-04 18:59:30 -03:00
ServiceFlags requiredServiceBits = GetDesirableServiceFlags ( NODE_NONE ) ;
2017-10-19 18:32:45 -03:00
std : : string host = strprintf ( " x%x.%s " , requiredServiceBits , seed ) ;
2017-05-23 20:48:08 -04:00
CNetAddr resolveSource ;
if ( ! resolveSource . SetInternal ( host ) ) {
continue ;
}
2018-03-06 20:26:29 -03:00
unsigned int nMaxIPs = 256 ; // Limits number of IPs learned from a DNS seed
2019-12-11 13:39:29 -03:00
if ( LookupHost ( host , vIPs , nMaxIPs , true ) ) {
2019-03-07 20:30:59 -03:00
for ( const CNetAddr & ip : vIPs ) {
2013-01-30 01:13:17 -03:00
int nOneDay = 24 * 3600 ;
2016-05-21 17:55:22 -04:00
CAddress addr = CAddress ( CService ( ip , Params ( ) . GetDefaultPort ( ) ) , requiredServiceBits ) ;
2019-03-07 20:30:59 -03:00
addr . nTime = GetTime ( ) - 3 * nOneDay - rng . randrange ( 4 * nOneDay ) ; // use a random age between 3 and 7 days old
2013-01-30 01:13:17 -03:00
vAdd . push_back ( addr ) ;
found + + ;
2011-05-02 10:34:42 -03:00
}
2017-05-23 20:48:08 -04:00
addrman . Add ( vAdd , resolveSource ) ;
2017-10-19 18:32:45 -03:00
} else {
// We now avoid directly using results from DNS Seeds which do not support service bit filtering,
2020-07-17 17:56:34 -04:00
// instead using them as a addrfetch to get nodes with our desired service bits.
AddAddrFetch ( seed ) ;
2016-04-12 21:38:06 -03:00
}
2011-03-09 00:40:50 -03:00
}
2019-03-07 20:30:59 -03:00
- - seeds_right_now ;
2011-03-09 00:40:50 -03:00
}
2013-09-18 07:38:08 -03:00
LogPrintf ( " %d addresses found from DNS seeds \n " , found ) ;
2011-03-09 00:40:50 -03:00
}
2010-08-29 12:58:15 -04:00
2016-04-16 18:43:11 -03:00
void CConnman : : DumpAddresses ( )
2012-01-04 19:39:45 -03:00
{
2013-04-13 02:13:08 -03:00
int64_t nStart = GetTimeMillis ( ) ;
2012-05-16 22:11:19 -04:00
2012-01-04 19:39:45 -03:00
CAddrDB adb ;
2012-05-16 22:11:19 -04:00
adb . Write ( addrman ) ;
2016-12-25 17:19:40 -03:00
LogPrint ( BCLog : : NET , " Flushed %d addresses to peers.dat %dms \n " ,
2012-05-16 22:11:19 -04:00
addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
2012-01-04 19:39:45 -03:00
}
2010-08-29 12:58:15 -04:00
2020-07-17 17:56:34 -04:00
void CConnman : : ProcessAddrFetch ( )
2012-04-23 21:15:00 -03:00
{
2016-04-15 20:53:45 -03:00
std : : string strDest ;
2012-04-23 21:15:00 -03:00
{
2020-07-17 17:56:34 -04:00
LOCK ( m_addr_fetches_mutex ) ;
if ( m_addr_fetches . empty ( ) )
2012-04-23 21:15:00 -03:00
return ;
2020-07-17 17:56:34 -04:00
strDest = m_addr_fetches . front ( ) ;
m_addr_fetches . pop_front ( ) ;
2012-04-23 21:15:00 -03:00
}
CAddress addr ;
2012-05-10 12:44:07 -04:00
CSemaphoreGrant grant ( * semOutbound , true ) ;
if ( grant ) {
2020-04-30 13:57:03 -04:00
OpenNetworkConnection ( addr , false , & grant , strDest . c_str ( ) , ConnectionType : : ADDR_FETCH ) ;
2012-05-10 12:44:07 -04:00
}
2012-04-23 21:15:00 -03:00
}
2017-10-23 14:36:15 -03:00
bool CConnman : : GetTryNewOutboundPeer ( )
{
return m_try_another_outbound_peer ;
}
void CConnman : : SetTryNewOutboundPeer ( bool flag )
{
m_try_another_outbound_peer = flag ;
2017-10-24 17:56:07 -03:00
LogPrint ( BCLog : : NET , " net: setting try another outbound peer=%s \n " , flag ? " true " : " false " ) ;
2017-10-23 14:36:15 -03: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
2020-09-15 04:29:20 -03:00
// disconnected soon (eg ADDR_FETCH and FEELER)
2017-10-23 14:36:15 -03:00
// 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)
2020-09-01 16:32:09 -04:00
int CConnman : : GetExtraFullOutboundCount ( )
2017-10-23 14:36:15 -03:00
{
2020-09-01 16:32:09 -04:00
int full_outbound_peers = 0 ;
2017-10-23 14:36:15 -03:00
{
LOCK ( cs_vNodes ) ;
2018-06-18 01:58:28 -04:00
for ( const CNode * pnode : vNodes ) {
2020-09-01 16:32:09 -04:00
if ( pnode - > fSuccessfullyConnected & & ! pnode - > fDisconnect & & pnode - > IsFullOutboundConn ( ) ) {
+ + full_outbound_peers ;
2017-10-23 14:36:15 -03:00
}
}
}
2020-09-01 16:32:09 -04:00
return std : : max ( full_outbound_peers - m_max_outbound_full_relay , 0 ) ;
2017-10-23 14:36:15 -03:00
}
2020-09-01 17:05:47 -04:00
int CConnman : : GetExtraBlockRelayCount ( )
{
int block_relay_peers = 0 ;
{
LOCK ( cs_vNodes ) ;
for ( const CNode * pnode : vNodes ) {
if ( pnode - > fSuccessfullyConnected & & ! pnode - > fDisconnect & & pnode - > IsBlockOnlyConn ( ) ) {
+ + block_relay_peers ;
}
}
}
return std : : max ( block_relay_peers - m_max_outbound_block_relay , 0 ) ;
}
2017-06-15 03:39:07 -04:00
void CConnman : : ThreadOpenConnections ( const std : : vector < std : : string > connect )
2010-08-29 12:58:15 -04:00
{
// Connect to specific addresses
2017-06-15 03:39:07 -04:00
if ( ! connect . empty ( ) )
2010-08-29 12:58:15 -04:00
{
2013-04-13 02:13:08 -03:00
for ( int64_t nLoop = 0 ; ; nLoop + + )
2010-08-29 12:58:15 -04:00
{
2020-07-17 17:56:34 -04:00
ProcessAddrFetch ( ) ;
2017-06-15 03:39:07 -04:00
for ( const std : : string & strAddr : connect )
2010-08-29 12:58:15 -04:00
{
2016-06-08 13:12:22 -04:00
CAddress addr ( CService ( ) , NODE_NONE ) ;
2020-04-30 13:57:03 -04:00
OpenNetworkConnection ( addr , false , nullptr , strAddr . c_str ( ) , ConnectionType : : MANUAL ) ;
2010-08-29 12:58:15 -04:00
for ( int i = 0 ; i < 10 & & i < nLoop ; i + + )
{
2016-12-27 19:12:44 -03:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2010-08-29 12:58:15 -04:00
}
}
2016-12-27 19:12:44 -03:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2010-08-29 12:58:15 -04:00
}
}
// Initiate network connections
2013-04-13 02:13:08 -03:00
int64_t nStart = GetTime ( ) ;
2016-06-17 00:10:07 -04:00
// Minimum time before next feeler connection (in microseconds).
int64_t nNextFeeler = PoissonNextSend ( nStart * 1000 * 1000 , FEELER_INTERVAL ) ;
2020-09-01 17:05:47 -04:00
int64_t nNextExtraBlockRelay = PoissonNextSend ( nStart * 1000 * 1000 , EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL ) ;
2016-12-27 19:12:44 -03:00
while ( ! interruptNet )
2010-08-29 12:58:15 -04:00
{
2020-07-17 17:56:34 -04:00
ProcessAddrFetch ( ) ;
2012-04-23 21:15:00 -03:00
2016-12-27 19:12:44 -03:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2012-02-15 17:17:15 -03:00
2012-05-10 12:44:07 -04:00
CSemaphoreGrant grant ( * semOutbound ) ;
2016-12-27 19:12:44 -03:00
if ( interruptNet )
return ;
2010-08-29 12:58:15 -04:00
2013-05-07 09:16:25 -04:00
// Add seed nodes if DNS seeds are all down (an infrastructure attack?).
2020-05-27 20:07:49 -04:00
// Note that we only do this if we started with an empty peers.dat,
// (in which case we will query DNS seeds immediately) *and* the DNS
// seeds have not returned any results.
2013-05-07 09:16:25 -04:00
if ( addrman . size ( ) = = 0 & & ( GetTime ( ) - nStart > 60 ) ) {
static bool done = false ;
if ( ! done ) {
2013-09-18 07:38:08 -03:00
LogPrintf ( " Adding fixed seed nodes as DNS doesn't seem to be available. \n " ) ;
2016-05-31 13:05:52 -04:00
CNetAddr local ;
2017-06-21 15:45:20 -04:00
local . SetInternal ( " fixedseeds " ) ;
2016-05-31 13:05:52 -04:00
addrman . Add ( convertSeed6 ( Params ( ) . FixedSeeds ( ) ) , local ) ;
2013-05-07 09:16:25 -04:00
done = true ;
2010-08-29 12:58:15 -04:00
}
}
//
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect ;
2012-07-01 20:23:26 -04:00
// Only connect out to one peer per network group (/16 for IPv4).
2019-03-09 14:55:06 -03:00
int nOutboundFullRelay = 0 ;
int nOutboundBlockRelay = 0 ;
2016-04-15 20:53:45 -03:00
std : : set < std : : vector < unsigned char > > setConnected ;
2020-06-03 00:23:44 -04:00
2012-04-06 13:39:12 -03:00
{
LOCK ( cs_vNodes ) ;
2018-06-18 01:58:28 -04:00
for ( const CNode * pnode : vNodes ) {
2020-06-03 00:23:44 -04:00
if ( pnode - > IsFullOutboundConn ( ) ) nOutboundFullRelay + + ;
if ( pnode - > IsBlockOnlyConn ( ) ) nOutboundBlockRelay + + ;
// Netgroups for inbound and manual 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 manual peers do not use our outbound slots. Inbound peers
// also have the added issue that they could be attacker controlled and used
// to prevent us from connecting to particular hosts if we used them here.
2020-08-11 13:36:42 -04:00
switch ( pnode - > m_conn_type ) {
2020-06-03 00:23:44 -04:00
case ConnectionType : : INBOUND :
case ConnectionType : : MANUAL :
break ;
2020-08-11 23:37:32 -04:00
case ConnectionType : : OUTBOUND_FULL_RELAY :
2020-06-03 00:23:44 -04:00
case ConnectionType : : BLOCK_RELAY :
case ConnectionType : : ADDR_FETCH :
case ConnectionType : : FEELER :
setConnected . insert ( pnode - > addr . GetGroup ( addrman . m_asmap ) ) ;
2020-08-20 18:26:27 -04:00
} // no default case, so the compiler can warn about missing cases
2012-05-10 12:44:07 -04:00
}
2012-04-06 13:39:12 -03:00
}
2010-08-29 12:58:15 -04:00
2020-08-14 00:54:38 -04:00
ConnectionType conn_type = ConnectionType : : OUTBOUND_FULL_RELAY ;
int64_t nTime = GetTimeMicros ( ) ;
2020-06-05 02:38:09 -04:00
bool anchor = false ;
2016-06-17 00:10:07 -04:00
bool fFeeler = false ;
2017-10-23 14:36:15 -03:00
2020-08-14 00:54:38 -04:00
// Determine what type of connection to open. Opening
2020-06-05 02:38:09 -04:00
// BLOCK_RELAY connections to addresses from anchors.dat gets the highest
// priority. Then we open OUTBOUND_FULL_RELAY priority until we
2020-08-14 00:54:38 -04:00
// meet our full-relay capacity. Then we open BLOCK_RELAY connection
// until we hit our block-relay-only peer limit.
// GetTryNewOutboundPeer() gets set when a stale tip is detected, so we
// try opening an additional OUTBOUND_FULL_RELAY connection. If none of
2020-09-01 17:05:47 -04:00
// these conditions are met, check to see if it's time to try an extra
// block-relay-only peer (to confirm our tip is current, see below) or the nNextFeeler
// timer to decide if we should open a FEELER.
2020-08-14 00:54:38 -04:00
2020-06-05 02:38:09 -04:00
if ( ! m_anchors . empty ( ) & & ( nOutboundBlockRelay < m_max_outbound_block_relay ) ) {
conn_type = ConnectionType : : BLOCK_RELAY ;
anchor = true ;
} else if ( nOutboundFullRelay < m_max_outbound_full_relay ) {
2020-08-14 00:54:38 -04:00
// OUTBOUND_FULL_RELAY
} else if ( nOutboundBlockRelay < m_max_outbound_block_relay ) {
conn_type = ConnectionType : : BLOCK_RELAY ;
} else if ( GetTryNewOutboundPeer ( ) ) {
// OUTBOUND_FULL_RELAY
2020-09-01 17:05:47 -04:00
} else if ( nTime > nNextExtraBlockRelay & & m_start_extra_block_relay_peers ) {
// Periodically connect to a peer (using regular outbound selection
// methodology from addrman) and stay connected long enough to sync
// headers, but not much else.
//
// Then disconnect the peer, if we haven't learned anything new.
//
// The idea is to make eclipse attacks very difficult to pull off,
// because every few minutes we're finding a new peer to learn headers
// from.
//
// This is similar to the logic for trying extra outbound (full-relay)
// peers, except:
// - we do this all the time on a poisson timer, rather than just when
// our tip is stale
// - we potentially disconnect our next-youngest block-relay-only peer, if our
// newest block-relay-only peer delivers a block more recently.
// See the eviction logic in net_processing.cpp.
//
// Because we can promote these connections to block-relay-only
// connections, they do not get their own ConnectionType enum
// (similar to how we deal with extra outbound peers).
nNextExtraBlockRelay = PoissonNextSend ( nTime , EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL ) ;
conn_type = ConnectionType : : BLOCK_RELAY ;
2020-08-14 00:54:38 -04:00
} else if ( nTime > nNextFeeler ) {
nNextFeeler = PoissonNextSend ( nTime , FEELER_INTERVAL ) ;
conn_type = ConnectionType : : FEELER ;
fFeeler = true ;
} else {
// skip to next iteration of while loop
continue ;
2016-06-17 00:10:07 -04:00
}
2011-10-04 00:41:47 -03:00
2016-10-27 14:55:39 -03:00
addrman . ResolveCollisions ( ) ;
2016-06-17 00:10:07 -04:00
int64_t nANow = GetAdjustedTime ( ) ;
2012-01-04 19:39:45 -03:00
int nTries = 0 ;
2016-12-27 19:12:44 -03:00
while ( ! interruptNet )
2010-08-29 12:58:15 -04:00
{
2020-06-05 02:38:09 -04:00
if ( anchor & & ! m_anchors . empty ( ) ) {
const CAddress addr = m_anchors . back ( ) ;
m_anchors . pop_back ( ) ;
if ( ! addr . IsValid ( ) | | IsLocal ( addr ) | | ! IsReachable ( addr ) | |
! HasAllDesirableServiceFlags ( addr . nServices ) | |
setConnected . count ( addr . GetGroup ( addrman . m_asmap ) ) ) continue ;
addrConnect = addr ;
LogPrint ( BCLog : : NET , " Trying to make an anchor connection to %s \n " , addrConnect . ToString ( ) ) ;
break ;
}
2020-09-12 12:17:49 -03: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.
nTries + + ;
if ( nTries > 100 )
break ;
2020-10-16 15:05:09 -03:00
CAddrInfo addr ;
if ( fFeeler ) {
// First, try to get a tried table collision address. This returns
// an empty (invalid) address if there are no collisions to try.
addr = addrman . SelectTriedCollision ( ) ;
if ( ! addr . IsValid ( ) ) {
// No tried table collisions. Select a new table address
// for our feeler.
addr = addrman . Select ( true ) ;
} else if ( AlreadyConnectedToAddress ( addr ) ) {
// If test-before-evict logic would have us connect to a
// peer that we're already connected to, just mark that
// address as Good(). We won't be able to initiate the
// connection anyway, so this avoids inadvertently evicting
// a currently-connected peer.
addrman . Good ( addr ) ;
// Select a new table address for our feeler instead.
addr = addrman . Select ( true ) ;
}
} else {
// Not a feeler
addr = addrman . Select ( ) ;
2016-10-27 14:55:39 -03:00
}
2010-08-29 12:58:15 -04:00
2019-03-01 18:15:50 -03:00
// Require outbound connections, other than feelers, to be to distinct network groups
2019-12-24 15:18:44 -03:00
if ( ! fFeeler & & setConnected . count ( addr . GetGroup ( addrman . m_asmap ) ) ) {
2019-02-26 17:04:48 -03:00
break ;
}
2019-03-01 18:15:50 -03:00
// if we selected an invalid or local address, restart
2019-02-26 17:04:48 -03:00
if ( ! addr . IsValid ( ) | | IsLocal ( addr ) ) {
2012-01-04 19:39:45 -03:00
break ;
2019-02-26 17:04:48 -03:00
}
2010-08-29 12:58:15 -04:00
2019-01-09 21:41:37 -03:00
if ( ! IsReachable ( addr ) )
2012-05-04 10:46:22 -04:00
continue ;
2012-01-04 19:39:45 -03:00
// only consider very recently tried nodes after 30 failed attempts
if ( nANow - addr . nLastTry < 600 & & nTries < 30 )
continue ;
2017-10-04 18:59:30 -03: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-16 20:20:49 -03:00
continue ;
2017-05-24 17:00:27 -04:00
}
2015-11-16 20:20:49 -03:00
2020-12-15 22:37:32 -03:00
// Do not allow non-default ports, unless after 50 invalid
// addresses selected already. This is to prevent malicious peers
// from advertising themselves as a service on another host and
// port, causing a DoS attack as nodes around the network attempt
// to connect to it fruitlessly.
2013-05-07 09:16:25 -04:00
if ( addr . GetPort ( ) ! = Params ( ) . GetDefaultPort ( ) & & nTries < 50 )
2012-01-04 19:39:45 -03:00
continue ;
addrConnect = addr ;
break ;
2010-08-29 12:58:15 -04:00
}
2016-06-17 00:10:07 -04: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 19:12:44 -03:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( randsleep ) ) )
return ;
2016-12-25 17:19:40 -03:00
LogPrint ( BCLog : : NET , " Making feeler connection to %s \n " , addrConnect . ToString ( ) ) ;
2016-06-17 00:10:07 -04:00
}
2020-04-30 13:57:03 -04:00
OpenNetworkConnection ( addrConnect , ( int ) setConnected . size ( ) > = std : : min ( nMaxConnections - 1 , 2 ) , & grant , nullptr , conn_type ) ;
2016-06-17 00:10:07 -04:00
}
2010-08-29 12:58:15 -04:00
}
}
2020-09-12 12:03:06 -03:00
std : : vector < CAddress > CConnman : : GetCurrentBlockRelayOnlyConns ( ) const
{
std : : vector < CAddress > ret ;
LOCK ( cs_vNodes ) ;
for ( const CNode * pnode : vNodes ) {
if ( pnode - > IsBlockOnlyConn ( ) ) {
ret . push_back ( pnode - > addr ) ;
}
}
return ret ;
}
2016-04-16 19:12:58 -03:00
std : : vector < AddedNodeInfo > CConnman : : GetAddedNodeInfo ( )
2011-12-16 21:48:03 -03:00
{
2016-05-28 09:32:30 -04:00
std : : vector < AddedNodeInfo > ret ;
std : : list < std : : string > lAddresses ( 0 ) ;
2012-07-02 13:55:16 -04:00
{
LOCK ( cs_vAddedNodes ) ;
2016-05-28 09:32:30 -04:00
ret . reserve ( vAddedNodes . size ( ) ) ;
2017-07-20 05:32:47 -04:00
std : : copy ( vAddedNodes . cbegin ( ) , vAddedNodes . cend ( ) , std : : back_inserter ( lAddresses ) ) ;
2012-07-02 13:55:16 -04:00
}
2011-12-16 21:48:03 -03:00
2016-05-28 09:32:30 -04: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 ( ) ) {
2020-07-28 16:39:38 -04:00
mapConnected [ pnode - > addr ] = pnode - > IsInboundConn ( ) ;
2012-07-02 13:55:16 -04:00
}
2017-02-06 14:04:34 -03:00
std : : string addrName = pnode - > GetAddrName ( ) ;
if ( ! addrName . empty ( ) ) {
2020-07-28 16:39:38 -04:00
mapConnectedByName [ std : : move ( addrName ) ] = std : : make_pair ( pnode - > IsInboundConn ( ) , static_cast < const CService & > ( pnode - > addr ) ) ;
2012-04-19 12:38:03 -03:00
}
}
}
2017-06-01 21:18:57 -04:00
for ( const std : : string & strAddNode : lAddresses ) {
2019-12-11 13:39:29 -03:00
CService service ( LookupNumeric ( strAddNode , Params ( ) . GetDefaultPort ( ) ) ) ;
2018-01-26 07:48:56 -03:00
AddedNodeInfo addedNode { strAddNode , CService ( ) , false , false } ;
2016-05-28 09:32:30 -04:00
if ( service . IsValid ( ) ) {
// strAddNode is an IP:port
auto it = mapConnected . find ( service ) ;
if ( it ! = mapConnected . end ( ) ) {
2018-01-26 07:48:56 -03:00
addedNode . resolvedAddress = service ;
addedNode . fConnected = true ;
addedNode . fInbound = it - > second ;
2016-05-28 09:32:30 -04:00
}
} else {
// strAddNode is a name
auto it = mapConnectedByName . find ( strAddNode ) ;
if ( it ! = mapConnectedByName . end ( ) ) {
2018-01-26 07:48:56 -03:00
addedNode . resolvedAddress = it - > second . second ;
addedNode . fConnected = true ;
addedNode . fInbound = it - > second . first ;
2012-04-19 12:38:03 -03:00
}
}
2018-01-26 07:48:56 -03:00
ret . emplace_back ( std : : move ( addedNode ) ) ;
2012-04-19 12:38:03 -03:00
}
2016-05-28 09:32:30 -04:00
return ret ;
}
2016-04-16 15:47:18 -03:00
void CConnman : : ThreadOpenAddedConnections ( )
2016-05-28 09:32:30 -04:00
{
2016-12-11 01:39:26 -03:00
while ( true )
2011-12-16 21:48:03 -03:00
{
2016-12-11 01:39:26 -03:00
CSemaphoreGrant grant ( * semAddnode ) ;
2016-05-28 09:32:30 -04:00
std : : vector < AddedNodeInfo > vInfo = GetAddedNodeInfo ( ) ;
2016-12-11 01:39:26 -03:00
bool tried = false ;
2016-05-28 09:32:30 -04:00
for ( const AddedNodeInfo & info : vInfo ) {
if ( ! info . fConnected ) {
2016-12-11 01:39:26 -03:00
if ( ! grant . TryAcquire ( ) ) {
2018-03-18 11:26:45 -03:00
// If we've used up our semaphore and need a new one, let's not wait here since while we are waiting
2016-12-11 01:39:26 -03:00
// the addednodeinfo state might change.
break ;
}
tried = true ;
2017-06-23 12:29:50 -04:00
CAddress addr ( CService ( ) , NODE_NONE ) ;
2020-04-30 13:57:03 -04:00
OpenNetworkConnection ( addr , false , & grant , info . strAddedNode . c_str ( ) , ConnectionType : : MANUAL ) ;
2016-12-27 19:12:44 -03:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2016-05-28 09:32:30 -04:00
}
2012-07-02 13:55:16 -04:00
}
2016-12-11 01:39:26 -03:00
// Retry every 60 seconds if a connection was attempted, otherwise two seconds
2017-01-07 14:49:14 -03:00
if ( ! interruptNet . sleep_for ( std : : chrono : : seconds ( tried ? 60 : 2 ) ) )
2016-12-27 19:12:44 -03:00
return ;
2011-12-16 21:48:03 -03:00
}
}
2012-07-25 20:48:39 -04:00
// if successful, this moves the passed grant to the constructed node
2020-04-30 13:57:03 -04:00
void CConnman : : OpenNetworkConnection ( const CAddress & addrConnect , bool fCountFailure , CSemaphoreGrant * grantOutbound , const char * pszDest , ConnectionType conn_type )
2010-08-29 12:58:15 -04:00
{
2020-04-29 17:55:59 -04:00
assert ( conn_type ! = ConnectionType : : INBOUND ) ;
2010-08-29 12:58:15 -04:00
//
// Initiate outbound network connection
//
2016-12-27 19:12:44 -03:00
if ( interruptNet ) {
2018-02-01 16:04:49 -03:00
return ;
2016-12-27 19:12:44 -03:00
}
2013-03-25 22:33:25 -03:00
if ( ! fNetworkActive ) {
2018-02-01 16:04:49 -03:00
return ;
2013-03-25 22:33:25 -03:00
}
2014-05-24 05:14:52 -04:00
if ( ! pszDest ) {
2020-06-10 20:11:38 -04:00
bool banned_or_discouraged = m_banman & & ( m_banman - > IsDiscouraged ( addrConnect ) | | m_banman - > IsBanned ( addrConnect ) ) ;
2020-10-16 12:10:17 -03:00
if ( IsLocal ( addrConnect ) | | banned_or_discouraged | | AlreadyConnectedToAddress ( addrConnect ) ) {
2018-02-01 16:04:49 -03:00
return ;
2020-06-10 20:11:38 -04:00
}
2015-05-31 10:44:22 -03:00
} else if ( FindNode ( std : : string ( pszDest ) ) )
2018-02-01 16:04:49 -03:00
return ;
2010-08-29 12:58:15 -04:00
2020-04-29 20:33:06 -04:00
CNode * pnode = ConnectNode ( addrConnect , pszDest , fCountFailure , conn_type ) ;
2013-03-07 00:31:26 -03:00
2010-08-29 12:58:15 -04:00
if ( ! pnode )
2018-02-01 16:04:49 -03:00
return ;
2012-05-10 12:44:07 -04:00
if ( grantOutbound )
grantOutbound - > MoveTo ( pnode - > grantOutbound ) ;
2010-08-29 12:58:15 -04:00
2017-07-06 14:08:23 -04:00
m_msgproc - > InitializeNode ( pnode ) ;
2017-01-24 18:51:22 -03:00
{
LOCK ( cs_vNodes ) ;
vNodes . push_back ( pnode ) ;
}
2010-08-29 12:58:15 -04:00
}
2016-04-16 15:47:18 -03:00
void CConnman : : ThreadMessageHandler ( )
2010-08-29 12:58:15 -04:00
{
2016-12-27 19:12:44 -03:00
while ( ! flagInterruptMsgProc )
2010-08-29 12:58:15 -04:00
{
2016-04-15 20:53:45 -03:00
std : : vector < CNode * > vNodesCopy ;
2010-08-29 12:58:15 -04:00
{
2012-04-06 13:39:12 -03:00
LOCK ( cs_vNodes ) ;
2010-08-29 12:58:15 -04:00
vNodesCopy = vNodes ;
2017-06-01 21:18:57 -04:00
for ( CNode * pnode : vNodesCopy ) {
2010-08-29 12:58:15 -04:00
pnode - > AddRef ( ) ;
2013-04-04 19:43:04 -03:00
}
2010-08-29 12:58:15 -04:00
}
2016-12-31 04:05:26 -03:00
bool fMoreWork = false ;
2013-11-15 08:24:34 -03:00
2017-06-01 21:18:57 -04:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 12:58:15 -04:00
{
2013-02-28 21:41:28 -03:00
if ( pnode - > fDisconnect )
continue ;
2010-08-29 12:58:15 -04:00
// Receive messages
2017-07-06 14:08:23 -04:00
bool fMoreNodeWork = m_msgproc - > ProcessMessages ( pnode , flagInterruptMsgProc ) ;
2016-12-31 04:05:36 -03:00
fMoreWork | = ( fMoreNodeWork & & ! pnode - > fPauseSend ) ;
2016-12-27 19:12:44 -03:00
if ( flagInterruptMsgProc )
return ;
2010-08-29 12:58:15 -04:00
// Send messages
2012-04-06 13:39:12 -03:00
{
2017-01-13 01:08:52 -03:00
LOCK ( pnode - > cs_sendProcessing ) ;
2018-07-01 22:26:47 -04:00
m_msgproc - > SendMessages ( pnode ) ;
2012-04-06 13:39:12 -03:00
}
2017-07-06 13:40:09 -04:00
2016-12-27 19:12:44 -03:00
if ( flagInterruptMsgProc )
return ;
2010-08-29 12:58:15 -04:00
}
{
2012-04-06 13:39:12 -03:00
LOCK ( cs_vNodes ) ;
2017-06-01 21:18:57 -04:00
for ( CNode * pnode : vNodesCopy )
2010-08-29 12:58:15 -04:00
pnode - > Release ( ) ;
}
2013-11-15 08:24:34 -03:00
2017-11-08 19:07:40 -03:00
WAIT_LOCK ( mutexMsgProc , lock ) ;
2016-12-31 04:05:26 -03:00
if ( ! fMoreWork ) {
2019-05-29 23:44:02 -04:00
condMsgProc . wait_until ( lock , std : : chrono : : steady_clock : : now ( ) + std : : chrono : : milliseconds ( 100 ) , [ this ] ( ) EXCLUSIVE_LOCKS_REQUIRED ( mutexMsgProc ) { return fMsgProcWake ; } ) ;
2016-12-27 19:12:44 -03:00
}
2016-12-31 04:05:26 -03:00
fMsgProcWake = false ;
2010-08-29 12:58:15 -04:00
}
}
2020-04-11 11:47:17 -04:00
bool CConnman : : BindListenPort ( const CService & addrBind , bilingual_str & strError , NetPermissionFlags permissions )
2010-08-29 12:58:15 -04:00
{
int nOne = 1 ;
// Create socket for listening for incoming connections
2012-05-11 09:28:59 -04:00
struct sockaddr_storage sockaddr ;
socklen_t len = sizeof ( sockaddr ) ;
if ( ! addrBind . GetSockAddr ( ( struct sockaddr * ) & sockaddr , & len ) )
{
2020-04-11 11:47:17 -04:00
strError = strprintf ( Untranslated ( " Error: Bind address family for %s not supported " ) , addrBind . ToString ( ) ) ;
LogPrintf ( " %s \n " , strError . original ) ;
2012-05-11 09:28:59 -04:00
return false ;
}
2017-10-02 17:31:37 -03:00
SOCKET hListenSocket = CreateSocket ( addrBind ) ;
2010-08-29 12:58:15 -04:00
if ( hListenSocket = = INVALID_SOCKET )
{
2020-04-11 11:47:17 -04:00
strError = strprintf ( Untranslated ( " Error: Couldn't open socket for incoming connections (socket returned error %s) " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
LogPrintf ( " %s \n " , strError . original ) ;
2010-08-29 12:58:15 -04:00
return false ;
}
2018-01-26 07:48:56 -03:00
2010-08-29 12:58:15 -04:00
// Allow binding if the port is still in TIME_WAIT state after
2015-08-20 16:50:13 -03:00
// the program was closed and restarted.
2018-01-26 07:48:56 -03:00
setsockopt ( hListenSocket , SOL_SOCKET , SO_REUSEADDR , ( sockopt_arg_type ) & nOne , sizeof ( int ) ) ;
2010-08-29 12:58:15 -04:00
2012-05-11 09:28:59 -04: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
2018-01-26 07:48:56 -03:00
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( sockopt_arg_type ) & nOne , sizeof ( int ) ) ;
2013-07-13 07:05:04 -04:00
# endif
2012-05-11 09:28:59 -04:00
# ifdef WIN32
2014-06-24 03:03:18 -04:00
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED ;
setsockopt ( hListenSocket , IPPROTO_IPV6 , IPV6_PROTECTION_LEVEL , ( const char * ) & nProtLevel , sizeof ( int ) ) ;
2012-05-11 09:28:59 -04:00
# endif
}
if ( : : bind ( hListenSocket , ( struct sockaddr * ) & sockaddr , len ) = = SOCKET_ERROR )
2010-08-29 12:58:15 -04:00
{
int nErr = WSAGetLastError ( ) ;
if ( nErr = = WSAEADDRINUSE )
2020-04-11 11:47:17 -04:00
strError = strprintf ( _ ( " Unable to bind to %s on this computer. %s is probably already running. " ) , addrBind . ToString ( ) , PACKAGE_NAME ) ;
2010-08-29 12:58:15 -04:00
else
2020-04-11 11:47:17 -04:00
strError = strprintf ( _ ( " Unable to bind to %s on this computer (bind returned error %s) " ) , addrBind . ToString ( ) , NetworkErrorString ( nErr ) ) ;
LogPrintf ( " %s \n " , strError . original ) ;
2014-07-17 16:33:58 -04:00
CloseSocket ( hListenSocket ) ;
2010-08-29 12:58:15 -04:00
return false ;
}
2014-01-16 12:15:27 -03:00
LogPrintf ( " Bound to %s \n " , addrBind . ToString ( ) ) ;
2010-08-29 12:58:15 -04:00
// Listen for incoming connections
if ( listen ( hListenSocket , SOMAXCONN ) = = SOCKET_ERROR )
{
2020-04-11 11:47:17 -04:00
strError = strprintf ( _ ( " Error: Listening for incoming connections failed (listen returned error %s) " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
LogPrintf ( " %s \n " , strError . original ) ;
2014-07-17 16:33:58 -04:00
CloseSocket ( hListenSocket ) ;
2010-08-29 12:58:15 -04:00
return false ;
}
2019-06-20 05:37:51 -04:00
vhListenSocket . push_back ( ListenSocket ( hListenSocket , permissions ) ) ;
2010-08-29 12:58:15 -04:00
return true ;
}
2018-02-07 19:42:39 -03:00
void Discover ( )
2010-08-29 12:58:15 -04:00
{
2012-05-24 13:02:21 -04:00
if ( ! fDiscover )
2012-02-19 16:44:35 -03:00
return ;
2010-08-29 12:58:15 -04:00
2011-10-07 12:02:21 -03:00
# ifdef WIN32
2012-07-25 20:48:39 -04:00
// Get local host IP
2014-11-13 11:23:15 -03:00
char pszHostName [ 256 ] = " " ;
2010-08-29 12:58:15 -04:00
if ( gethostname ( pszHostName , sizeof ( pszHostName ) ) ! = SOCKET_ERROR )
{
2016-04-15 20:53:45 -03:00
std : : vector < CNetAddr > vaddr ;
2016-04-12 21:23:16 -03:00
if ( LookupHost ( pszHostName , vaddr , 0 , true ) )
2012-04-30 19:44:59 -04:00
{
2017-06-01 21:18:57 -04:00
for ( const CNetAddr & addr : vaddr )
2012-04-30 19:44:59 -04:00
{
2014-11-13 11:20:57 -03:00
if ( AddLocal ( addr , LOCAL_IF ) )
LogPrintf ( " %s: %s - %s \n " , __func__ , pszHostName , addr . ToString ( ) ) ;
2012-04-30 19:44:59 -04:00
}
}
2010-08-29 12:58:15 -04:00
}
2018-07-19 14:21:05 -04:00
# elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS)
2010-08-29 12:58:15 -04:00
// Get local host ip
struct ifaddrs * myaddrs ;
if ( getifaddrs ( & myaddrs ) = = 0 )
{
2017-08-07 01:36:37 -04:00
for ( struct ifaddrs * ifa = myaddrs ; ifa ! = nullptr ; ifa = ifa - > ifa_next )
2010-08-29 12:58:15 -04:00
{
2017-08-07 01:36:37 -04:00
if ( ifa - > ifa_addr = = nullptr ) continue ;
2010-08-29 12:58:15 -04: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 09:45:24 -03:00
CNetAddr addr ( s4 - > sin_addr ) ;
2012-03-31 12:58:25 -03:00
if ( AddLocal ( addr , LOCAL_IF ) )
2014-11-13 11:20:57 -03:00
LogPrintf ( " %s: IPv4 %s: %s \n " , __func__ , ifa - > ifa_name , addr . ToString ( ) ) ;
2010-08-29 12:58:15 -04:00
}
else if ( ifa - > ifa_addr - > sa_family = = AF_INET6 )
{
struct sockaddr_in6 * s6 = ( struct sockaddr_in6 * ) ( ifa - > ifa_addr ) ;
2012-02-12 09:45:24 -03:00
CNetAddr addr ( s6 - > sin6_addr ) ;
2012-03-31 12:58:25 -03:00
if ( AddLocal ( addr , LOCAL_IF ) )
2014-11-13 11:20:57 -03:00
LogPrintf ( " %s: IPv6 %s: %s \n " , __func__ , ifa - > ifa_name , addr . ToString ( ) ) ;
2010-08-29 12:58:15 -04:00
}
}
freeifaddrs ( myaddrs ) ;
}
# endif
2012-02-19 16:44:35 -03:00
}
2013-03-25 22:33:25 -03:00
void CConnman : : SetNetworkActive ( bool active )
{
2020-07-09 03:12:19 -04:00
LogPrintf ( " %s: %s \n " , __func__ , active ) ;
2013-03-25 22:33:25 -03:00
2017-07-14 10:00:19 -04:00
if ( fNetworkActive = = active ) {
return ;
}
fNetworkActive = active ;
2013-03-25 22:33:25 -03:00
2013-03-25 23:07:06 -03:00
uiInterface . NotifyNetworkActiveChanged ( fNetworkActive ) ;
2013-03-25 22:33:25 -03:00
}
2020-07-09 03:07:47 -04:00
CConnman : : CConnman ( uint64_t nSeed0In , uint64_t nSeed1In , bool network_active )
: nSeed0 ( nSeed0In ) , nSeed1 ( nSeed1In )
2016-04-16 15:47:18 -03:00
{
2017-10-23 14:36:15 -03: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 08:02:36 -04:00
Options connOptions ;
Init ( connOptions ) ;
2020-07-09 03:07:47 -04:00
SetNetworkActive ( network_active ) ;
2016-04-16 15:47:18 -03:00
}
2016-04-17 21:20:34 -03:00
NodeId CConnman : : GetNewNodeId ( )
2016-04-16 18:43:11 -03:00
{
2016-04-17 21:20:34 -03:00
return nLastNodeId . fetch_add ( 1 , std : : memory_order_relaxed ) ;
}
2016-04-16 18:43:11 -03:00
2017-06-01 06:34:02 -04:00
2019-06-20 05:37:51 -04:00
bool CConnman : : Bind ( const CService & addr , unsigned int flags , NetPermissionFlags permissions ) {
2019-01-09 21:41:37 -03:00
if ( ! ( flags & BF_EXPLICIT ) & & ! IsReachable ( addr ) )
2017-06-01 06:34:02 -04:00
return false ;
2020-04-11 11:47:17 -04:00
bilingual_str strError ;
2019-06-20 05:37:51 -04:00
if ( ! BindListenPort ( addr , strError , permissions ) ) {
2017-06-01 06:34:02 -04:00
if ( ( flags & BF_REPORT_ERROR ) & & clientInterface ) {
clientInterface - > ThreadSafeMessageBox ( strError , " " , CClientUIInterface : : MSG_ERROR ) ;
}
return false ;
}
2020-09-29 12:02:44 -03:00
2020-09-29 12:03:43 -03:00
if ( addr . IsRoutable ( ) & & fDiscover & & ! ( flags & BF_DONT_ADVERTISE ) & & ! ( permissions & PF_NOBAN ) ) {
2020-09-29 12:02:44 -03:00
AddLocal ( addr , LOCAL_BIND ) ;
}
2017-06-01 06:34:02 -04:00
return true ;
}
2020-09-29 12:03:43 -03:00
bool CConnman : : InitBinds (
const std : : vector < CService > & binds ,
const std : : vector < NetWhitebindPermissions > & whiteBinds ,
const std : : vector < CService > & onion_binds )
2019-06-20 05:37:51 -04:00
{
2017-06-01 06:34:02 -04:00
bool fBound = false ;
for ( const auto & addrBind : binds ) {
2019-06-20 05:37:51 -04:00
fBound | = Bind ( addrBind , ( BF_EXPLICIT | BF_REPORT_ERROR ) , NetPermissionFlags : : PF_NONE ) ;
2017-06-01 06:34:02 -04:00
}
for ( const auto & addrBind : whiteBinds ) {
2019-06-20 05:37:51 -04:00
fBound | = Bind ( addrBind . m_service , ( BF_EXPLICIT | BF_REPORT_ERROR ) , addrBind . m_flags ) ;
2017-06-01 06:34:02 -04:00
}
if ( binds . empty ( ) & & whiteBinds . empty ( ) ) {
struct in_addr inaddr_any ;
2020-09-22 07:42:47 -03:00
inaddr_any . s_addr = htonl ( INADDR_ANY ) ;
2018-07-16 02:29:27 -04:00
struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT ;
2019-06-20 05:37:51 -04:00
fBound | = Bind ( CService ( inaddr6_any , GetListenPort ( ) ) , BF_NONE , NetPermissionFlags : : PF_NONE ) ;
fBound | = Bind ( CService ( inaddr_any , GetListenPort ( ) ) , ! fBound ? BF_REPORT_ERROR : BF_NONE , NetPermissionFlags : : PF_NONE ) ;
2017-06-01 06:34:02 -04:00
}
2020-09-29 12:03:43 -03:00
for ( const auto & addr_bind : onion_binds ) {
fBound | = Bind ( addr_bind , BF_EXPLICIT | BF_DONT_ADVERTISE , NetPermissionFlags : : PF_NONE ) ;
}
2017-06-01 06:34:02 -04:00
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 08:02:36 -04:00
bool CConnman : : Start ( CScheduler & scheduler , const Options & connOptions )
2016-04-17 21:20:34 -03: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 08:02:36 -04:00
Init ( connOptions ) ;
2020-09-29 12:03:43 -03:00
if ( fListen & & ! InitBinds ( connOptions . vBinds , connOptions . vWhiteBinds , connOptions . onion_binds ) ) {
2017-06-01 06:34:02 -04:00
if ( clientInterface ) {
clientInterface - > ThreadSafeMessageBox (
2020-04-11 11:47:17 -04:00
_ ( " Failed to listen on any port. Use -listen=0 if you want this. " ) ,
2017-06-01 06:34:02 -04:00
" " , CClientUIInterface : : MSG_ERROR ) ;
}
return false ;
}
2017-05-27 06:00:37 -04:00
for ( const auto & strDest : connOptions . vSeedNodes ) {
2020-07-17 17:56:34 -04:00
AddAddrFetch ( strDest ) ;
2017-05-27 06:00:37 -04:00
}
2017-02-25 21:41:51 -03:00
if ( clientInterface ) {
2019-06-28 14:09:58 -04:00
clientInterface - > InitMessage ( _ ( " Loading P2P addresses... " ) . translated ) ;
2017-02-25 21:41:51 -03:00
}
2015-07-03 04:46:17 -03:00
// Load addresses from peers.dat
2014-09-18 09:08:43 -03:00
int64_t nStart = GetTimeMillis ( ) ;
{
CAddrDB adb ;
2015-07-03 04:46:17 -03:00
if ( adb . Read ( addrman ) )
LogPrintf ( " Loaded %i addresses from peers.dat %dms \n " , addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
2016-02-02 06:45:11 -03:00
else {
2016-03-16 13:54:30 -03:00
addrman . Clear ( ) ; // Addrman can be in an inconsistent state after failure, reset it
2014-09-18 09:08:43 -03:00
LogPrintf ( " Invalid or missing peers.dat; recreating \n " ) ;
2016-02-02 06:45:11 -03:00
DumpAddresses ( ) ;
}
2014-09-18 09:08:43 -03:00
}
2015-06-19 10:27:37 -03:00
2020-09-12 12:05:54 -03:00
if ( m_use_addrman_outgoing ) {
// Load addresses from anchors.dat
m_anchors = ReadAnchors ( GetDataDir ( ) / ANCHORS_DATABASE_FILENAME ) ;
if ( m_anchors . size ( ) > MAX_BLOCK_RELAY_ONLY_ANCHORS ) {
m_anchors . resize ( MAX_BLOCK_RELAY_ONLY_ANCHORS ) ;
}
LogPrintf ( " %i block-relay-only anchors will be tried for connections. \n " , m_anchors . size ( ) ) ;
}
2019-06-28 14:09:58 -04:00
uiInterface . InitMessage ( _ ( " Starting network threads... " ) . translated ) ;
2016-07-22 10:01:12 -04:00
2014-09-18 09:08:43 -03:00
fAddressesInitialized = true ;
2017-08-07 01:36:37 -04:00
if ( semOutbound = = nullptr ) {
2012-05-10 12:44:07 -04:00
// initialize semaphore
2019-03-09 14:55:06 -03:00
semOutbound = MakeUnique < CSemaphore > ( std : : min ( m_max_outbound , nMaxConnections ) ) ;
2012-05-10 12:44:07 -04:00
}
2017-08-07 01:36:37 -04:00
if ( semAddnode = = nullptr ) {
2016-12-11 01:39:26 -03:00
// initialize semaphore
2017-08-15 02:46:56 -03:00
semAddnode = MakeUnique < CSemaphore > ( nMaxAddnode ) ;
2016-12-11 01:39:26 -03:00
}
2012-05-10 12:44:07 -04:00
2010-08-29 12:58:15 -04:00
//
// Start threads
//
2017-07-06 13:40:09 -04:00
assert ( m_msgproc ) ;
2016-12-27 19:13:31 -03:00
InterruptSocks5 ( false ) ;
2016-12-27 19:12:44 -03:00
interruptNet . reset ( ) ;
flagInterruptMsgProc = false ;
2010-08-29 12:58:15 -04:00
2016-12-31 04:05:26 -03:00
{
2017-11-08 19:07:40 -03:00
LOCK ( mutexMsgProc ) ;
2016-12-31 04:05:26 -03:00
fMsgProcWake = false ;
}
2016-12-27 19:11:57 -03:00
// Send and receive from sockets, accept connections
2016-12-27 19:12:44 -03:00
threadSocketHandler = std : : thread ( & TraceThread < std : : function < void ( ) > > , " net " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadSocketHandler , this ) ) ) ;
2010-08-29 12:58:15 -04:00
2017-08-01 15:17:40 -04:00
if ( ! gArgs . GetBoolArg ( " -dnsseed " , true ) )
2013-09-18 07:38:08 -03:00
LogPrintf ( " DNS seeding disabled \n " ) ;
2011-11-21 14:25:00 -03:00
else
2016-12-27 19:12:44 -03:00
threadDNSAddressSeed = std : : thread ( & TraceThread < std : : function < void ( ) > > , " dnsseed " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadDNSAddressSeed , this ) ) ) ;
2010-08-29 12:58:15 -04:00
2020-04-29 17:55:59 -04:00
// Initiate manual connections
2016-12-27 19:12:44 -03:00
threadOpenAddedConnections = std : : thread ( & TraceThread < std : : function < void ( ) > > , " addcon " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadOpenAddedConnections , this ) ) ) ;
2011-12-16 21:48:03 -03:00
2017-06-15 03:39:07 -04:00
if ( connOptions . m_use_addrman_outgoing & & ! connOptions . m_specified_outgoing . empty ( ) ) {
if ( clientInterface ) {
clientInterface - > ThreadSafeMessageBox (
2020-04-11 11:47:17 -04:00
_ ( " Cannot provide specific connections and have addrman find outgoing connections at the same. " ) ,
2017-06-15 03:39:07 -04:00
" " , 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 12:58:15 -04:00
// Process messages
2016-12-27 19:12:44 -03:00
threadMessageHandler = std : : thread ( & TraceThread < std : : function < void ( ) > > , " msghand " , std : : function < void ( ) > ( std : : bind ( & CConnman : : ThreadMessageHandler , this ) ) ) ;
2010-08-29 12:58:15 -04:00
2016-04-16 18:43:11 -03:00
// Dump network addresses
2020-03-06 20:06:50 -03:00
scheduler . scheduleEvery ( [ this ] { DumpAddresses ( ) ; } , DUMP_PEERS_INTERVAL ) ;
2016-04-16 18:43:11 -03:00
2016-04-16 15:47:18 -03:00
return true ;
2010-08-29 12:58:15 -04:00
}
class CNetCleanup
{
public :
2014-05-24 05:14:52 -04:00
CNetCleanup ( ) { }
2010-08-29 12:58:15 -04:00
~ CNetCleanup ( )
{
2011-10-07 12:02:21 -03:00
# ifdef WIN32
2010-08-29 12:58:15 -04:00
// Shutdown Windows Sockets
WSACleanup ( ) ;
# endif
}
2019-05-26 05:01:58 -04:00
} ;
static CNetCleanup instance_of_cnetcleanup ;
2012-08-12 23:26:30 -04:00
2016-12-27 19:12:44 -03:00
void CConnman : : Interrupt ( )
2016-04-16 15:47:18 -03:00
{
2016-12-27 19:12:44 -03:00
{
2019-05-29 23:44:02 -04:00
LOCK ( mutexMsgProc ) ;
2016-12-27 19:12:44 -03:00
flagInterruptMsgProc = true ;
}
condMsgProc . notify_all ( ) ;
interruptNet ( ) ;
2016-12-27 19:13:31 -03:00
InterruptSocks5 ( true ) ;
2016-12-27 19:12:44 -03:00
2017-03-08 16:55:28 -03:00
if ( semOutbound ) {
2019-03-09 14:55:06 -03:00
for ( int i = 0 ; i < m_max_outbound ; i + + ) {
2016-04-16 15:47:18 -03:00
semOutbound - > post ( ) ;
2017-03-08 16:55:28 -03:00
}
}
2017-03-08 16:41:57 -03:00
2017-03-08 16:55:28 -03:00
if ( semAddnode ) {
for ( int i = 0 ; i < nMaxAddnode ; i + + ) {
2017-03-08 16:41:57 -03:00
semAddnode - > post ( ) ;
2017-03-08 16:55:28 -03:00
}
}
2016-12-27 19:12:44 -03:00
}
2020-03-28 11:44:53 -03:00
void CConnman : : StopThreads ( )
2016-12-27 19:12:44 -03:00
{
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 ( ) ;
2020-03-28 11:44:53 -03:00
}
2016-04-16 15:47:18 -03:00
2020-03-28 11:44:53 -03:00
void CConnman : : StopNodes ( )
{
if ( fAddressesInitialized ) {
2017-10-05 13:46:54 -03:00
DumpAddresses ( ) ;
2016-04-16 18:43:11 -03:00
fAddressesInitialized = false ;
2020-09-12 12:05:54 -03:00
if ( m_use_addrman_outgoing ) {
// Anchor connections are only dumped during clean shutdown.
std : : vector < CAddress > anchors_to_dump = GetCurrentBlockRelayOnlyConns ( ) ;
if ( anchors_to_dump . size ( ) > MAX_BLOCK_RELAY_ONLY_ANCHORS ) {
anchors_to_dump . resize ( MAX_BLOCK_RELAY_ONLY_ANCHORS ) ;
}
DumpAnchors ( GetDataDir ( ) / ANCHORS_DATABASE_FILENAME , anchors_to_dump ) ;
}
2016-04-16 18:43:11 -03:00
}
2016-04-16 15:47:18 -03:00
// Close sockets
2020-03-28 11:44:53 -03:00
LOCK ( cs_vNodes ) ;
2017-06-01 21:18:57 -04:00
for ( CNode * pnode : vNodes )
2017-02-06 16:05:45 -03:00
pnode - > CloseSocketDisconnect ( ) ;
2017-06-01 21:18:57 -04:00
for ( ListenSocket & hListenSocket : vhListenSocket )
2016-04-16 15:47:18 -03: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)
2020-03-28 11:44:53 -03:00
for ( CNode * pnode : vNodes ) {
2016-05-24 18:59:16 -04:00
DeleteNode ( pnode ) ;
}
2020-03-28 11:44:53 -03:00
for ( CNode * pnode : vNodesDisconnected ) {
2016-05-24 18:59:16 -04:00
DeleteNode ( pnode ) ;
}
2016-04-16 15:47:18 -03:00
vNodes . clear ( ) ;
vNodesDisconnected . clear ( ) ;
vhListenSocket . clear ( ) ;
2017-08-09 10:07:22 -04:00
semOutbound . reset ( ) ;
semAddnode . reset ( ) ;
2016-04-16 15:47:18 -03:00
}
2016-05-24 18:59:16 -04:00
void CConnman : : DeleteNode ( CNode * pnode )
{
assert ( pnode ) ;
bool fUpdateConnectionTime = false ;
2020-10-24 04:16:04 -03:00
m_msgproc - > FinalizeNode ( * pnode , fUpdateConnectionTime ) ;
2020-03-28 11:44:53 -03:00
if ( fUpdateConnectionTime ) {
2016-05-24 18:59:16 -04:00
addrman . Connected ( pnode - > addr ) ;
2017-07-06 13:40:09 -04:00
}
2016-05-24 18:59:16 -04:00
delete pnode ;
}
2016-04-16 15:47:18 -03:00
CConnman : : ~ CConnman ( )
{
2016-12-27 19:12:44 -03:00
Interrupt ( ) ;
2016-09-13 15:42:55 -03:00
Stop ( ) ;
2016-04-16 15:47:18 -03:00
}
2012-08-12 23:26:30 -04:00
2016-04-16 18:43:11 -03:00
void CConnman : : SetServices ( const CService & addr , ServiceFlags nServices )
{
addrman . SetServices ( addr , nServices ) ;
}
void CConnman : : MarkAddressGood ( const CAddress & addr )
{
addrman . Good ( addr ) ;
}
2020-07-23 13:10:35 -04:00
bool CConnman : : AddNewAddresses ( const std : : vector < CAddress > & vAddr , const CAddress & addrFrom , int64_t nTimePenalty )
2016-04-16 18:43:11 -03:00
{
2020-07-23 13:10:35 -04:00
return addrman . Add ( vAddr , addrFrom , nTimePenalty ) ;
2016-04-16 18:43:11 -03:00
}
2020-07-23 10:34:40 -04:00
std : : vector < CAddress > CConnman : : GetAddresses ( size_t max_addresses , size_t max_pct )
2016-04-16 18:43:11 -03:00
{
2020-07-23 10:34:40 -04:00
std : : vector < CAddress > addresses = addrman . GetAddr ( max_addresses , max_pct ) ;
2020-07-04 04:25:51 -04:00
if ( m_banman ) {
addresses . erase ( std : : remove_if ( addresses . begin ( ) , addresses . end ( ) ,
[ this ] ( const CAddress & addr ) { return m_banman - > IsDiscouraged ( addr ) | | m_banman - > IsBanned ( addr ) ; } ) ,
addresses . end ( ) ) ;
}
return addresses ;
2016-04-16 18:43:11 -03:00
}
2020-08-11 05:41:26 -04:00
std : : vector < CAddress > CConnman : : GetAddresses ( CNode & requestor , size_t max_addresses , size_t max_pct )
2020-05-16 21:05:44 -04:00
{
2020-08-11 05:41:26 -04:00
SOCKET socket ;
WITH_LOCK ( requestor . cs_hSocket , socket = requestor . hSocket ) ;
auto local_socket_bytes = GetBindAddress ( socket ) . GetAddrBytes ( ) ;
uint64_t cache_id = GetDeterministicRandomizer ( RANDOMIZER_ID_ADDRCACHE )
. Write ( requestor . addr . GetNetwork ( ) )
. Write ( local_socket_bytes . data ( ) , local_socket_bytes . size ( ) )
. Finalize ( ) ;
2020-05-16 21:05:44 -04:00
const auto current_time = GetTime < std : : chrono : : microseconds > ( ) ;
2020-08-11 06:39:56 -04:00
auto r = m_addr_response_caches . emplace ( cache_id , CachedAddrResponse { } ) ;
CachedAddrResponse & cache_entry = r . first - > second ;
if ( cache_entry . m_cache_entry_expiration < current_time ) { // If emplace() added new one it has expiration 0.
cache_entry . m_addrs_response_cache = GetAddresses ( max_addresses , max_pct ) ;
2020-08-11 03:42:26 -04:00
// Choosing a proper cache lifetime is a trade-off between the privacy leak minimization
// and the usefulness of ADDR responses to honest users.
//
// Longer cache lifetime makes it more difficult for an attacker to scrape
// enough AddrMan data to maliciously infer something useful.
// By the time an attacker scraped enough AddrMan records, most of
// the records should be old enough to not leak topology info by
// e.g. analyzing real-time changes in timestamps.
//
// It takes only several hundred requests to scrape everything from an AddrMan containing 100,000 nodes,
// so ~24 hours of cache lifetime indeed makes the data less inferable by the time
// most of it could be scraped (considering that timestamps are updated via
// ADDR self-announcements and when nodes communicate).
// We also should be robust to those attacks which may not require scraping *full* victim's AddrMan
// (because even several timestamps of the same handful of nodes may leak privacy).
//
// On the other hand, longer cache lifetime makes ADDR responses
// outdated and less useful for an honest requestor, e.g. if most nodes
// in the ADDR response are no longer active.
//
// However, the churn in the network is known to be rather low. Since we consider
// nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days,
// max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference
// in terms of the freshness of the response.
2020-08-11 06:39:56 -04:00
cache_entry . m_cache_entry_expiration = current_time + std : : chrono : : hours ( 21 ) + GetRandMillis ( std : : chrono : : hours ( 6 ) ) ;
2020-05-16 21:05:44 -04:00
}
2020-08-11 06:39:56 -04:00
return cache_entry . m_addrs_response_cache ;
2020-05-16 21:05:44 -04:00
}
2016-04-16 19:12:58 -03:00
bool CConnman : : AddNode ( const std : : string & strNode )
{
LOCK ( cs_vAddedNodes ) ;
2017-07-20 05:32:47 -04:00
for ( const std : : string & it : vAddedNodes ) {
if ( strNode = = it ) return false ;
2016-04-16 19:12:58 -03: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-16 19:30:03 -03: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 05:32:47 -04:00
for ( const auto & pnode : vNodes ) {
2020-07-28 16:39:38 -04:00
if ( flags & ( pnode - > IsInboundConn ( ) ? CONNECTIONS_IN : CONNECTIONS_OUT ) ) {
2016-04-16 19:30:03 -03:00
nNum + + ;
2017-07-20 05:32:47 -04:00
}
}
2016-04-16 19:30:03 -03:00
return nNum ;
}
void CConnman : : GetNodeStats ( std : : vector < CNodeStats > & vstats )
{
vstats . clear ( ) ;
LOCK ( cs_vNodes ) ;
vstats . reserve ( vNodes . size ( ) ) ;
2017-07-20 05:32:47 -04:00
for ( CNode * pnode : vNodes ) {
2017-02-06 13:44:38 -03:00
vstats . emplace_back ( ) ;
2019-12-24 15:26:46 -03:00
pnode - > copyStats ( vstats . back ( ) , addrman . m_asmap ) ;
2016-04-16 19:30:03 -03:00
}
}
bool CConnman : : DisconnectNode ( const std : : string & strNode )
{
2017-01-24 18:50:27 -03:00
LOCK ( cs_vNodes ) ;
2016-04-16 19:30:03 -03:00
if ( CNode * pnode = FindNode ( strNode ) ) {
pnode - > fDisconnect = true ;
return true ;
}
return false ;
}
2017-10-04 19:25:34 -03:00
bool CConnman : : DisconnectNode ( const CSubNet & subnet )
{
bool disconnected = false ;
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes ) {
if ( subnet . Match ( pnode - > addr ) ) {
pnode - > fDisconnect = true ;
disconnected = true ;
}
}
return disconnected ;
}
bool CConnman : : DisconnectNode ( const CNetAddr & addr )
{
return DisconnectNode ( CSubNet ( addr ) ) ;
}
2016-04-16 19:30:03 -03:00
bool CConnman : : DisconnectNode ( NodeId id )
{
LOCK ( cs_vNodes ) ;
for ( CNode * pnode : vNodes ) {
2017-04-11 13:13:55 -03:00
if ( id = = pnode - > GetId ( ) ) {
2016-04-16 19:30:03 -03:00
pnode - > fDisconnect = true ;
return true ;
}
}
return false ;
}
2016-04-18 22:44:42 -03:00
void CConnman : : RecordBytesRecv ( uint64_t bytes )
2013-08-22 12:09:32 -04:00
{
LOCK ( cs_totalBytesRecv ) ;
nTotalBytesRecv + = bytes ;
}
2016-04-18 22:44:42 -03:00
void CConnman : : RecordBytesSent ( uint64_t bytes )
2013-08-22 12:09:32 -04:00
{
LOCK ( cs_totalBytesSent ) ;
nTotalBytesSent + = bytes ;
2015-09-02 12:03:27 -03:00
2020-10-24 08:13:42 -03:00
const auto now = GetTime < std : : chrono : : seconds > ( ) ;
2020-10-24 05:33:26 -03:00
if ( nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME < now )
2015-09-02 12:03:27 -03:00
{
// timeframe expired, reset cycle
nMaxOutboundCycleStartTime = now ;
nMaxOutboundTotalBytesSentInCycle = 0 ;
}
2020-06-06 11:07:25 -04:00
// TODO, exclude peers with download permission
2015-09-02 12:03:27 -03:00
nMaxOutboundTotalBytesSentInCycle + = bytes ;
}
2016-04-18 22:44:42 -03:00
uint64_t CConnman : : GetMaxOutboundTarget ( )
2015-09-02 12:03:27 -03:00
{
LOCK ( cs_totalBytesSent ) ;
return nMaxOutboundLimit ;
}
2020-10-24 08:13:42 -03:00
std : : chrono : : seconds CConnman : : GetMaxOutboundTimeframe ( )
2015-09-02 12:03:27 -03:00
{
2020-10-24 05:33:26 -03:00
return MAX_UPLOAD_TIMEFRAME ;
2015-09-02 12:03:27 -03:00
}
2020-10-24 08:13:42 -03:00
std : : chrono : : seconds CConnman : : GetMaxOutboundTimeLeftInCycle ( )
2015-09-02 12:03:27 -03:00
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
2020-10-24 08:13:42 -03:00
return 0 s ;
2015-09-02 12:03:27 -03:00
2020-10-24 08:13:42 -03:00
if ( nMaxOutboundCycleStartTime . count ( ) = = 0 )
2020-10-24 05:33:26 -03:00
return MAX_UPLOAD_TIMEFRAME ;
2015-09-02 12:03:27 -03:00
2020-10-24 08:13:42 -03:00
const std : : chrono : : seconds cycleEndTime = nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME ;
const auto now = GetTime < std : : chrono : : seconds > ( ) ;
return ( cycleEndTime < now ) ? 0 s : cycleEndTime - now ;
2015-09-02 12:03:27 -03:00
}
2016-04-18 22:44:42 -03:00
bool CConnman : : OutboundTargetReached ( bool historicalBlockServingLimit )
2015-09-02 12:03:27 -03:00
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
return false ;
if ( historicalBlockServingLimit )
{
2016-01-17 08:03:56 -03:00
// keep a large enough buffer to at least relay each block once
2020-10-24 08:13:42 -03:00
const std : : chrono : : seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle ( ) ;
const uint64_t buffer = timeLeftInCycle / std : : chrono : : minutes { 10 } * MAX_BLOCK_SERIALIZED_SIZE ;
2015-09-02 12:03:27 -03:00
if ( buffer > = nMaxOutboundLimit | | nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit - buffer )
return true ;
}
else if ( nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit )
return true ;
return false ;
}
2016-04-18 22:44:42 -03:00
uint64_t CConnman : : GetOutboundTargetBytesLeft ( )
2015-09-02 12:03:27 -03:00
{
LOCK ( cs_totalBytesSent ) ;
if ( nMaxOutboundLimit = = 0 )
return 0 ;
return ( nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit ) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle ;
2013-08-22 12:09:32 -04:00
}
2016-04-18 22:44:42 -03:00
uint64_t CConnman : : GetTotalBytesRecv ( )
2013-08-22 12:09:32 -04:00
{
LOCK ( cs_totalBytesRecv ) ;
return nTotalBytesRecv ;
}
2016-04-18 22:44:42 -03:00
uint64_t CConnman : : GetTotalBytesSent ( )
2013-08-22 12:09:32 -04:00
{
LOCK ( cs_totalBytesSent ) ;
return nTotalBytesSent ;
}
2013-10-28 03:28:00 -03:00
2016-04-19 01:04:58 -03:00
ServiceFlags CConnman : : GetLocalServices ( ) const
{
return nLocalServices ;
}
2016-04-19 01:01:19 -03:00
unsigned int CConnman : : GetReceiveFloodSize ( ) const { return nReceiveFloodSize ; }
2014-08-20 23:17:21 -04:00
2021-01-02 06:25:05 -03:00
CNode : : CNode ( NodeId idIn , ServiceFlags nLocalServicesIn , SOCKET hSocketIn , const CAddress & addrIn , uint64_t nKeyedNetGroupIn , uint64_t nLocalHostNonceIn , const CAddress & addrBindIn , const std : : string & addrNameIn , ConnectionType conn_type_in , bool inbound_onion )
2019-01-05 08:11:04 -03:00
: nTimeConnected ( GetSystemTimeInSeconds ( ) ) ,
2020-12-14 14:25:20 -03:00
addr ( addrIn ) ,
addrBind ( addrBindIn ) ,
nKeyedNetGroup ( nKeyedNetGroupIn ) ,
id ( idIn ) ,
nLocalHostNonce ( nLocalHostNonceIn ) ,
m_conn_type ( conn_type_in ) ,
nLocalServices ( nLocalServicesIn ) ,
m_inbound_onion ( inbound_onion )
2014-08-20 23:17:21 -04:00
{
2020-10-21 06:52:19 -03:00
if ( inbound_onion ) assert ( conn_type_in = = ConnectionType : : INBOUND ) ;
2014-08-20 23:17:21 -04:00
hSocket = hSocketIn ;
addrName = addrNameIn = = " " ? addr . ToStringIPPort ( ) : addrNameIn ;
2020-04-29 20:33:06 -04:00
if ( conn_type_in ! = ConnectionType : : BLOCK_RELAY ) {
2019-03-09 14:55:06 -03:00
m_tx_relay = MakeUnique < TxRelay > ( ) ;
2020-08-10 17:48:54 -04:00
}
if ( RelayAddrsWithConn ( ) ) {
2020-05-12 17:48:24 -04:00
m_addr_known = MakeUnique < CRollingBloomFilter > ( 5000 , 0.001 ) ;
2019-03-09 14:55:06 -03:00
}
2016-04-17 21:21:58 -03:00
2017-06-01 21:18:57 -04:00
for ( const std : : string & msg : getAllNetMessageTypes ( ) )
2015-12-07 11:31:32 -03:00
mapRecvBytesPerMsgCmd [ msg ] = 0 ;
2015-08-25 11:30:31 -03:00
mapRecvBytesPerMsgCmd [ NET_MESSAGE_COMMAND_OTHER ] = 0 ;
2014-08-20 23:17:21 -04:00
2016-12-25 17:19:40 -03: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 ) ;
}
2019-06-13 04:39:44 -04:00
2020-06-08 22:26:22 -04:00
m_deserializer = MakeUnique < V1TransportDeserializer > ( V1TransportDeserializer ( Params ( ) , GetId ( ) , SER_NETWORK , INIT_PROTO_VERSION ) ) ;
2019-08-07 09:56:24 -04:00
m_serializer = MakeUnique < V1TransportSerializer > ( V1TransportSerializer ( ) ) ;
2014-08-20 23:17:21 -04:00
}
CNode : : ~ CNode ( )
{
CloseSocket ( hSocket ) ;
}
2017-01-20 22:34:57 -03:00
bool CConnman : : NodeFullyConnected ( const CNode * pnode )
{
return pnode & & pnode - > fSuccessfullyConnected & & ! pnode - > fDisconnect ;
}
2016-11-10 22:17:30 -03:00
void CConnman : : PushMessage ( CNode * pnode , CSerializedNetMsg & & msg )
2016-09-12 21:00:33 -03:00
{
2016-11-10 22:17:30 -03:00
size_t nMessageSize = msg . data . size ( ) ;
2020-05-10 13:48:11 -04:00
LogPrint ( BCLog : : NET , " sending %s (%d bytes) peer=%d \n " , SanitizeString ( msg . m_type ) , nMessageSize , pnode - > GetId ( ) ) ;
2016-09-12 21:00:33 -03:00
2019-08-07 09:56:24 -04:00
// make sure we use the appropriate network transport format
2016-11-10 22:17:30 -03:00
std : : vector < unsigned char > serializedHeader ;
2019-08-07 09:56:24 -04:00
pnode - > m_serializer - > prepareForTransport ( msg , serializedHeader ) ;
size_t nTotalSize = nMessageSize + serializedHeader . size ( ) ;
2016-09-12 21:00:33 -03:00
size_t nBytesSent = 0 ;
{
LOCK ( pnode - > cs_vSend ) ;
bool optimisticSend ( pnode - > vSendMsg . empty ( ) ) ;
2020-05-10 13:48:11 -04:00
//log total amount of bytes per message type
pnode - > mapSendBytesPerMsgCmd [ msg . m_type ] + = nTotalSize ;
2016-11-10 22:17:30 -03:00
pnode - > nSendSize + = nTotalSize ;
2016-12-31 04:05:32 -03:00
if ( pnode - > nSendSize > nSendBufferMaxSize )
pnode - > fPauseSend = true ;
2016-11-10 22:17:30 -03:00
pnode - > vSendMsg . push_back ( std : : move ( serializedHeader ) ) ;
if ( nMessageSize )
pnode - > vSendMsg . push_back ( std : : move ( msg . data ) ) ;
2016-09-12 21:00:33 -03:00
// If write queue empty, attempt "optimistic write"
if ( optimisticSend = = true )
nBytesSent = SocketSendData ( pnode ) ;
}
if ( nBytesSent )
RecordBytesSent ( nBytesSent ) ;
}
2016-04-16 20:13:12 -03: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 13:13:55 -03:00
if ( pnode - > GetId ( ) = = id ) {
2016-04-16 20:13:12 -03:00
found = pnode ;
break ;
}
}
2017-01-20 22:34:57 -03:00
return found ! = nullptr & & NodeFullyConnected ( found ) & & func ( found ) ;
2016-04-16 20:13:12 -03:00
}
2018-05-21 15:02:40 -04:00
int64_t CConnman : : PoissonNextSendInbound ( int64_t now , int average_interval_seconds )
{
if ( m_next_send_inv_to_incoming < now ) {
// If this function were called from multiple threads simultaneously
// it would possible that both update the next send variable, and return a different result to their caller.
// This is not possible in practice as only the net processing thread invokes this function.
m_next_send_inv_to_incoming = PoissonNextSend ( now , average_interval_seconds ) ;
}
return m_next_send_inv_to_incoming ;
}
int64_t PoissonNextSend ( int64_t now , int average_interval_seconds )
{
return now + ( int64_t ) ( log1p ( GetRand ( 1ULL < < 48 ) * - 0.0000000000000035527136788 /* -1/2^48 */ ) * average_interval_seconds * - 1000000.0 + 0.5 ) ;
2015-04-08 15:20:00 -03:00
}
2016-05-25 09:38:32 -04:00
2017-01-23 22:32:52 -03:00
CSipHasher CConnman : : GetDeterministicRandomizer ( uint64_t id ) const
2016-05-25 09:38:32 -04:00
{
2016-09-09 07:48:10 -03:00
return CSipHasher ( nSeed0 , nSeed1 ) . Write ( id ) ;
}
2016-05-25 09:38:32 -04:00
2017-01-23 22:32:52 -03:00
uint64_t CConnman : : CalculateKeyedNetGroup ( const CAddress & ad ) const
2016-09-09 07:48:10 -03:00
{
2019-12-24 15:18:44 -03:00
std : : vector < unsigned char > vchNetGroup ( ad . GetGroup ( addrman . m_asmap ) ) ;
2016-05-25 09:38:32 -04:00
2017-02-19 15:18:04 -03:00
return GetDeterministicRandomizer ( RANDOMIZER_ID_NETGROUP ) . Write ( vchNetGroup . data ( ) , vchNetGroup . size ( ) ) . Finalize ( ) ;
2016-05-25 09:38:32 -04:00
}