2010-08-29 16:58:15 +00:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2022-12-24 23:49:50 +00:00
// Copyright (c) 2009-2022 The Bitcoin Core developers
2014-12-13 12:09:33 +08:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 22:02:28 +08:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2010-08-29 16:58:15 +00:00
2013-05-27 19:55:01 -04:00
# if defined(HAVE_CONFIG_H)
2017-11-10 13:57:53 +13:00
# include <config/bitcoin-config.h>
2013-05-27 19:55:01 -04:00
# endif
2017-11-10 13:57:53 +13:00
# include <net.h>
2021-08-20 12:33:24 +02:00
# include <addrdb.h>
2021-11-30 14:49:43 +01:00
# include <addrman.h>
2017-10-05 16:40:43 -04:00
# include <banman.h>
2017-11-10 13:57:53 +13:00
# include <clientversion.h>
2023-03-23 12:23:29 +01:00
# include <common/args.h>
2022-06-28 13:27:57 +01:00
# include <compat/compat.h>
2017-11-10 13:57:53 +13:00
# include <consensus/consensus.h>
# include <crypto/sha256.h>
2020-11-24 11:28:52 +01:00
# include <i2p.h>
2023-03-06 22:01:13 +01:00
# include <logging.h>
2019-06-20 18:37:51 +09:00
# include <net_permissions.h>
2021-05-02 19:05:42 +02:00
# include <netaddress.h>
2020-06-19 18:14:17 -04:00
# include <netbase.h>
2023-03-06 22:01:13 +01:00
# include <node/eviction.h>
2022-06-14 10:38:51 +02:00
# include <node/interface_ui.h>
2020-05-10 15:47:32 +02:00
# include <protocol.h>
2019-11-23 11:42:23 -05:00
# include <random.h>
2017-11-10 13:57:53 +13:00
# include <scheduler.h>
2023-03-15 11:18:06 +01:00
# include <util/fs.h>
2021-01-04 13:02:43 +01:00
# include <util/sock.h>
2018-10-22 15:51:11 -07:00
# include <util/strencodings.h>
2021-04-13 20:44:46 +03:00
# include <util/thread.h>
2022-10-11 15:33:22 +08:00
# include <util/threadinterrupt.h>
2021-05-20 16:54:54 +02:00
# include <util/trace.h>
2019-06-17 10:56:52 +03:00
# include <util/translation.h>
2013-04-13 00:13:08 -05:00
2011-10-07 11:02:21 -04:00
# ifdef WIN32
2011-07-02 03:59:37 +02:00
# include <string.h>
2013-04-13 00:13:08 -05:00
# else
2013-07-17 16:51:40 +08:00
# include <fcntl.h>
# endif
2021-03-26 12:53:05 +08:00
# if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
# include <ifaddrs.h>
# endif
2018-09-26 21:54:52 -04:00
# ifdef USE_POLL
# include <poll.h>
# endif
2020-09-30 19:07:36 +03:00
# include <algorithm>
2021-04-20 13:22:20 +02:00
# include <array>
2019-12-29 13:04:02 -08:00
# include <cstdint>
2021-01-13 02:05:00 +01:00
# include <functional>
2021-03-15 11:59:05 +08:00
# include <optional>
2018-09-26 21:54:52 -04:00
# include <unordered_map>
2014-01-30 10:55:55 +01:00
2015-04-08 11:20:00 -07:00
# include <math.h>
2020-09-12 18: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 18:06:50 -05:00
// How often to dump addresses to peers.dat
static constexpr std : : chrono : : minutes DUMP_PEERS_INTERVAL { 15 } ;
2017-10-05 12:46:54 -04:00
2019-03-07 15:30:59 -08: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 13:20:21 +10:00
/** How long to delay before querying DNS seeds
2020-05-28 10:07:49 +10: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 13:20:21 +10:00
*/
2020-05-28 10:07:49 +10: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 13:20:21 +10:00
2020-10-24 16:33:26 +08:00
/** The default timeframe for -maxuploadtarget. 1 day. */
2020-10-24 19:13:42 +08:00
static constexpr std : : chrono : : seconds MAX_UPLOAD_TIMEFRAME { 60 * 60 * 24 } ;
2020-10-24 16:33:26 +08:00
2022-05-10 09:08:49 +02:00
// A random time period (0 to 1 seconds) is added to feeler connections to prevent synchronization.
static constexpr auto FEELER_SLEEP_WINDOW { 1 s } ;
2016-06-17 00:10:07 -04:00
2017-06-01 12:34:02 +02:00
/** Used to pass flags to the Bind() function */
enum BindFlags {
BF_NONE = 0 ,
2022-07-29 13:23:29 +02:00
BF_REPORT_ERROR = ( 1U < < 0 ) ,
2020-09-29 18: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 .
*/
2022-07-29 13:23:29 +02:00
BF_DONT_ADVERTISE = ( 1U < < 1 ) ,
2017-06-01 12:34:02 +02:00
} ;
2018-10-29 16:30:30 -04: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 ;
2022-04-07 17:13:52 +05:30
const std : : string NET_MESSAGE_TYPE_OTHER = " *other* " ;
2015-08-25 16:30:31 +02:00
2016-09-09 12:48:10 +02:00
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL ; // SHA256("netgroup")[0:8]
2016-10-26 15:10:15 -04:00
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL ; // SHA256("localhostnonce")[0:8]
2020-08-11 12:41:26 +03:00
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL ; // SHA256("addrcache")[0:8]
2010-08-29 16:58:15 +00:00
//
// Global state variables
//
2012-05-24 19:02:21 +02:00
bool fDiscover = true ;
2014-05-29 12:33:17 +02:00
bool fListen = true ;
2022-04-20 17:10:13 +10:00
GlobalMutex g_maplocalhost_mutex ;
2022-01-19 07:04:52 -03:00
std : : map < CNetAddr , LocalServiceInfo > mapLocalHost GUARDED_BY ( g_maplocalhost_mutex ) ;
static bool vfLimited [ NET_MAX ] GUARDED_BY ( g_maplocalhost_mutex ) = { } ;
2015-07-31 18:05:42 +02:00
std : : string strSubVersion ;
2010-08-29 16:58:15 +00:00
2020-07-17 14:56:34 -07:00
void CConnman : : AddAddrFetch ( const std : : string & strDest )
2012-04-24 02:15:00 +02:00
{
2020-07-17 14:56:34 -07:00
LOCK ( m_addr_fetches_mutex ) ;
m_addr_fetches . push_back ( strDest ) ;
2012-04-24 02:15:00 +02:00
}
2019-12-29 13:04:02 -08:00
uint16_t GetListenPort ( )
2011-04-21 10:45:08 -04:00
{
2020-10-18 14:45:35 +02:00
// If -bind= is provided with ":port" part, use that (first one if multiple are provided).
for ( const std : : string & bind_arg : gArgs . GetArgs ( " -bind " ) ) {
constexpr uint16_t dummy_port = 0 ;
2022-10-10 15:02:59 -03:00
const std : : optional < CService > bind_addr { Lookup ( bind_arg , dummy_port , /*fAllowLookup=*/ false ) } ;
if ( bind_addr . has_value ( ) & & bind_addr - > GetPort ( ) ! = dummy_port ) return bind_addr - > GetPort ( ) ;
2020-10-18 14:45:35 +02:00
}
// Otherwise, if -whitebind= without NetPermissionFlags::NoBan is provided, use that
// (-whitebind= is required to have ":port").
for ( const std : : string & whitebind_arg : gArgs . GetArgs ( " -whitebind " ) ) {
NetWhitebindPermissions whitebind ;
bilingual_str error ;
if ( NetWhitebindPermissions : : TryParse ( whitebind_arg , whitebind , error ) ) {
if ( ! NetPermissions : : HasFlag ( whitebind . m_flags , NetPermissionFlags : : NoBan ) ) {
return whitebind . m_service . GetPort ( ) ;
}
}
}
// Otherwise, if -port= is provided, use that. Otherwise use the default port.
2019-08-22 21:40:41 -04:00
return static_cast < uint16_t > ( gArgs . GetIntArg ( " -port " , Params ( ) . GetDefaultPort ( ) ) ) ;
2011-04-21 10:45:08 -04:00
}
2010-08-29 16:58:15 +00:00
2012-02-12 13:45:24 +01:00
// find 'best' local address for a particular peer
2012-05-10 20:35:13 +02:00
bool GetLocal ( CService & addr , const CNetAddr * paddrPeer )
2012-02-12 13:45:24 +01:00
{
2014-05-29 12:33:17 +02:00
if ( ! fListen )
2012-02-12 13:45:24 +01:00
return false ;
2010-08-29 16:58:15 +00:00
2012-05-13 00:41:24 +02:00
int nBestScore = - 1 ;
2012-02-12 13:45:24 +01:00
int nBestReachability = - 1 ;
{
2022-01-19 07:04:52 -03:00
LOCK ( g_maplocalhost_mutex ) ;
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapLocalHost )
2012-02-12 13:45:24 +01:00
{
2017-06-04 22:02:43 +02:00
int nScore = entry . second . nScore ;
int nReachability = entry . first . GetReachabilityFrom ( paddrPeer ) ;
2012-05-13 00:41:24 +02:00
if ( nReachability > nBestReachability | | ( nReachability = = nBestReachability & & nScore > nBestScore ) )
2012-02-12 13:45:24 +01:00
{
2017-06-04 22:02:43 +02:00
addr = CService ( entry . first , entry . second . nPort ) ;
2012-02-12 13:45:24 +01:00
nBestReachability = nReachability ;
2012-05-13 00:41:24 +02:00
nBestScore = nScore ;
2012-02-12 13:45:24 +01:00
}
}
}
2012-05-13 00:41:24 +02:00
return nBestScore > = 0 ;
2012-02-12 13:45:24 +01:00
}
2010-08-29 16:58:15 +00:00
2021-03-31 13:29:24 +02:00
//! Convert the serialized seeds into usable address objects.
static std : : vector < CAddress > ConvertSeeds ( const std : : vector < uint8_t > & vSeedsIn )
2015-01-23 23:40:50 -05:00
{
// 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.
2022-03-28 14:20:04 +02:00
const auto one_week { 7 * 24 h } ;
2015-01-23 23:40:50 -05:00
std : : vector < CAddress > vSeedsOut ;
2018-10-31 15:02:24 -07:00
FastRandomContext rng ;
2021-03-31 13:29:24 +02:00
CDataStream s ( vSeedsIn , SER_NETWORK , PROTOCOL_VERSION | ADDRV2_FORMAT ) ;
while ( ! s . eof ( ) ) {
CService endpoint ;
s > > endpoint ;
CAddress addr { endpoint , GetDesirableServiceFlags ( NODE_NONE ) } ;
2022-03-28 14:20:04 +02:00
addr . nTime = rng . rand_uniform_delay ( Now < NodeSeconds > ( ) - one_week , - one_week ) ;
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " Added hardcoded seed: %s \n " , addr . ToStringAddrPort ( ) ) ;
2015-01-23 23:40:50 -05:00
vSeedsOut . push_back ( addr ) ;
}
return vSeedsOut ;
}
2012-02-12 13:45:24 +01:00
// get best local address for a particular peer as a CAddress
2014-07-20 23:32:25 -07: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.
2022-07-04 18:02:28 +02:00
CService GetLocalAddress ( const CNetAddr & addrPeer )
2012-02-12 13:45:24 +01:00
{
2012-05-10 20:35:13 +02:00
CService addr ;
2022-07-04 18:02:28 +02:00
if ( GetLocal ( addr , & addrPeer ) ) {
2022-08-10 15:09:29 +02:00
return addr ;
2012-02-12 13:45:24 +01:00
}
2022-08-10 15:09:29 +02:00
return CService { CNetAddr ( ) , GetListenPort ( ) } ;
2012-02-12 13:45:24 +01:00
}
2010-08-29 16:58:15 +00:00
2018-05-02 17:14:48 +02:00
static int GetnScore ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
2022-01-19 07:04:52 -03:00
LOCK ( g_maplocalhost_mutex ) ;
2021-09-06 00:10:31 +02:00
const auto it = mapLocalHost . find ( addr ) ;
return ( it ! = mapLocalHost . end ( ) ) ? it - > second . nScore : 0 ;
2014-07-20 23:32:25 -07:00
}
// Is our peer's addrLocal potentially useful as an external IP source?
bool IsPeerAddrLocalGood ( CNode * pnode )
{
2017-02-06 12:18:51 -05:00
CService addrLocal = pnode - > GetAddrLocal ( ) ;
return fDiscover & & pnode - > addr . IsRoutable ( ) & & addrLocal . IsRoutable ( ) & &
2019-01-09 16:41:37 -08:00
IsReachable ( addrLocal . GetNetwork ( ) ) ;
2014-07-20 23:32:25 -07:00
}
2022-07-04 18:02:28 +02:00
std : : optional < CService > GetLocalAddrForPeer ( CNode & node )
2014-07-20 23:32:25 -07:00
{
2022-07-04 18:02:28 +02:00
CService addrLocal { GetLocalAddress ( node . addr ) } ;
2020-07-09 07:52:48 +01:00
if ( gArgs . GetBoolArg ( " -addrmantest " , false ) ) {
// use IPv4 loopback during addrmantest
2022-07-04 18:02:28 +02:00
addrLocal = CService ( LookupNumeric ( " 127.0.0.1 " , GetListenPort ( ) ) ) ;
2020-07-09 07:52:48 +01: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.
FastRandomContext rng ;
2022-07-04 18:02:28 +02:00
if ( IsPeerAddrLocalGood ( & node ) & & ( ! addrLocal . IsRoutable ( ) | |
2020-07-09 07:52:48 +01:00
rng . randbits ( ( GetnScore ( addrLocal ) > LOCAL_MANUAL ) ? 3 : 1 ) = = 0 ) )
2012-02-12 13:45:24 +01:00
{
2022-07-04 18:02:28 +02:00
if ( node . IsInboundConn ( ) ) {
2020-10-18 14:45:35 +02:00
// For inbound connections, assume both the address and the port
// as seen from the peer.
2022-07-04 18:02:28 +02:00
addrLocal = CService { node . GetAddrLocal ( ) } ;
2020-10-18 14:45:35 +02:00
} else {
// For outbound connections, assume just the address as seen from
// the peer and leave the port in `addrLocal` as returned by
// `GetLocalAddress()` above. The peer has no way to observe our
// listening port when we have initiated the connection.
2022-07-04 18:02:28 +02:00
addrLocal . SetIP ( node . GetAddrLocal ( ) ) ;
2020-10-18 14:45:35 +02:00
}
2020-07-09 07:52:48 +01:00
}
if ( addrLocal . IsRoutable ( ) | | gArgs . GetBoolArg ( " -addrmantest " , false ) )
{
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " Advertising address %s to peer=%d \n " , addrLocal . ToStringAddrPort ( ) , node . GetId ( ) ) ;
2020-07-09 07:52:48 +01:00
return addrLocal ;
2012-02-12 13:45:24 +01:00
}
2020-07-09 07:42:11 +01:00
// Address is unroutable. Don't advertise.
2021-03-15 10:41:30 +08:00
return std : : nullopt ;
2012-02-12 13:45:24 +01:00
}
2021-09-13 13:02:05 +02:00
/**
* If an IPv6 address belongs to the address range used by the CJDNS network and
* the CJDNS network is reachable ( - cjdnsreachable config is set ) , then change
* the type from NET_IPV6 to NET_CJDNS .
* @ param [ in ] service Address to potentially convert .
* @ return a copy of ` service ` either unmodified or changed to CJDNS .
*/
CService MaybeFlipIPv6toCJDNS ( const CService & service )
{
CService ret { service } ;
if ( ret . m_net = = NET_IPV6 & & ret . m_addr [ 0 ] = = 0xfc & & IsReachable ( NET_CJDNS ) ) {
ret . m_net = NET_CJDNS ;
}
return ret ;
}
2012-02-12 13:45:24 +01:00
// learn a new local address
2021-09-13 13:02:05 +02:00
bool AddLocal ( const CService & addr_ , int nScore )
2012-02-12 13:45:24 +01:00
{
2021-09-13 13:02:05 +02:00
CService addr { MaybeFlipIPv6toCJDNS ( addr_ ) } ;
2012-02-12 13:45:24 +01:00
if ( ! addr . IsRoutable ( ) )
return false ;
2012-05-24 19:02:21 +02:00
if ( ! fDiscover & & nScore < LOCAL_MANUAL )
2012-05-13 14:11:53 +02:00
return false ;
2019-01-09 16:41:37 -08:00
if ( ! IsReachable ( addr ) )
2012-05-13 15:11:51 +02:00
return false ;
2022-07-15 14:13:39 +02:00
LogPrintf ( " AddLocal(%s,%i) \n " , addr . ToStringAddrPort ( ) , nScore ) ;
2012-02-12 13:45:24 +01:00
{
2022-01-19 07:04:52 -03:00
LOCK ( g_maplocalhost_mutex ) ;
2021-09-06 00:10:31 +02:00
const auto [ it , is_newly_added ] = mapLocalHost . emplace ( addr , LocalServiceInfo ( ) ) ;
LocalServiceInfo & info = it - > second ;
if ( is_newly_added | | nScore > = info . nScore ) {
info . nScore = nScore + ( is_newly_added ? 0 : 1 ) ;
2012-08-29 02:33:25 +02:00
info . nPort = addr . GetPort ( ) ;
2012-05-13 00:41:24 +02:00
}
2012-02-12 13:45:24 +01:00
}
return true ;
}
2012-05-13 01:26:14 +02:00
bool AddLocal ( const CNetAddr & addr , int nScore )
2012-05-10 20:35:13 +02:00
{
2012-05-13 01:26:14 +02:00
return AddLocal ( CService ( addr , GetListenPort ( ) ) , nScore ) ;
2012-05-10 20:35:13 +02:00
}
2018-07-27 08:22:42 +02:00
void RemoveLocal ( const CService & addr )
2015-09-08 17:48:45 +02:00
{
2022-01-19 07:04:52 -03:00
LOCK ( g_maplocalhost_mutex ) ;
2022-07-15 14:13:39 +02:00
LogPrintf ( " RemoveLocal(%s) \n " , addr . ToStringAddrPort ( ) ) ;
2015-09-08 17:48:45 +02:00
mapLocalHost . erase ( addr ) ;
}
2019-01-09 16:41:37 -08:00
void SetReachable ( enum Network net , bool reachable )
2012-05-04 16:46:22 +02:00
{
2017-05-23 20:04:38 -04:00
if ( net = = NET_UNROUTABLE | | net = = NET_INTERNAL )
2012-05-14 17:15:58 +02:00
return ;
2022-01-19 07:04:52 -03:00
LOCK ( g_maplocalhost_mutex ) ;
2019-01-09 16:41:37 -08:00
vfLimited [ net ] = ! reachable ;
2012-05-04 16:46:22 +02:00
}
2019-01-09 16:41:37 -08:00
bool IsReachable ( enum Network net )
2012-05-04 16:46:22 +02:00
{
2022-01-19 07:04:52 -03:00
LOCK ( g_maplocalhost_mutex ) ;
2019-01-09 16:41:37 -08:00
return ! vfLimited [ net ] ;
2012-05-14 17:15:58 +02:00
}
2019-01-09 16:41:37 -08:00
bool IsReachable ( const CNetAddr & addr )
2012-05-14 17:15:58 +02:00
{
2019-01-09 16:41:37 -08:00
return IsReachable ( addr . GetNetwork ( ) ) ;
2012-05-04 16:46:22 +02:00
}
/** vote for a local address */
2012-05-10 20:35:13 +02:00
bool SeenLocal ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
2022-01-19 07:04:52 -03:00
LOCK ( g_maplocalhost_mutex ) ;
2021-09-06 00:10:31 +02:00
const auto it = mapLocalHost . find ( addr ) ;
if ( it = = mapLocalHost . end ( ) ) return false ;
+ + it - > second . nScore ;
2012-02-12 13:45:24 +01:00
return true ;
}
2014-07-20 23:32:25 -07:00
2012-05-04 16:46:22 +02:00
/** check whether a given address is potentially local */
2012-05-10 20:35:13 +02:00
bool IsLocal ( const CService & addr )
2012-02-12 13:45:24 +01:00
{
2022-01-19 07:04:52 -03:00
LOCK ( g_maplocalhost_mutex ) ;
2012-02-12 13:45:24 +01:00
return mapLocalHost . count ( addr ) > 0 ;
}
2010-08-29 16:58:15 +00:00
2016-04-16 19:13:12 -04:00
CNode * CConnman : : FindNode ( const CNetAddr & ip )
2010-08-29 16:58:15 +00:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( CNode * pnode : m_nodes ) {
2017-06-01 16:13:35 +02:00
if ( static_cast < CNetAddr > ( pnode - > addr ) = = ip ) {
2017-07-20 11:32:47 +02:00
return pnode ;
}
}
2017-08-07 07:36:37 +02:00
return nullptr ;
2010-08-29 16:58:15 +00:00
}
2016-04-16 19:13:12 -04:00
CNode * CConnman : : FindNode ( const CSubNet & subNet )
2015-05-25 20:03:51 +02:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( CNode * pnode : m_nodes ) {
2017-06-01 16:13:35 +02:00
if ( subNet . Match ( static_cast < CNetAddr > ( pnode - > addr ) ) ) {
2017-07-20 11:32:47 +02:00
return pnode ;
}
}
2017-08-07 07:36:37 +02:00
return nullptr ;
2015-05-25 20:03:51 +02:00
}
2016-04-16 19:13:12 -04:00
CNode * CConnman : : FindNode ( const std : : string & addrName )
2012-04-19 17:38:03 +02:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( CNode * pnode : m_nodes ) {
2021-08-26 10:39:10 +02:00
if ( pnode - > m_addr_name = = addrName ) {
2017-07-20 11:32:47 +02:00
return pnode ;
2017-02-06 12:04:34 -05:00
}
}
2017-08-07 07:36:37 +02:00
return nullptr ;
2012-04-19 17:38:03 +02:00
}
2016-04-16 19:13:12 -04:00
CNode * CConnman : : FindNode ( const CService & addr )
2010-08-29 16:58:15 +00:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( CNode * pnode : m_nodes ) {
2017-06-01 16:13:35 +02:00
if ( static_cast < CService > ( pnode - > addr ) = = addr ) {
2017-07-20 11:32:47 +02:00
return pnode ;
}
}
2017-08-07 07:36:37 +02:00
return nullptr ;
2010-08-29 16:58:15 +00:00
}
2020-10-16 11:10:17 -04:00
bool CConnman : : AlreadyConnectedToAddress ( const CAddress & addr )
{
2022-07-18 13:28:40 +02:00
return FindNode ( static_cast < CNetAddr > ( addr ) ) | | FindNode ( addr . ToStringAddrPort ( ) ) ;
2020-10-16 11:10:17 -04:00
}
2016-04-17 20:21:58 -04:00
bool CConnman : : CheckIncomingNonce ( uint64_t nonce )
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * pnode : m_nodes ) {
2020-07-28 13:39:38 -07:00
if ( ! pnode - > fSuccessfullyConnected & & ! pnode - > IsInboundConn ( ) & & pnode - > GetLocalNonce ( ) = = nonce )
2016-04-17 20:21:58 -04:00
return false ;
}
return true ;
}
2017-05-30 11:59:42 +02:00
/** Get the bind address for a socket as CAddress */
2021-04-13 15:11:20 +02:00
static CAddress GetBindAddress ( const Sock & sock )
2017-05-30 11:59:42 +02:00
{
CAddress addr_bind ;
struct sockaddr_storage sockaddr_bind ;
socklen_t sockaddr_bind_len = sizeof ( sockaddr_bind ) ;
2021-04-13 15:11:20 +02:00
if ( sock . Get ( ) ! = INVALID_SOCKET ) {
if ( ! sock . GetSockName ( ( struct sockaddr * ) & sockaddr_bind , & sockaddr_bind_len ) ) {
2017-05-30 11:59:42 +02:00
addr_bind . SetSockAddr ( ( const struct sockaddr * ) & sockaddr_bind ) ;
} else {
2022-05-25 11:31:58 +02:00
LogPrintLevel ( BCLog : : NET , BCLog : : Level : : Warning , " getsockname failed \n " ) ;
2017-05-30 11:59:42 +02:00
}
}
return addr_bind ;
}
2020-04-29 17:33:06 -07:00
CNode * CConnman : : ConnectNode ( CAddress addrConnect , const char * pszDest , bool fCountFailure , ConnectionType conn_type )
2010-08-29 16:58:15 +00:00
{
2023-01-06 11:23:46 +01:00
AssertLockNotHeld ( m_unused_i2p_sessions_mutex ) ;
2020-04-29 14:55:59 -07:00
assert ( conn_type ! = ConnectionType : : INBOUND ) ;
2017-08-07 07:36:37 +02:00
if ( pszDest = = nullptr ) {
2012-02-12 13:45:24 +01:00
if ( IsLocal ( addrConnect ) )
2017-08-07 07:36:37 +02:00
return nullptr ;
2010-08-29 16:58:15 +00:00
2012-04-19 17:38:03 +02:00
// Look for an existing connection
2017-06-01 16:13:35 +02:00
CNode * pnode = FindNode ( static_cast < CService > ( addrConnect ) ) ;
2012-04-19 17:38:03 +02:00
if ( pnode )
{
2017-01-24 16:51:22 -05:00
LogPrintf ( " Failed to open new connection, already connected \n " ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2012-04-19 17:38:03 +02:00
}
2010-08-29 16:58:15 +00:00
}
2022-05-25 11:31:58 +02:00
LogPrintLevel ( BCLog : : NET , BCLog : : Level : : Debug , " trying connection %s lastseen=%.1fhrs \n " ,
2022-07-15 14:13:39 +02:00
pszDest ? pszDest : addrConnect . ToStringAddrPort ( ) ,
2022-03-24 19:56:00 +01:00
Ticks < HoursDouble > ( pszDest ? 0 h : Now < NodeSeconds > ( ) - addrConnect . nTime ) ) ;
2010-08-29 16:58:15 +00:00
2017-06-22 14:01:04 -04:00
// Resolve
2021-05-31 17:30:18 +02:00
const uint16_t default_port { pszDest ! = nullptr ? Params ( ) . GetDefaultPort ( pszDest ) :
Params ( ) . GetDefaultPort ( ) } ;
2017-06-22 14:01:04 -04:00
if ( pszDest ) {
2022-10-10 15:02:59 -03:00
const std : : vector < CService > resolved { Lookup ( pszDest , default_port , fNameLookup & & ! HaveNameProxy ( ) , 256 ) } ;
if ( ! resolved . empty ( ) ) {
const CService & rnd { resolved [ GetRand ( resolved . size ( ) ) ] } ;
2021-09-13 13:02:05 +02:00
addrConnect = CAddress { MaybeFlipIPv6toCJDNS ( rnd ) , NODE_NONE } ;
2017-06-22 14:01:04 -04:00
if ( ! addrConnect . IsValid ( ) ) {
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " Resolver returned invalid address %s for %s \n " , addrConnect . ToStringAddrPort ( ) , pszDest ) ;
2017-06-22 14:01:04 -04:00
return nullptr ;
}
2016-05-28 16:22:02 +02:00
// It is possible that we already have a connection to the IP/port pszDest resolved to.
2021-08-24 19:19:58 +02:00
// In that case, drop the connection that was just created.
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
2017-06-01 16:13:35 +02:00
CNode * pnode = FindNode ( static_cast < CService > ( addrConnect ) ) ;
2021-08-24 19:19:58 +02:00
if ( pnode ) {
2017-01-24 16:51:22 -05:00
LogPrintf ( " Failed to open new connection, already connected \n " ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-05-28 16:22:02 +02:00
}
}
2017-06-22 14:01:04 -04:00
}
2016-05-28 16:22:02 +02:00
2017-06-22 14:01:04 -04:00
// Connect
bool connected = false ;
2020-12-23 16:40:11 +01:00
std : : unique_ptr < Sock > sock ;
2021-11-08 17:34:32 +01:00
Proxy proxy ;
2020-11-25 14:42:33 +01:00
CAddress addr_bind ;
assert ( ! addr_bind . IsValid ( ) ) ;
2022-06-08 17:59:32 +02:00
std : : unique_ptr < i2p : : sam : : Session > i2p_transient_session ;
2020-11-25 14:42:33 +01:00
2017-06-22 14:01:04 -04:00
if ( addrConnect . IsValid ( ) ) {
2022-06-08 17:59:32 +02:00
const bool use_proxy { GetProxy ( addrConnect . GetNetwork ( ) , proxy ) } ;
2017-06-22 14:01:04 -04:00
bool proxyConnectionFailed = false ;
2022-06-08 17:59:32 +02:00
if ( addrConnect . GetNetwork ( ) = = NET_I2P & & use_proxy ) {
2020-11-25 14:42:33 +01:00
i2p : : Connection conn ;
2022-06-08 17:59:32 +02:00
if ( m_i2p_sam_session ) {
connected = m_i2p_sam_session - > Connect ( addrConnect , conn , proxyConnectionFailed ) ;
} else {
2023-01-06 11:23:46 +01:00
{
LOCK ( m_unused_i2p_sessions_mutex ) ;
if ( m_unused_i2p_sessions . empty ( ) ) {
i2p_transient_session =
std : : make_unique < i2p : : sam : : Session > ( proxy . proxy , & interruptNet ) ;
} else {
i2p_transient_session . swap ( m_unused_i2p_sessions . front ( ) ) ;
m_unused_i2p_sessions . pop ( ) ;
}
}
2022-06-08 17:59:32 +02:00
connected = i2p_transient_session - > Connect ( addrConnect , conn , proxyConnectionFailed ) ;
2023-01-06 11:23:46 +01:00
if ( ! connected ) {
LOCK ( m_unused_i2p_sessions_mutex ) ;
if ( m_unused_i2p_sessions . size ( ) < MAX_UNUSED_I2P_SESSIONS_SIZE ) {
m_unused_i2p_sessions . emplace ( i2p_transient_session . release ( ) ) ;
}
}
2022-06-08 17:59:32 +02:00
}
if ( connected ) {
2021-03-04 14:31:49 +01:00
sock = std : : move ( conn . sock ) ;
2020-11-25 14:42:33 +01:00
addr_bind = CAddress { conn . me , NODE_NONE } ;
}
2022-06-08 17:59:32 +02:00
} else if ( use_proxy ) {
2020-12-23 16:40:11 +01:00
sock = CreateSock ( proxy . proxy ) ;
if ( ! sock ) {
2017-09-18 18:45:51 -04:00
return nullptr ;
}
2022-07-18 13:28:40 +02:00
connected = ConnectThroughProxy ( proxy , addrConnect . ToStringAddr ( ) , addrConnect . GetPort ( ) ,
2020-12-28 16:57:10 +01:00
* sock , nConnectTimeout , proxyConnectionFailed ) ;
2017-09-18 18:45:51 -04:00
} else {
// no proxy needed (none set for target network)
2020-12-23 16:40:11 +01:00
sock = CreateSock ( addrConnect ) ;
if ( ! sock ) {
2017-09-18 18:45:51 -04:00
return nullptr ;
}
2021-03-05 17:01:59 +01:00
connected = ConnectSocketDirectly ( addrConnect , * sock , nConnectTimeout ,
2020-12-23 16:40:11 +01:00
conn_type = = ConnectionType : : MANUAL ) ;
2017-09-18 18:45:51 -04: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 ) ) {
2020-12-23 16:40:11 +01:00
sock = CreateSock ( proxy . proxy ) ;
if ( ! sock ) {
2017-09-18 18:45:51 -04:00
return nullptr ;
}
2017-06-22 14:01:04 -04:00
std : : string host ;
2021-03-01 21:35:28 +01:00
uint16_t port { default_port } ;
2017-06-22 14:01:04 -04:00
SplitHostPort ( std : : string ( pszDest ) , port , host ) ;
2019-12-11 16:39:29 +00:00
bool proxyConnectionFailed ;
2020-12-28 16:57:10 +01:00
connected = ConnectThroughProxy ( proxy , host , port , * sock , nConnectTimeout ,
2020-12-23 16:40:11 +01:00
proxyConnectionFailed ) ;
2017-06-22 14:01:04 -04:00
}
2017-10-02 14:18:32 -04:00
if ( ! connected ) {
return nullptr ;
2010-08-29 16:58:15 +00:00
}
2014-05-24 11:14:52 +02:00
2017-10-02 14:18:32 -04:00
// Add node
NodeId id = GetNewNodeId ( ) ;
uint64_t nonce = GetDeterministicRandomizer ( RANDOMIZER_ID_LOCALHOSTNONCE ) . Write ( id ) . Finalize ( ) ;
2020-11-25 14:42:33 +01:00
if ( ! addr_bind . IsValid ( ) ) {
2021-04-13 15:11:20 +02:00
addr_bind = GetBindAddress ( * sock ) ;
2020-11-25 14:42:33 +01:00
}
2022-01-28 06:31:41 +01:00
CNode * pnode = new CNode ( id ,
std : : move ( sock ) ,
addrConnect ,
CalculateKeyedNetGroup ( addrConnect ) ,
nonce ,
addr_bind ,
pszDest ? pszDest : " " ,
conn_type ,
2022-06-08 17:59:32 +02:00
/*inbound_onion=*/ false ,
2023-03-24 15:45:50 +01:00
CNodeOptions {
. i2p_sam_session = std : : move ( i2p_transient_session ) ,
. recv_flood_size = nReceiveFloodSize ,
} ) ;
2017-10-02 14:18:32 -04:00
pnode - > AddRef ( ) ;
2019-11-23 11:42:23 -05:00
// We're making a new connection, harvest entropy from the time (and our peer count)
RandAddEvent ( ( uint32_t ) id ) ;
2017-10-02 14:18:32 -04:00
return pnode ;
2010-08-29 16:58:15 +00:00
}
void CNode : : CloseSocketDisconnect ( )
{
fDisconnect = true ;
2021-04-23 15:30:46 +02:00
LOCK ( m_sock_mutex ) ;
2021-04-23 15:15:23 +02:00
if ( m_sock ) {
2016-12-25 20:19:40 +00:00
LogPrint ( BCLog : : NET , " disconnecting peer=%d \n " , id ) ;
2021-04-23 15:15:23 +02:00
m_sock . reset ( ) ;
2010-08-29 16:58:15 +00:00
}
2022-06-08 17:26:24 +02:00
m_i2p_sam_session . reset ( ) ;
2010-08-29 16:58:15 +00:00
}
2019-06-20 18:37:51 +09: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 13:34:36 +02:00
}
}
2021-08-24 19:19:58 +02:00
CService CNode : : GetAddrLocal ( ) const
{
2022-01-20 17:28:37 -03:00
AssertLockNotHeld ( m_addr_local_mutex ) ;
2022-01-20 05:41:33 -03:00
LOCK ( m_addr_local_mutex ) ;
2017-02-06 12:18:51 -05:00
return addrLocal ;
}
void CNode : : SetAddrLocal ( const CService & addrLocalIn ) {
2022-01-20 17:28:37 -03:00
AssertLockNotHeld ( m_addr_local_mutex ) ;
2022-01-20 05:41:33 -03:00
LOCK ( m_addr_local_mutex ) ;
2017-02-06 12:18:51 -05:00
if ( addrLocal . IsValid ( ) ) {
2022-07-15 14:13:39 +02:00
error ( " Addr local already set for node: %i. Refusing to change from %s to %s " , id , addrLocal . ToStringAddrPort ( ) , addrLocalIn . ToStringAddrPort ( ) ) ;
2017-02-06 12:18:51 -05:00
} else {
addrLocal = addrLocalIn ;
}
}
2020-09-30 19:19:19 +03:00
Network CNode : : ConnectedThroughNetwork ( ) const
{
2020-10-21 11:52:19 +02:00
return m_inbound_onion ? NET_ONION : addr . GetNetClass ( ) ;
2020-09-30 19:19:19 +03:00
}
2012-06-29 17:24:53 -04:00
# undef X
# define X(name) stats.name = name
2021-09-01 11:24:46 +01:00
void CNode : : CopyStats ( CNodeStats & stats )
2012-06-29 17:24:53 -04:00
{
2013-11-18 01:25:17 +01:00
stats . nodeid = this - > GetId ( ) ;
2016-10-04 19:27:11 -04:00
X ( addr ) ;
2017-05-30 11:59:42 +02:00
X ( addrBind ) ;
2020-12-25 14:25:45 +01:00
stats . m_network = ConnectedThroughNetwork ( ) ;
2021-10-22 11:06:23 +02:00
X ( m_last_send ) ;
X ( m_last_recv ) ;
2021-12-13 12:32:28 +01:00
X ( m_last_tx_time ) ;
X ( m_last_block_time ) ;
X ( m_connected ) ;
2014-12-15 11:06:15 +01:00
X ( nTimeOffset ) ;
2021-08-26 10:39:10 +02:00
X ( m_addr_name ) ;
2012-06-29 17:24:53 -04:00
X ( nVersion ) ;
2017-02-06 12:08:31 -05:00
{
2022-01-16 02:11:04 +01:00
LOCK ( m_subver_mutex ) ;
2017-02-06 12:08:31 -05:00
X ( cleanSubVer ) ;
}
2020-07-28 13:39:38 -07:00
stats . fInbound = IsInboundConn ( ) ;
2020-08-21 15:17:42 +02:00
X ( m_bip152_highbandwidth_to ) ;
X ( m_bip152_highbandwidth_from ) ;
2017-02-06 02:34:57 -05:00
{
LOCK ( cs_vSend ) ;
2022-04-07 17:13:52 +05:30
X ( mapSendBytesPerMsgType ) ;
2017-02-06 02:34:57 -05:00
X ( nSendBytes ) ;
}
{
LOCK ( cs_vRecv ) ;
2022-04-07 17:13:52 +05:30
X ( mapRecvBytesPerMsgType ) ;
2017-02-06 02:34:57 -05:00
X ( nRecvBytes ) ;
}
2022-09-01 18:50:26 +10:00
X ( m_permission_flags ) ;
2013-11-15 12:24:34 +01:00
2020-09-29 19:11:53 -07:00
X ( m_last_ping_time ) ;
X ( m_min_ping_time ) ;
2013-11-15 12:24:34 +01:00
2013-08-21 22:50:19 -07:00
// Leave string empty if addrLocal invalid (not filled in yet)
2017-02-06 12:18:51 -05:00
CService addrLocalUnlocked = GetAddrLocal ( ) ;
2022-07-15 14:13:39 +02:00
stats . addrLocal = addrLocalUnlocked . IsValid ( ) ? addrLocalUnlocked . ToStringAddrPort ( ) : " " ;
2020-08-12 13:57:13 -07:00
2021-01-02 10:44:03 +01:00
X ( m_conn_type ) ;
2012-06-29 17:24:53 -04:00
}
# undef X
2010-08-29 16:58:15 +00:00
2020-11-20 10:16:10 +01:00
bool CNode : : ReceiveMsgBytes ( Span < const uint8_t > msg_bytes , bool & complete )
2012-11-15 19:41:12 -05:00
{
2016-04-18 21:33:54 -04:00
complete = false ;
2020-04-14 13:24:18 -04:00
const auto time = GetTime < std : : chrono : : microseconds > ( ) ;
2017-02-06 02:34:57 -05:00
LOCK ( cs_vRecv ) ;
2020-07-10 18:19:11 +02:00
m_last_recv = std : : chrono : : duration_cast < std : : chrono : : seconds > ( time ) ;
2020-09-30 17:08:26 +02:00
nRecvBytes + = msg_bytes . size ( ) ;
while ( msg_bytes . size ( ) > 0 ) {
2012-11-15 19:41:12 -05:00
// absorb network data
2020-09-30 17:08:26 +02: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 04:01:22 -08:00
2019-06-13 11:25:54 +02:00
if ( m_deserializer - > Complete ( ) ) {
2019-06-13 10:39:44 +02:00
// decompose a transport agnostic CNetMessage from the deserializer
2020-11-05 05:05:32 -05:00
bool reject_message { false } ;
CNetMessage msg = m_deserializer - > GetMessage ( time , reject_message ) ;
if ( reject_message ) {
2022-01-29 18:58:07 +05:30
// 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
2022-04-07 17:13:52 +05:30
mapRecvBytesPerMsgType . at ( NET_MESSAGE_TYPE_OTHER ) + = msg . m_raw_message_size ;
2020-06-29 14:15:06 -04:00
continue ;
}
2019-06-13 10:39:44 +02:00
2022-01-29 18:58:07 +05:30
// Store received bytes per message type.
// To prevent a memory DOS, only allow known message types.
2022-04-07 17:13:52 +05:30
auto i = mapRecvBytesPerMsgType . find ( msg . m_type ) ;
if ( i = = mapRecvBytesPerMsgType . end ( ) ) {
i = mapRecvBytesPerMsgType . find ( NET_MESSAGE_TYPE_OTHER ) ;
2020-11-05 05:05:32 -05:00
}
2022-04-07 17:13:52 +05:30
assert ( i ! = mapRecvBytesPerMsgType . end ( ) ) ;
2020-11-05 05:05:32 -05:00
i - > second + = msg . m_raw_message_size ;
2019-06-13 10:39:44 +02:00
// push the message to the process queue,
2020-11-05 05:05:32 -05:00
vRecvMsg . push_back ( std : : move ( msg ) ) ;
2015-08-25 16:30:31 +02:00
2016-04-18 21:33:54 -04:00
complete = true ;
2015-04-05 02:35:37 -07:00
}
2012-11-15 19:41:12 -05:00
}
return true ;
}
2020-11-20 10:16:10 +01:00
int V1TransportDeserializer : : readHeader ( Span < const uint8_t > msg_bytes )
2012-11-15 19:41:12 -05:00
{
// copy data to temporary parsing buffer
2020-05-10 15:47:32 +02:00
unsigned int nRemaining = CMessageHeader : : HEADER_SIZE - nHdrPos ;
2020-09-30 17:08:26 +02:00
unsigned int nCopy = std : : min < unsigned int > ( nRemaining , msg_bytes . size ( ) ) ;
2012-11-15 19:41:12 -05:00
2020-09-30 17:08:26 +02:00
memcpy ( & hdrbuf [ nHdrPos ] , msg_bytes . data ( ) , nCopy ) ;
2012-11-15 19:41:12 -05:00
nHdrPos + = nCopy ;
// if header incomplete, exit
2020-05-10 15:47:32 +02:00
if ( nHdrPos < CMessageHeader : : HEADER_SIZE )
2012-11-15 19:41:12 -05:00
return nCopy ;
// deserialize to CMessageHeader
try {
hdrbuf > > hdr ;
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & ) {
2021-05-07 07:45:55 +02:00
LogPrint ( BCLog : : NET , " Header error: Unable to deserialize, peer=%d \n " , m_node_id ) ;
2020-05-26 17:01:57 -04:00
return - 1 ;
}
// Check start string, network magic
if ( memcmp ( hdr . pchMessageStart , m_chain_params . MessageStart ( ) , CMessageHeader : : MESSAGE_START_SIZE ) ! = 0 ) {
2021-05-07 07:45:55 +02:00
LogPrint ( BCLog : : NET , " Header error: Wrong MessageStart %s received, peer=%d \n " , HexStr ( hdr . pchMessageStart ) , m_node_id ) ;
2012-11-15 19:41:12 -05:00
return - 1 ;
}
2019-10-18 11:57:10 -07:00
// reject messages larger than MAX_SIZE or MAX_PROTOCOL_MESSAGE_LENGTH
if ( hdr . nMessageSize > MAX_SIZE | | hdr . nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH ) {
2021-05-07 07:45:55 +02:00
LogPrint ( BCLog : : NET , " Header error: Size too large (%s, %u bytes), peer=%d \n " , SanitizeString ( hdr . GetCommand ( ) ) , hdr . nMessageSize , m_node_id ) ;
2017-03-06 17:54:08 +01:00
return - 1 ;
2019-10-18 11:57:10 -07:00
}
2012-11-15 19:41:12 -05:00
// switch state to reading message data
in_data = true ;
return nCopy ;
}
2020-11-20 10:16:10 +01:00
int V1TransportDeserializer : : readData ( Span < const uint8_t > msg_bytes )
2012-11-15 19:41:12 -05:00
{
unsigned int nRemaining = hdr . nMessageSize - nDataPos ;
2020-09-30 17:08:26 +02:00
unsigned int nCopy = std : : min < unsigned int > ( nRemaining , msg_bytes . size ( ) ) ;
2012-11-15 19:41:12 -05:00
2014-06-21 17:00:38 +02:00
if ( vRecv . size ( ) < nDataPos + nCopy ) {
// Allocate up to 256 KiB ahead, but never more than the total message size.
vRecv . resize ( std : : min ( hdr . nMessageSize , nDataPos + nCopy + 256 * 1024 ) ) ;
}
2020-11-20 10:16:10 +01:00
hasher . Write ( msg_bytes . first ( nCopy ) ) ;
2020-09-30 17:08:26 +02:00
memcpy ( & vRecv [ nDataPos ] , msg_bytes . data ( ) , nCopy ) ;
2012-11-15 19:41:12 -05:00
nDataPos + = nCopy ;
return nCopy ;
}
2019-06-13 11:25:54 +02:00
const uint256 & V1TransportDeserializer : : GetMessageHash ( ) const
2016-10-30 18:02:16 -04:00
{
2019-06-13 11:25:54 +02:00
assert ( Complete ( ) ) ;
2016-10-30 18:02:16 -04:00
if ( data_hash . IsNull ( ) )
2020-06-18 17:19:46 -07:00
hasher . Finalize ( data_hash ) ;
2016-10-30 18:02:16 -04:00
return data_hash ;
}
2020-11-05 05:05:32 -05:00
CNetMessage V1TransportDeserializer : : GetMessage ( const std : : chrono : : microseconds time , bool & reject_message )
2020-04-14 13:24:18 -04:00
{
2020-11-05 05:05:32 -05:00
// Initialize out parameter
reject_message = false ;
2019-06-13 10:39:44 +02:00
// decompose a single CNetMessage from the TransportDeserializer
2020-11-05 05:05:32 -05:00
CNetMessage msg ( std : : move ( vRecv ) ) ;
2019-06-13 10:39:44 +02:00
2022-01-29 18:58:07 +05:30
// store message type string, time, and sizes
2022-01-15 20:59:19 +02:00
msg . m_type = hdr . GetCommand ( ) ;
2020-11-05 05:05:32 -05:00
msg . m_time = time ;
msg . m_message_size = hdr . nMessageSize ;
msg . m_raw_message_size = hdr . nMessageSize + CMessageHeader : : HEADER_SIZE ;
2019-06-13 10:39:44 +02:00
2020-06-08 22:26:22 -04:00
uint256 hash = GetMessageHash ( ) ;
2019-06-13 10:39:44 +02:00
2019-11-23 11:42:23 -05:00
// We just received a message off the wire, harvest entropy from the time (and the message checksum)
RandAddEvent ( ReadLE32 ( hash . begin ( ) ) ) ;
2022-01-29 18:58:07 +05:30
// Check checksum and header message type string
2020-06-29 14:15:06 -04:00
if ( memcmp ( hash . begin ( ) , hdr . pchChecksum , CMessageHeader : : CHECKSUM_SIZE ) ! = 0 ) {
2021-05-07 07:45:55 +02:00
LogPrint ( BCLog : : NET , " Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d \n " ,
2022-01-15 20:59:19 +02:00
SanitizeString ( msg . m_type ) , msg . m_message_size ,
2021-11-02 10:07:46 -04:00
HexStr ( Span { hash } . first ( CMessageHeader : : CHECKSUM_SIZE ) ) ,
2020-06-29 14:09:42 -04:00
HexStr ( hdr . pchChecksum ) ,
m_node_id ) ;
2020-11-05 05:05:32 -05:00
reject_message = true ;
2020-05-26 17:01:57 -04:00
} else if ( ! hdr . IsCommandValid ( ) ) {
2021-05-07 07:45:55 +02:00
LogPrint ( BCLog : : NET , " Header error: Invalid message type (%s, %u bytes), peer=%d \n " ,
2020-11-05 05:05:32 -05:00
SanitizeString ( hdr . GetCommand ( ) ) , msg . m_message_size , m_node_id ) ;
reject_message = true ;
2019-06-13 10:39:44 +02:00
}
2020-06-29 14:15:06 -04:00
// Always reset the network deserializer (prepare for the next message)
2019-06-13 10:39:44 +02:00
Reset ( ) ;
return msg ;
}
2022-03-05 04:09:35 +10:00
void V1TransportSerializer : : prepareForTransport ( CSerializedNetMsg & msg , std : : vector < unsigned char > & header ) const
{
2019-08-07 15:56:24 +02:00
// create dbl-sha256 checksum
2020-06-26 13:36:41 -07:00
uint256 hash = Hash ( msg . data ) ;
2019-08-07 15:56:24 +02:00
// create header
2020-05-10 19:48:11 +02:00
CMessageHeader hdr ( Params ( ) . MessageStart ( ) , msg . m_type . c_str ( ) , msg . data . size ( ) ) ;
2019-08-07 15:56:24 +02: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 } ;
}
2021-01-06 08:12:28 +01:00
size_t CConnman : : SocketSendData ( CNode & node ) const
2012-11-15 18:04:52 -05:00
{
2021-01-06 08:12:28 +01:00
auto it = node . vSendMsg . begin ( ) ;
2016-05-21 12:04:02 +02:00
size_t nSentSize = 0 ;
2013-03-24 16:52:24 +01:00
2021-01-06 08:12:28 +01:00
while ( it ! = node . vSendMsg . end ( ) ) {
const auto & data = * it ;
assert ( data . size ( ) > node . nSendOffset ) ;
2017-02-06 14:05:45 -05:00
int nBytes = 0 ;
{
2021-04-23 15:30:46 +02:00
LOCK ( node . m_sock_mutex ) ;
2021-04-23 15:15:23 +02:00
if ( ! node . m_sock ) {
2017-02-06 14:05:45 -05:00
break ;
2021-04-23 15:15:23 +02:00
}
2018-02-23 14:02:37 -05:00
int flags = MSG_NOSIGNAL | MSG_DONTWAIT ;
# ifdef MSG_MORE
if ( it + 1 ! = node . vSendMsg . end ( ) ) {
flags | = MSG_MORE ;
}
# endif
nBytes = node . m_sock - > Send ( reinterpret_cast < const char * > ( data . data ( ) ) + node . nSendOffset , data . size ( ) - node . nSendOffset , flags ) ;
2017-02-06 14:05:45 -05:00
}
2013-03-24 16:52:24 +01:00
if ( nBytes > 0 ) {
2020-07-10 18:19:11 +02:00
node . m_last_send = GetTime < std : : chrono : : seconds > ( ) ;
2021-01-06 08:12:28 +01:00
node . nSendBytes + = nBytes ;
node . nSendOffset + = nBytes ;
2016-05-21 12:04:02 +02:00
nSentSize + = nBytes ;
2021-01-06 08:12:28 +01:00
if ( node . nSendOffset = = data . size ( ) ) {
node . nSendOffset = 0 ;
node . nSendSize - = data . size ( ) ;
node . fPauseSend = node . nSendSize > nSendBufferMaxSize ;
2013-03-24 16:52:24 +01:00
it + + ;
} else {
// could not send full message; stop sending more
break ;
}
} else {
if ( nBytes < 0 ) {
// error
int nErr = WSAGetLastError ( ) ;
2021-01-06 08:12:28 +01:00
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS ) {
2020-12-18 07:40:37 +10:00
LogPrint ( BCLog : : NET , " socket send error for peer=%d: %s \n " , node . GetId ( ) , NetworkErrorString ( nErr ) ) ;
2021-01-06 08:12:28 +01:00
node . CloseSocketDisconnect ( ) ;
2013-03-24 16:52:24 +01:00
}
}
// couldn't send anything at all
break ;
2012-11-15 18:04:52 -05:00
}
}
2013-03-24 16:52:24 +01:00
2021-01-06 08:12:28 +01:00
if ( it = = node . vSendMsg . end ( ) ) {
assert ( node . nSendOffset = = 0 ) ;
assert ( node . nSendSize = = 0 ) ;
2013-03-24 16:52:24 +01:00
}
2021-01-06 08:12:28 +01:00
node . vSendMsg . erase ( node . vSendMsg . begin ( ) , it ) ;
2016-05-21 12:04:02 +02:00
return nSentSize ;
2012-11-15 18:04:52 -05:00
}
2010-08-29 16:58:15 +00:00
2020-09-18 12:47:08 +00:00
/** Try to find a connection to evict when the node is full.
* Extreme care must be taken to avoid opening the node to attacker
* triggered network partitioning .
* The strategy used here is to protect a small number of peers
* for each of several distinct characteristics which are difficult
* to forge . In order to partition a node the attacker must be
* simultaneously better at all of them than honest peers .
*/
bool CConnman : : AttemptToEvictConnection ( )
{
std : : vector < NodeEvictionCandidate > vEvictionCandidates ;
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * node : m_nodes ) {
2020-09-18 12:47:08 +00:00
if ( node - > fDisconnect )
continue ;
2022-03-11 10:14:31 +01:00
NodeEvictionCandidate candidate {
2022-07-01 01:23:02 +02:00
. id = node - > GetId ( ) ,
. m_connected = node - > m_connected ,
. m_min_ping_time = node - > m_min_ping_time ,
. m_last_block_time = node - > m_last_block_time ,
. m_last_tx_time = node - > m_last_tx_time ,
2020-07-20 18:46:13 +01:00
. fRelevantServices = node - > m_has_all_wanted_services ,
2022-07-01 01:23:02 +02:00
. m_relay_txs = node - > m_relays_txs . load ( ) ,
. fBloomFilter = node - > m_bloom_filter_loaded . load ( ) ,
. nKeyedNetGroup = node - > nKeyedNetGroup ,
. prefer_evict = node - > m_prefer_evict ,
. m_is_local = node - > addr . IsLocal ( ) ,
. m_network = node - > ConnectedThroughNetwork ( ) ,
. m_noban = node - > HasPermission ( NetPermissionFlags : : NoBan ) ,
2023-03-24 15:29:21 +01:00
. m_conn_type = node - > m_conn_type ,
2022-03-11 10:14:31 +01:00
} ;
2020-09-18 12:47:08 +00:00
vEvictionCandidates . push_back ( candidate ) ;
}
}
2021-03-15 10:41:30 +08:00
const std : : optional < NodeId > node_id_to_evict = SelectNodeToEvict ( std : : move ( vEvictionCandidates ) ) ;
2020-09-18 12:47:08 +00:00
if ( ! node_id_to_evict ) {
return false ;
}
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( CNode * pnode : m_nodes ) {
2020-09-18 12:47:08 +00:00
if ( pnode - > GetId ( ) = = * node_id_to_evict ) {
2020-12-18 07:18:28 +10:00
LogPrint ( BCLog : : NET , " selected %s connection for eviction peer=%d; disconnecting \n " , pnode - > ConnectionTypeAsString ( ) , pnode - > GetId ( ) ) ;
2017-07-20 11:32:47 +02:00
pnode - > fDisconnect = true ;
2016-04-18 15:58:19 -04:00
return true ;
}
}
return false ;
2015-08-13 02:58:58 -07:00
}
2016-04-16 14:47:18 -04:00
void CConnman : : AcceptConnection ( const ListenSocket & hListenSocket ) {
2015-08-13 02:00:10 -07:00
struct sockaddr_storage sockaddr ;
socklen_t len = sizeof ( sockaddr ) ;
2021-04-23 12:15:15 +02:00
auto sock = hListenSocket . sock - > Accept ( ( struct sockaddr * ) & sockaddr , & len ) ;
2015-08-13 02:00:10 -07:00
CAddress addr ;
2021-04-23 12:15:15 +02:00
if ( ! sock ) {
2020-11-24 12:15:07 +01:00
const int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK ) {
LogPrintf ( " socket error accept failed: %s \n " , NetworkErrorString ( nErr ) ) ;
2017-05-30 11:59:42 +02:00
}
2020-11-24 12:15:07 +01:00
return ;
}
if ( ! addr . SetSockAddr ( ( const struct sockaddr * ) & sockaddr ) ) {
2022-05-25 11:31:58 +02:00
LogPrintLevel ( BCLog : : NET , BCLog : : Level : : Warning , " Unknown socket family \n " ) ;
2021-09-13 13:02:05 +02:00
} else {
addr = CAddress { MaybeFlipIPv6toCJDNS ( addr ) , NODE_NONE } ;
2017-05-30 11:59:42 +02:00
}
2015-08-13 02:00:10 -07:00
2021-04-13 15:11:20 +02:00
const CAddress addr_bind { MaybeFlipIPv6toCJDNS ( GetBindAddress ( * sock ) ) , NODE_NONE } ;
2020-11-24 12:24:18 +01:00
2022-09-01 18:50:26 +10:00
NetPermissionFlags permission_flags = NetPermissionFlags : : None ;
hListenSocket . AddSocketPermissionFlags ( permission_flags ) ;
2020-11-24 12:40:03 +01:00
2022-09-01 18:50:26 +10:00
CreateNodeFromAcceptedSocket ( std : : move ( sock ) , permission_flags , addr_bind , addr ) ;
2020-11-24 12:40:03 +01:00
}
2021-04-13 12:14:57 +02:00
void CConnman : : CreateNodeFromAcceptedSocket ( std : : unique_ptr < Sock > & & sock ,
2022-09-01 18:50:26 +10:00
NetPermissionFlags permission_flags ,
2020-11-24 12:40:03 +01:00
const CAddress & addr_bind ,
const CAddress & addr )
{
int nInbound = 0 ;
int nMaxInbound = nMaxConnections - m_max_outbound ;
2022-09-01 18:50:26 +10:00
AddWhitelistPermissionFlags ( permission_flags , addr ) ;
if ( NetPermissions : : HasFlag ( permission_flags , NetPermissionFlags : : Implicit ) ) {
NetPermissions : : ClearFlag ( permission_flags , NetPermissionFlags : : Implicit ) ;
if ( gArgs . GetBoolArg ( " -whitelistforcerelay " , DEFAULT_WHITELISTFORCERELAY ) ) NetPermissions : : AddFlag ( permission_flags , NetPermissionFlags : : ForceRelay ) ;
if ( gArgs . GetBoolArg ( " -whitelistrelay " , DEFAULT_WHITELISTRELAY ) ) NetPermissions : : AddFlag ( permission_flags , NetPermissionFlags : : Relay ) ;
NetPermissions : : AddFlag ( permission_flags , NetPermissionFlags : : Mempool ) ;
NetPermissions : : AddFlag ( permission_flags , NetPermissionFlags : : NoBan ) ;
2019-06-20 18:37:51 +09:00
}
2015-08-13 02:00:10 -07:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * pnode : m_nodes ) {
2020-07-28 13:39:38 -07:00
if ( pnode - > IsInboundConn ( ) ) nInbound + + ;
2017-07-20 11:32:47 +02:00
}
2015-08-13 02:00:10 -07:00
}
2013-03-26 02:33:25 +01:00
if ( ! fNetworkActive ) {
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " connection from %s dropped: not accepting new connections \n " , addr . ToStringAddrPort ( ) ) ;
2013-03-26 02:33:25 +01:00
return ;
}
2021-04-13 14:29:14 +02:00
if ( ! sock - > IsSelectable ( ) ) {
2022-07-15 14:13:39 +02:00
LogPrintf ( " connection from %s dropped: non-selectable socket \n " , addr . ToStringAddrPort ( ) ) ;
2015-08-13 02:16:46 -07:00
return ;
2015-08-13 02:00:10 -07:00
}
2015-08-13 02:16:46 -07:00
2015-10-21 23:52:29 +00:00
// According to the internet TCP_NODELAY is not carried into accepted sockets
// on all platforms. Set it again here just to be sure.
2021-04-13 14:01:44 +02:00
const int on { 1 } ;
if ( sock - > SetSockOpt ( IPPROTO_TCP , TCP_NODELAY , & on , sizeof ( on ) ) = = SOCKET_ERROR ) {
LogPrint ( BCLog : : NET , " connection from %s: unable to set TCP_NODELAY, continuing anyway \n " ,
2022-07-15 14:13:39 +02:00
addr . ToStringAddrPort ( ) ) ;
2021-04-13 14:01:44 +02:00
}
2015-10-21 23:52:29 +00:00
2020-06-08 18:46:53 -07:00
// Don't accept connections from banned peers.
2020-07-14 10:24:43 +01:00
bool banned = m_banman & & m_banman - > IsBanned ( addr ) ;
2022-09-01 18:50:26 +10:00
if ( ! NetPermissions : : HasFlag ( permission_flags , NetPermissionFlags : : NoBan ) & & banned )
2015-08-13 02:00:10 -07:00
{
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " connection from %s dropped (banned) \n " , addr . ToStringAddrPort ( ) ) ;
2015-08-13 02:16:46 -07:00
return ;
2015-08-13 02:00:10 -07:00
}
2015-08-13 02:16:46 -07:00
2020-06-08 18:46:53 -07:00
// Only accept connections from discouraged peers if our inbound slots aren't (almost) full.
2020-07-14 10:24:43 +01:00
bool discouraged = m_banman & & m_banman - > IsDiscouraged ( addr ) ;
2022-09-01 18:50:26 +10:00
if ( ! NetPermissions : : HasFlag ( permission_flags , NetPermissionFlags : : NoBan ) & & nInbound + 1 > = nMaxInbound & & discouraged )
2020-06-08 18:46:53 -07:00
{
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " connection from %s dropped (discouraged) \n " , addr . ToStringAddrPort ( ) ) ;
2020-06-08 18:46:53 -07:00
return ;
}
2015-08-13 02:19:17 -07:00
if ( nInbound > = nMaxInbound )
2015-08-13 02:00:10 -07:00
{
2016-05-22 05:55:15 +00:00
if ( ! AttemptToEvictConnection ( ) ) {
2015-08-13 02:58:58 -07:00
// No connection to evict, disconnect the new connection
2016-12-25 20:19:40 +00:00
LogPrint ( BCLog : : NET , " failed to find an eviction candidate - connection dropped (full) \n " ) ;
2015-08-13 02:58:58 -07:00
return ;
}
2015-08-13 02:00:10 -07:00
}
2016-10-26 15:10:15 -04:00
NodeId id = GetNewNodeId ( ) ;
uint64_t nonce = GetDeterministicRandomizer ( RANDOMIZER_ID_LOCALHOSTNONCE ) . Write ( id ) . Finalize ( ) ;
2019-06-20 18:37:51 +09:00
ServiceFlags nodeServices = nLocalServices ;
2022-09-01 18:50:26 +10:00
if ( NetPermissions : : HasFlag ( permission_flags , NetPermissionFlags : : BloomFilter ) ) {
2019-06-20 18:37:51 +09:00
nodeServices = static_cast < ServiceFlags > ( nodeServices | NODE_BLOOM ) ;
}
2020-09-30 19:07:36 +03:00
const bool inbound_onion = std : : find ( m_onion_binds . begin ( ) , m_onion_binds . end ( ) , addr_bind ) ! = m_onion_binds . end ( ) ;
2022-01-28 06:31:41 +01:00
CNode * pnode = new CNode ( id ,
std : : move ( sock ) ,
addr ,
CalculateKeyedNetGroup ( addr ) ,
nonce ,
addr_bind ,
/*addrNameIn=*/ " " ,
ConnectionType : : INBOUND ,
2022-09-01 18:44:07 +10:00
inbound_onion ,
CNodeOptions {
2023-03-24 15:45:50 +01:00
. permission_flags = permission_flags ,
. prefer_evict = discouraged ,
. recv_flood_size = nReceiveFloodSize ,
2022-09-01 18:44:07 +10:00
} ) ;
2015-08-13 02:16:46 -07:00
pnode - > AddRef ( ) ;
2020-07-20 14:01:05 +01:00
m_msgproc - > InitializeNode ( * pnode , nodeServices ) ;
2015-08-13 02:00:10 -07:00
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " connection from %s accepted \n " , addr . ToStringAddrPort ( ) ) ;
2015-08-13 02:16:46 -07:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
m_nodes . push_back ( pnode ) ;
2015-08-13 02:00:10 -07:00
}
2019-11-23 11:42:23 -05:00
// We received a new connection, harvest entropy from the time (and our peer count)
RandAddEvent ( ( uint32_t ) id ) ;
2015-08-13 02:00:10 -07:00
}
2020-06-02 09:46:41 -07:00
bool CConnman : : AddConnection ( const std : : string & address , ConnectionType conn_type )
{
2023-01-06 11:23:46 +01:00
AssertLockNotHeld ( m_unused_i2p_sessions_mutex ) ;
2021-05-31 22:49:42 +02:00
std : : optional < int > max_connections ;
switch ( conn_type ) {
case ConnectionType : : INBOUND :
case ConnectionType : : MANUAL :
return false ;
case ConnectionType : : OUTBOUND_FULL_RELAY :
max_connections = m_max_outbound_full_relay ;
break ;
case ConnectionType : : BLOCK_RELAY :
max_connections = m_max_outbound_block_relay ;
break ;
// no limit for ADDR_FETCH because -seednode has no limit either
case ConnectionType : : ADDR_FETCH :
break ;
2021-08-23 10:42:39 +01:00
// no limit for FEELER connections since they're short-lived
case ConnectionType : : FEELER :
break ;
2021-05-31 22:49:42 +02:00
} // no default case, so the compiler can warn about missing cases
2020-06-02 09:46:41 -07:00
// Count existing connections
2021-08-28 20:57:52 +02:00
int existing_connections = WITH_LOCK ( m_nodes_mutex ,
2023-03-24 15:29:21 +01:00
return std : : count_if ( m_nodes . begin ( ) , m_nodes . end ( ) , [ conn_type ] ( CNode * node ) { return node - > m_conn_type = = conn_type ; } ) ; ) ;
2020-06-02 09:46:41 -07:00
// Max connections of specified type already exist
2021-05-31 22:49:42 +02:00
if ( max_connections ! = std : : nullopt & & existing_connections > = max_connections ) return false ;
2020-06-02 09:46:41 -07:00
// Max total outbound connections already exist
CSemaphoreGrant grant ( * semOutbound , true ) ;
if ( ! grant ) return false ;
OpenNetworkConnection ( CAddress ( ) , false , & grant , address . c_str ( ) , conn_type ) ;
return true ;
}
2018-09-24 16:36:58 -04:00
void CConnman : : DisconnectNodes ( )
2010-08-29 16:58:15 +00:00
{
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
2018-05-10 18:23:22 +02:00
2018-09-24 16:36:58 -04:00
if ( ! fNetworkActive ) {
// Disconnect any connected nodes
2021-08-28 20:57:52 +02:00
for ( CNode * pnode : m_nodes ) {
2018-09-24 16:36:58 -04:00
if ( ! pnode - > fDisconnect ) {
LogPrint ( BCLog : : NET , " Network not active, dropping peer=%d \n " , pnode - > GetId ( ) ) ;
pnode - > fDisconnect = true ;
2018-05-10 18:23:22 +02:00
}
}
2018-09-24 16:36:58 -04:00
}
2018-05-10 18:23:22 +02:00
2018-09-24 16:36:58 -04:00
// Disconnect unused nodes
2021-08-28 20:57:52 +02:00
std : : vector < CNode * > nodes_copy = m_nodes ;
for ( CNode * pnode : nodes_copy )
2018-09-24 16:36:58 -04:00
{
if ( pnode - > fDisconnect )
2010-08-29 16:58:15 +00:00
{
2021-08-28 20:57:52 +02:00
// remove from m_nodes
m_nodes . erase ( remove ( m_nodes . begin ( ) , m_nodes . end ( ) , pnode ) , m_nodes . end ( ) ) ;
2010-08-29 16:58:15 +00:00
2018-09-24 16:36:58 -04:00
// release outbound grant (if any)
pnode - > grantOutbound . Release ( ) ;
2012-04-04 16:01:57 +02:00
2018-09-24 16:36:58 -04:00
// close socket and cleanup
pnode - > CloseSocketDisconnect ( ) ;
2010-08-29 16:58:15 +00:00
2018-09-24 16:36:58 -04:00
// hold in disconnected pool until all refs are released
pnode - > Release ( ) ;
2021-08-28 20:57:52 +02:00
m_nodes_disconnected . push_back ( pnode ) ;
2010-08-29 16:58:15 +00:00
}
2013-07-25 02:25:25 +02:00
}
2018-09-24 16:36:58 -04:00
}
{
// Delete disconnected nodes
2021-08-28 20:57:52 +02:00
std : : list < CNode * > nodes_disconnected_copy = m_nodes_disconnected ;
for ( CNode * pnode : nodes_disconnected_copy )
2013-07-25 02:25:25 +02:00
{
2021-04-22 11:06:13 +02:00
// Destroy the object only after other threads have stopped using it.
2018-09-24 16:36:58 -04:00
if ( pnode - > GetRefCount ( ) < = 0 ) {
2021-08-28 20:57:52 +02:00
m_nodes_disconnected . remove ( pnode ) ;
2021-04-22 11:06:13 +02:00
DeleteNode ( pnode ) ;
2010-08-29 16:58:15 +00:00
}
}
2018-09-24 16:36:58 -04:00
}
}
void CConnman : : NotifyNumConnectionsChanged ( )
{
2021-08-28 20:57:52 +02:00
size_t nodes_size ;
2018-09-24 16:36:58 -04:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
nodes_size = m_nodes . size ( ) ;
2018-09-24 16:36:58 -04:00
}
2021-08-28 20:57:52 +02:00
if ( nodes_size ! = nPrevNodeCount ) {
nPrevNodeCount = nodes_size ;
2021-08-18 13:41:39 +08:00
if ( m_client_interface ) {
2021-08-28 20:57:52 +02:00
m_client_interface - > NotifyNumConnectionsChanged ( nodes_size ) ;
2021-08-18 13:37:27 +08:00
}
2018-09-24 16:36:58 -04:00
}
}
2020-07-10 18:19:11 +02:00
bool CConnman : : ShouldRunInactivityChecks ( const CNode & node , std : : chrono : : seconds now ) const
2021-02-12 10:01:55 +00:00
{
2021-12-13 12:32:28 +01:00
return node . m_connected + m_peer_connect_timeout < now ;
2021-02-12 10:01:55 +00:00
}
2021-01-06 11:12:51 +00:00
bool CConnman : : InactivityCheck ( const CNode & node ) const
2018-09-24 16:43:00 -04:00
{
2020-07-10 18:19:11 +02:00
// Tests that see disconnects after using mocktime can start nodes with a
// large timeout. For example, -peertimeout=999999999.
const auto now { GetTime < std : : chrono : : seconds > ( ) } ;
const auto last_send { node . m_last_send . load ( ) } ;
const auto last_recv { node . m_last_recv . load ( ) } ;
2021-01-06 11:12:51 +00:00
2021-02-16 15:55:03 +00:00
if ( ! ShouldRunInactivityChecks ( node , now ) ) return false ;
2020-07-10 18:19:11 +02:00
if ( last_recv . count ( ) = = 0 | | last_send . count ( ) = = 0 ) {
LogPrint ( BCLog : : NET , " socket no message in first %i seconds, %d %d peer=%d \n " , count_seconds ( m_peer_connect_timeout ) , last_recv . count ( ) ! = 0 , last_send . count ( ) ! = 0 , node . GetId ( ) ) ;
2021-01-06 11:12:51 +00:00
return true ;
}
2020-07-10 18:19:11 +02:00
if ( now > last_send + TIMEOUT_INTERVAL ) {
LogPrint ( BCLog : : NET , " socket sending timeout: %is peer=%d \n " , count_seconds ( now - last_send ) , node . GetId ( ) ) ;
2021-01-06 11:12:51 +00:00
return true ;
}
2020-07-10 18:19:11 +02:00
if ( now > last_recv + TIMEOUT_INTERVAL ) {
LogPrint ( BCLog : : NET , " socket receive timeout: %is peer=%d \n " , count_seconds ( now - last_recv ) , node . GetId ( ) ) ;
2021-01-06 11:12:51 +00:00
return true ;
}
if ( ! node . fSuccessfullyConnected ) {
2020-12-18 07:41:34 +10:00
LogPrint ( BCLog : : NET , " version handshake timeout peer=%d \n " , node . GetId ( ) ) ;
2021-01-06 11:12:51 +00:00
return true ;
}
return false ;
2018-09-24 16:43:00 -04:00
}
2010-08-29 16:58:15 +00:00
2021-05-04 18:37:19 +02:00
Sock : : EventsPerSock CConnman : : GenerateWaitSockets ( Span < CNode * const > nodes )
2018-09-24 16:36:58 -04:00
{
2021-05-04 18:37:19 +02:00
Sock : : EventsPerSock events_per_sock ;
2018-09-24 17:03:17 -04:00
for ( const ListenSocket & hListenSocket : vhListenSocket ) {
2021-05-04 18:37:19 +02:00
events_per_sock . emplace ( hListenSocket . sock , Sock : : Events { Sock : : RECV } ) ;
2018-09-24 17:03:17 -04:00
}
2014-06-24 09:09:45 +02:00
2021-10-25 13:49:33 +02:00
for ( CNode * pnode : nodes ) {
// 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 16:58:15 +00:00
{
2021-10-25 13:49:33 +02:00
LOCK ( pnode - > cs_vSend ) ;
select_send = ! pnode - > vSendMsg . empty ( ) ;
}
2017-02-06 13:47:24 -05:00
2021-04-23 15:30:46 +02:00
LOCK ( pnode - > m_sock_mutex ) ;
2021-04-23 15:15:23 +02:00
if ( ! pnode - > m_sock ) {
2021-10-25 13:49:33 +02:00
continue ;
2021-04-23 15:15:23 +02:00
}
2017-02-06 14:05:45 -05:00
2021-05-04 18:37:19 +02:00
Sock : : Event requested { 0 } ;
2021-10-25 13:49:33 +02:00
if ( select_send ) {
2021-05-04 18:37:19 +02:00
requested = Sock : : SEND ;
} else if ( select_recv ) {
requested = Sock : : RECV ;
2021-10-25 13:49:33 +02:00
}
2018-09-26 21:54:52 -04:00
2021-05-04 18:37:19 +02:00
events_per_sock . emplace ( pnode - > m_sock , Sock : : Events { requested } ) ;
2018-09-26 21:54:52 -04:00
}
2021-05-04 18:37:19 +02:00
return events_per_sock ;
2018-09-26 21:54:52 -04:00
}
2018-09-26 21:51:46 -04:00
void CConnman : : SocketHandler ( )
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2021-05-04 18:37:19 +02:00
Sock : : EventsPerSock events_per_sock ;
2018-09-26 21:51:46 -04:00
2018-09-24 17:03:17 -04:00
{
2021-10-25 11:03:58 +02:00
const NodesSnapshot snap { * this , /*shuffle=*/ false } ;
2018-09-24 17:03:17 -04:00
2021-05-04 18:37:19 +02:00
const auto timeout = std : : chrono : : milliseconds ( SELECT_TIMEOUT_MILLISECONDS ) ;
2021-10-25 11:03:58 +02:00
// Check for the readiness of the already connected sockets and the
// listening sockets in one call ("readiness" as in poll(2) or
// select(2)). If none are ready, wait for a short while and return
// empty sets.
2021-05-04 18:37:19 +02:00
events_per_sock = GenerateWaitSockets ( snap . Nodes ( ) ) ;
if ( events_per_sock . empty ( ) | | ! events_per_sock . begin ( ) - > first - > WaitMany ( timeout , events_per_sock ) ) {
interruptNet . sleep_for ( timeout ) ;
}
2018-09-26 21:51:46 -04:00
2021-10-25 11:03:58 +02:00
// Service (send/receive) each of the already connected nodes.
2021-05-04 18:37:19 +02:00
SocketHandlerConnected ( snap . Nodes ( ) , events_per_sock ) ;
2018-09-24 17:03:17 -04:00
}
2021-10-25 11:03:58 +02:00
// Accept new connections from listening sockets.
2021-05-04 18:37:19 +02:00
SocketHandlerListening ( events_per_sock ) ;
2021-10-25 11:03:58 +02:00
}
void CConnman : : SocketHandlerConnected ( const std : : vector < CNode * > & nodes ,
2021-05-04 18:37:19 +02:00
const Sock : : EventsPerSock & events_per_sock )
2021-10-25 11:03:58 +02:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2021-10-25 11:03:58 +02:00
for ( CNode * pnode : nodes ) {
2018-09-24 17:03:17 -04:00
if ( interruptNet )
return ;
2010-08-29 16:58:15 +00:00
//
2018-09-24 17:03:17 -04:00
// Receive
2010-08-29 16:58:15 +00:00
//
2018-09-24 17:03:17 -04:00
bool recvSet = false ;
bool sendSet = false ;
bool errorSet = false ;
2010-08-29 16:58:15 +00:00
{
2021-04-23 15:30:46 +02:00
LOCK ( pnode - > m_sock_mutex ) ;
2021-04-23 15:15:23 +02:00
if ( ! pnode - > m_sock ) {
2018-09-24 17:03:17 -04:00
continue ;
2021-04-23 15:15:23 +02:00
}
2021-05-04 18:37:19 +02:00
const auto it = events_per_sock . find ( pnode - > m_sock ) ;
if ( it ! = events_per_sock . end ( ) ) {
recvSet = it - > second . occurred & Sock : : RECV ;
sendSet = it - > second . occurred & Sock : : SEND ;
errorSet = it - > second . occurred & Sock : : ERR ;
}
2010-08-29 16:58:15 +00:00
}
2018-09-24 17:03:17 -04:00
if ( recvSet | | errorSet )
2010-08-29 16:58:15 +00:00
{
2018-09-24 17:03:17 -04:00
// typical socket buffer is 8K-64K
2020-11-20 10:16:10 +01:00
uint8_t pchBuf [ 0x10000 ] ;
2018-09-24 17:03:17 -04:00
int nBytes = 0 ;
2017-02-06 14:05:45 -05:00
{
2021-04-23 15:30:46 +02:00
LOCK ( pnode - > m_sock_mutex ) ;
2021-04-23 15:15:23 +02:00
if ( ! pnode - > m_sock ) {
2017-02-06 14:05:45 -05:00
continue ;
2021-04-23 15:15:23 +02:00
}
nBytes = pnode - > m_sock - > Recv ( pchBuf , sizeof ( pchBuf ) , MSG_DONTWAIT ) ;
2017-02-06 14:05:45 -05:00
}
2018-09-24 17:03:17 -04:00
if ( nBytes > 0 )
2010-08-29 16:58:15 +00:00
{
2018-09-24 17:03:17 -04:00
bool notify = false ;
2021-11-02 10:07:46 -04:00
if ( ! pnode - > ReceiveMsgBytes ( { pchBuf , ( size_t ) nBytes } , notify ) ) {
2017-03-06 17:54:08 +01:00
pnode - > CloseSocketDisconnect ( ) ;
2021-11-02 10:07:46 -04:00
}
2018-09-24 17:03:17 -04:00
RecordBytesRecv ( nBytes ) ;
if ( notify ) {
2023-03-24 15:45:50 +01:00
pnode - > MarkReceivedMsgsForProcessing ( ) ;
2018-09-24 17:03:17 -04:00
WakeMessageHandler ( ) ;
2010-08-29 16:58:15 +00:00
}
}
2018-09-24 17:03:17 -04:00
else if ( nBytes = = 0 )
2010-08-29 16:58:15 +00:00
{
2018-09-24 17:03:17 -04:00
// socket closed gracefully
if ( ! pnode - > fDisconnect ) {
2019-10-25 15:30:35 +02:00
LogPrint ( BCLog : : NET , " socket closed for peer=%d \n " , pnode - > GetId ( ) ) ;
2016-04-18 21:44:42 -04:00
}
2018-09-24 17:03:17 -04:00
pnode - > CloseSocketDisconnect ( ) ;
2010-08-29 16:58:15 +00:00
}
2018-09-24 17:03:17 -04:00
else if ( nBytes < 0 )
2010-08-29 16:58:15 +00:00
{
2018-09-24 17:03:17 -04:00
// error
int nErr = WSAGetLastError ( ) ;
if ( nErr ! = WSAEWOULDBLOCK & & nErr ! = WSAEMSGSIZE & & nErr ! = WSAEINTR & & nErr ! = WSAEINPROGRESS )
2017-02-07 15:23:17 -05:00
{
2019-10-25 15:30:35 +02:00
if ( ! pnode - > fDisconnect ) {
LogPrint ( BCLog : : NET , " socket recv error for peer=%d: %s \n " , pnode - > GetId ( ) , NetworkErrorString ( nErr ) ) ;
}
2018-09-24 17:03:17 -04:00
pnode - > CloseSocketDisconnect ( ) ;
2017-02-07 15:23:17 -05:00
}
2010-08-29 16:58:15 +00:00
}
}
2018-09-24 17:03:17 -04:00
2020-12-27 09:22:04 +00:00
if ( sendSet ) {
// Send data
2021-01-06 08:12:28 +01:00
size_t bytes_sent = WITH_LOCK ( pnode - > cs_vSend , return SocketSendData ( * pnode ) ) ;
2020-12-27 09:22:04 +00:00
if ( bytes_sent ) RecordBytesSent ( bytes_sent ) ;
2010-08-29 16:58:15 +00:00
}
2018-09-24 17:03:17 -04:00
2021-02-16 15:55:03 +00:00
if ( InactivityCheck ( * pnode ) ) pnode - > fDisconnect = true ;
2018-09-24 17:03:17 -04:00
}
}
2021-05-04 18:37:19 +02:00
void CConnman : : SocketHandlerListening ( const Sock : : EventsPerSock & events_per_sock )
2021-10-25 11:03:58 +02:00
{
for ( const ListenSocket & listen_socket : vhListenSocket ) {
if ( interruptNet ) {
return ;
}
2021-05-04 18:37:19 +02:00
const auto it = events_per_sock . find ( listen_socket . sock ) ;
if ( it ! = events_per_sock . end ( ) & & it - > second . occurred & Sock : : RECV ) {
2021-10-25 11:03:58 +02:00
AcceptConnection ( listen_socket ) ;
}
2018-09-24 17:03:17 -04:00
}
}
void CConnman : : ThreadSocketHandler ( )
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2018-09-24 17:03:17 -04:00
while ( ! interruptNet )
{
DisconnectNodes ( ) ;
NotifyNumConnectionsChanged ( ) ;
SocketHandler ( ) ;
2010-08-29 16:58:15 +00:00
}
}
2016-12-31 02:05:21 -05:00
void CConnman : : WakeMessageHandler ( )
{
2016-12-31 02:05:26 -05:00
{
2019-05-30 13:44:02 +10:00
LOCK ( mutexMsgProc ) ;
2016-12-31 02:05:26 -05:00
fMsgProcWake = true ;
}
2016-12-31 02:05:21 -05:00
condMsgProc . notify_one ( ) ;
}
2010-08-29 16:58:15 +00:00
2016-04-16 14:47:18 -04:00
void CConnman : : ThreadDNSAddressSeed ( )
2011-11-21 12:25:00 -05:00
{
2019-03-07 15:30:59 -08: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 15:30:59 -08:00
if ( gArgs . GetBoolArg ( " -forcednsseed " , DEFAULT_FORCEDNSSEED ) ) {
// When -forcednsseed is provided, query all.
seeds_right_now = seeds . size ( ) ;
2023-01-13 14:23:38 -08:00
} else if ( addrman . Size ( ) = = 0 ) {
2020-02-11 13:20:21 +10:00
// If we have no known peers, query all.
2020-05-28 10:07:49 +10:00
// This will occur on the first run, or if peers.dat has been
// deleted.
2020-02-11 13:20:21 +10:00
seeds_right_now = seeds . size ( ) ;
2014-07-29 11:04:46 -04:00
}
2020-02-11 13:20:21 +10: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)
2023-01-13 14:23:38 -08:00
const std : : chrono : : seconds seeds_wait_time = ( addrman . Size ( ) > = DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS ) ;
2020-02-11 13:20:21 +10:00
2019-03-07 15:30:59 -08:00
for ( const std : : string & seed : seeds ) {
2020-02-11 13:20:21 +10:00
if ( seeds_right_now = = 0 ) {
seeds_right_now + = DNSSEEDS_TO_QUERY_AT_ONCE ;
2011-03-08 22:40:50 -05:00
2023-01-13 14:23:38 -08:00
if ( addrman . Size ( ) > 0 ) {
2020-02-11 13:20:21 +10:00
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-28 10:07:49 +10: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 13:20:21 +10: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 ;
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * pnode : m_nodes ) {
2021-05-21 13:03:00 +10:00
if ( pnode - > fSuccessfullyConnected & & pnode - > IsFullOutboundConn ( ) ) + + nRelevant ;
2020-02-11 13:20:21 +10: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 15:30:59 -08:00
}
}
2013-01-29 23:13:17 -05:00
2020-02-12 01:32:46 +10:00
if ( interruptNet ) return ;
2020-05-28 10:07:49 +10:00
// hold off on querying seeds if P2P network deactivated
2020-02-12 01:32:46 +10: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 16:29:57 -04:00
}
2020-02-11 13:20:21 +10:00
2019-03-07 15:30:59 -08:00
LogPrintf ( " Loading addresses from DNS seed %s \n " , seed ) ;
2020-09-25 12:33:47 -07:00
// If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address
// for the base dns seed domain in chainparams
2013-01-29 23:13:17 -05:00
if ( HaveNameProxy ( ) ) {
2020-07-17 14:56:34 -07:00
AddAddrFetch ( seed ) ;
2013-01-29 23:13:17 -05:00
} else {
2016-04-15 19:53:45 -04:00
std : : vector < CAddress > vAdd ;
2017-10-04 17:59:30 -04:00
ServiceFlags requiredServiceBits = GetDesirableServiceFlags ( NODE_NONE ) ;
2017-10-19 17:32:45 -04: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 18:26:29 -05:00
unsigned int nMaxIPs = 256 ; // Limits number of IPs learned from a DNS seed
2022-10-07 11:10:35 -03:00
const auto addresses { LookupHost ( host , nMaxIPs , true ) } ;
if ( ! addresses . empty ( ) ) {
for ( const CNetAddr & ip : addresses ) {
2016-05-21 23:55:22 +02:00
CAddress addr = CAddress ( CService ( ip , Params ( ) . GetDefaultPort ( ) ) , requiredServiceBits ) ;
2022-03-28 14:20:04 +02:00
addr . nTime = rng . rand_uniform_delay ( Now < NodeSeconds > ( ) - 3 * 24 h , - 4 * 24 h ) ; // use a random age between 3 and 7 days old
2013-01-29 23:13:17 -05:00
vAdd . push_back ( addr ) ;
found + + ;
2011-05-02 15:34:42 +02:00
}
2017-05-23 20:48:08 -04:00
addrman . Add ( vAdd , resolveSource ) ;
2017-10-19 17:32:45 -04:00
} else {
2020-09-25 12:33:47 -07:00
// If the seed does not support a subdomain with our desired service bits,
// we make an ADDR_FETCH connection to the DNS resolved peer address for the
// base dns seed domain in chainparams
2020-07-17 14:56:34 -07:00
AddAddrFetch ( seed ) ;
2016-04-12 20:38:06 -04:00
}
2011-03-08 22:40:50 -05:00
}
2019-03-07 15:30:59 -08:00
- - seeds_right_now ;
2011-03-08 22:40:50 -05:00
}
2013-09-18 20:38:08 +10:00
LogPrintf ( " %d addresses found from DNS seeds \n " , found ) ;
2011-03-08 22:40:50 -05:00
}
2010-08-29 16:58:15 +00:00
2016-04-16 17:43:11 -04:00
void CConnman : : DumpAddresses ( )
2012-01-04 23:39:45 +01:00
{
2022-06-28 17:50:53 +02:00
const auto start { SteadyClock : : now ( ) } ;
2012-05-16 22:11:19 -04:00
2021-08-21 11:22:21 +02:00
DumpPeerAddresses ( : : gArgs , addrman ) ;
2012-05-16 22:11:19 -04:00
2016-12-25 20:19:40 +00:00
LogPrint ( BCLog : : NET , " Flushed %d addresses to peers.dat %dms \n " ,
2023-01-13 14:23:38 -08:00
addrman . Size ( ) , Ticks < std : : chrono : : milliseconds > ( SteadyClock : : now ( ) - start ) ) ;
2012-01-04 23:39:45 +01:00
}
2010-08-29 16:58:15 +00:00
2020-07-17 14:56:34 -07:00
void CConnman : : ProcessAddrFetch ( )
2012-04-24 02:15:00 +02:00
{
2023-01-06 11:23:46 +01:00
AssertLockNotHeld ( m_unused_i2p_sessions_mutex ) ;
2016-04-15 19:53:45 -04:00
std : : string strDest ;
2012-04-24 02:15:00 +02:00
{
2020-07-17 14:56:34 -07:00
LOCK ( m_addr_fetches_mutex ) ;
if ( m_addr_fetches . empty ( ) )
2012-04-24 02:15:00 +02:00
return ;
2020-07-17 14:56:34 -07:00
strDest = m_addr_fetches . front ( ) ;
m_addr_fetches . pop_front ( ) ;
2012-04-24 02:15:00 +02:00
}
CAddress addr ;
2012-05-10 18:44:07 +02:00
CSemaphoreGrant grant ( * semOutbound , true ) ;
if ( grant ) {
2020-04-30 10:57:03 -07:00
OpenNetworkConnection ( addr , false , & grant , strDest . c_str ( ) , ConnectionType : : ADDR_FETCH ) ;
2012-05-10 18:44:07 +02:00
}
2012-04-24 02:15:00 +02:00
}
2021-04-17 19:17:40 +02:00
bool CConnman : : GetTryNewOutboundPeer ( ) const
2017-10-23 13:36:15 -04:00
{
return m_try_another_outbound_peer ;
}
void CConnman : : SetTryNewOutboundPeer ( bool flag )
{
m_try_another_outbound_peer = flag ;
scripted-diff: remove duplicate categories from LogPrint output
-BEGIN VERIFY SCRIPT-
s() { git grep -l "$1" src | xargs sed -i "s/$1/$2/g"; }
s 'BCLog::TOR, "tor: ' 'BCLog::TOR, "'
s 'BCLog::I2P, "I2P: ' 'BCLog::I2P, "'
s 'BCLog::NET, "net: ' 'BCLog::NET, "'
s 'BCLog::ZMQ, "zmq: ' 'BCLog::ZMQ, "'
s 'BCLog::PRUNE, "Prune: ' 'BCLog::PRUNE, "'
-END VERIFY SCRIPT-
2022-05-24 21:16:39 +02:00
LogPrint ( BCLog : : NET , " setting try another outbound peer=%s \n " , flag ? " true " : " false " ) ;
2017-10-23 13:36:15 -04:00
}
2022-04-01 18:22:53 +02:00
void CConnman : : StartExtraBlockRelayPeers ( )
{
scripted-diff: remove duplicate categories from LogPrint output
-BEGIN VERIFY SCRIPT-
s() { git grep -l "$1" src | xargs sed -i "s/$1/$2/g"; }
s 'BCLog::TOR, "tor: ' 'BCLog::TOR, "'
s 'BCLog::I2P, "I2P: ' 'BCLog::I2P, "'
s 'BCLog::NET, "net: ' 'BCLog::NET, "'
s 'BCLog::ZMQ, "zmq: ' 'BCLog::ZMQ, "'
s 'BCLog::PRUNE, "Prune: ' 'BCLog::PRUNE, "'
-END VERIFY SCRIPT-
2022-05-24 21:16:39 +02:00
LogPrint ( BCLog : : NET , " enabling extra block-relay-only peers \n " ) ;
2022-04-01 18:22:53 +02:00
m_start_extra_block_relay_peers = true ;
}
2017-10-23 13:36:15 -04: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 10:29:20 +03:00
// disconnected soon (eg ADDR_FETCH and FEELER)
2017-10-23 13:36:15 -04: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)
2021-04-17 19:17:40 +02:00
int CConnman : : GetExtraFullOutboundCount ( ) const
2017-10-23 13:36:15 -04:00
{
2020-09-01 16:32:09 -04:00
int full_outbound_peers = 0 ;
2017-10-23 13:36:15 -04:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * pnode : m_nodes ) {
2020-09-01 16:32:09 -04:00
if ( pnode - > fSuccessfullyConnected & & ! pnode - > fDisconnect & & pnode - > IsFullOutboundConn ( ) ) {
+ + full_outbound_peers ;
2017-10-23 13:36:15 -04:00
}
}
}
2020-09-01 16:32:09 -04:00
return std : : max ( full_outbound_peers - m_max_outbound_full_relay , 0 ) ;
2017-10-23 13:36:15 -04:00
}
2021-04-17 19:17:40 +02:00
int CConnman : : GetExtraBlockRelayCount ( ) const
2020-09-01 17:05:47 -04:00
{
int block_relay_peers = 0 ;
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * pnode : m_nodes ) {
2020-09-01 17:05:47 -04:00
if ( pnode - > fSuccessfullyConnected & & ! pnode - > fDisconnect & & pnode - > IsBlockOnlyConn ( ) ) {
+ + block_relay_peers ;
}
}
}
return std : : max ( block_relay_peers - m_max_outbound_block_relay , 0 ) ;
}
2022-11-30 15:55:22 -05:00
std : : unordered_set < Network > CConnman : : GetReachableEmptyNetworks ( ) const
{
std : : unordered_set < Network > networks { } ;
for ( int n = 0 ; n < NET_MAX ; n + + ) {
enum Network net = ( enum Network ) n ;
if ( net = = NET_UNROUTABLE | | net = = NET_INTERNAL ) continue ;
if ( IsReachable ( net ) & & addrman . Size ( net , std : : nullopt ) = = 0 ) {
networks . insert ( net ) ;
}
}
return networks ;
}
2017-06-15 09:39:07 +02:00
void CConnman : : ThreadOpenConnections ( const std : : vector < std : : string > connect )
2010-08-29 16:58:15 +00:00
{
2023-01-06 11:23:46 +01:00
AssertLockNotHeld ( m_unused_i2p_sessions_mutex ) ;
2022-05-10 09:08:49 +02:00
FastRandomContext rng ;
2010-08-29 16:58:15 +00:00
// Connect to specific addresses
2017-06-15 09:39:07 +02:00
if ( ! connect . empty ( ) )
2010-08-29 16:58:15 +00:00
{
2013-04-13 00:13:08 -05:00
for ( int64_t nLoop = 0 ; ; nLoop + + )
2010-08-29 16:58:15 +00:00
{
2017-06-15 09:39:07 +02:00
for ( const std : : string & strAddr : connect )
2010-08-29 16:58:15 +00:00
{
2016-06-08 19:12:22 +02:00
CAddress addr ( CService ( ) , NODE_NONE ) ;
2020-04-30 10:57:03 -07:00
OpenNetworkConnection ( addr , false , nullptr , strAddr . c_str ( ) , ConnectionType : : MANUAL ) ;
2010-08-29 16:58:15 +00:00
for ( int i = 0 ; i < 10 & & i < nLoop ; i + + )
{
2016-12-27 17:12:44 -05:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2010-08-29 16:58:15 +00:00
}
}
2016-12-27 17:12:44 -05:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2010-08-29 16:58:15 +00:00
}
}
// Initiate network connections
2020-09-29 20:19:57 -07:00
auto start = GetTime < std : : chrono : : microseconds > ( ) ;
2016-06-17 00:10:07 -04:00
// Minimum time before next feeler connection (in microseconds).
2020-04-15 19:06:59 -04:00
auto next_feeler = GetExponentialRand ( start , FEELER_INTERVAL ) ;
auto next_extra_block_relay = GetExponentialRand ( start , EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL ) ;
2020-09-05 09:51:33 -07:00
const bool dnsseed = gArgs . GetBoolArg ( " -dnsseed " , DEFAULT_DNSSEED ) ;
bool add_fixed_seeds = gArgs . GetBoolArg ( " -fixedseeds " , DEFAULT_FIXEDSEEDS ) ;
if ( ! add_fixed_seeds ) {
LogPrintf ( " Fixed seeds are disabled \n " ) ;
}
2016-12-27 17:12:44 -05:00
while ( ! interruptNet )
2010-08-29 16:58:15 +00:00
{
2020-07-17 14:56:34 -07:00
ProcessAddrFetch ( ) ;
2012-04-24 02:15:00 +02:00
2016-12-27 17:12:44 -05:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2012-02-15 21:17:15 +01:00
2012-05-10 18:44:07 +02:00
CSemaphoreGrant grant ( * semOutbound ) ;
2016-12-27 17:12:44 -05:00
if ( interruptNet )
return ;
2010-08-29 16:58:15 +00:00
2022-11-30 15:55:22 -05:00
const std : : unordered_set < Network > fixed_seed_networks { GetReachableEmptyNetworks ( ) } ;
if ( add_fixed_seeds & & ! fixed_seed_networks . empty ( ) ) {
2020-09-05 09:51:33 -07:00
// When the node starts with an empty peers.dat, there are a few other sources of peers before
// we fallback on to fixed seeds: -dnsseed, -seednode, -addnode
// If none of those are available, we fallback on to fixed seeds immediately, else we allow
// 60 seconds for any of those sources to populate addrman.
bool add_fixed_seeds_now = false ;
// It is cheapest to check if enough time has passed first.
if ( GetTime < std : : chrono : : seconds > ( ) > start + std : : chrono : : minutes { 1 } ) {
add_fixed_seeds_now = true ;
2022-11-30 15:55:22 -05:00
LogPrintf ( " Adding fixed seeds as 60 seconds have passed and addrman is empty for at least one reachable network \n " ) ;
2020-09-05 09:51:33 -07:00
}
// Checking !dnsseed is cheaper before locking 2 mutexes.
if ( ! add_fixed_seeds_now & & ! dnsseed ) {
2021-08-28 20:57:52 +02:00
LOCK2 ( m_addr_fetches_mutex , m_added_nodes_mutex ) ;
if ( m_addr_fetches . empty ( ) & & m_added_nodes . empty ( ) ) {
2020-09-05 09:51:33 -07:00
add_fixed_seeds_now = true ;
2022-07-22 14:51:44 -04:00
LogPrintf ( " Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet), -addnode is not provided and all -seednode(s) attempted \n " ) ;
2020-09-05 09:51:33 -07:00
}
}
if ( add_fixed_seeds_now ) {
2022-07-22 13:54:35 -04:00
std : : vector < CAddress > seed_addrs { ConvertSeeds ( Params ( ) . FixedSeeds ( ) ) } ;
2022-09-07 21:30:50 +03:00
// We will not make outgoing connections to peers that are unreachable
// (e.g. because of -onlynet configuration).
// Therefore, we do not add them to addrman in the first place.
2022-11-30 15:55:22 -05:00
// In case previously unreachable networks become reachable
// (e.g. in case of -onlynet changes by the user), fixed seeds will
2023-02-15 14:03:37 -08:00
// be loaded only for networks for which we have no addresses.
2022-07-22 13:54:35 -04:00
seed_addrs . erase ( std : : remove_if ( seed_addrs . begin ( ) , seed_addrs . end ( ) ,
2022-11-30 15:55:22 -05:00
[ & fixed_seed_networks ] ( const CAddress & addr ) { return fixed_seed_networks . count ( addr . GetNetwork ( ) ) = = 0 ; } ) ,
seed_addrs . end ( ) ) ;
2016-05-31 13:05:52 -04:00
CNetAddr local ;
2017-06-21 15:45:20 -04:00
local . SetInternal ( " fixedseeds " ) ;
2022-07-22 13:54:35 -04:00
addrman . Add ( seed_addrs , local ) ;
2020-09-05 09:51:33 -07:00
add_fixed_seeds = false ;
2022-07-22 13:54:35 -04:00
LogPrintf ( " Added %d fixed seeds from reachable networks. \n " , seed_addrs . size ( ) ) ;
2010-08-29 16:58:15 +00:00
}
}
//
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect ;
2023-03-30 20:18:14 +05:30
// Only connect out to one peer per ipv4/ipv6 network group (/16 for IPv4).
2019-03-09 12:55:06 -05:00
int nOutboundFullRelay = 0 ;
int nOutboundBlockRelay = 0 ;
2023-03-30 20:18:14 +05:30
int outbound_privacy_network_peers = 0 ;
2023-04-14 11:01:43 -07:00
std : : set < std : : vector < unsigned char > > outbound_ipv46_peer_netgroups ;
2020-06-02 21:23:44 -07:00
2012-04-06 18:39:12 +02:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * pnode : m_nodes ) {
2020-06-02 21:23:44 -07:00
if ( pnode - > IsFullOutboundConn ( ) ) nOutboundFullRelay + + ;
if ( pnode - > IsBlockOnlyConn ( ) ) nOutboundBlockRelay + + ;
2023-03-30 20:18:14 +05:30
// Make sure our persistent outbound slots to ipv4/ipv6 peers belong to different netgroups.
2023-03-24 15:29:21 +01:00
switch ( pnode - > m_conn_type ) {
2021-09-14 14:54:40 +03:00
// We currently don't take inbound connections into account. Since they are
// free to make, an attacker could make them to prevent us from connecting to
// certain peers.
2020-06-02 21:23:44 -07:00
case ConnectionType : : INBOUND :
2021-09-14 14:54:40 +03:00
// Short-lived outbound connections should not affect how we select outbound
// peers from addrman.
case ConnectionType : : ADDR_FETCH :
case ConnectionType : : FEELER :
2020-06-02 21:23:44 -07:00
break ;
2021-09-14 15:19:41 +03:00
case ConnectionType : : MANUAL :
2020-08-11 20:37:32 -07:00
case ConnectionType : : OUTBOUND_FULL_RELAY :
2020-06-02 21:23:44 -07:00
case ConnectionType : : BLOCK_RELAY :
2023-04-14 11:01:43 -07:00
const CAddress address { pnode - > addr } ;
2023-03-30 20:18:14 +05:30
if ( address . IsTor ( ) | | address . IsI2P ( ) | | address . IsCJDNS ( ) ) {
// Since our addrman-groups for these networks are
// random, without relation to the route we
// take to connect to these peers or to the
// difficulty in obtaining addresses with diverse
// groups, we don't worry about diversity with
// respect to our addrman groups when connecting to
// these networks.
+ + outbound_privacy_network_peers ;
} else {
2023-04-14 11:01:43 -07:00
outbound_ipv46_peer_netgroups . insert ( m_netgroupman . GetGroup ( address ) ) ;
2023-03-30 20:18:14 +05:30
}
2020-08-20 15:26:27 -07:00
} // no default case, so the compiler can warn about missing cases
2012-05-10 18:44:07 +02:00
}
2012-04-06 18:39:12 +02:00
}
2010-08-29 16:58:15 +00:00
2020-08-13 21:54:38 -07:00
ConnectionType conn_type = ConnectionType : : OUTBOUND_FULL_RELAY ;
2020-09-29 20:19:57 -07:00
auto now = GetTime < std : : chrono : : microseconds > ( ) ;
2020-06-05 09:38:09 +03:00
bool anchor = false ;
2016-06-17 00:10:07 -04:00
bool fFeeler = false ;
2017-10-23 13:36:15 -04:00
2020-08-13 21:54:38 -07:00
// Determine what type of connection to open. Opening
2020-06-05 09:38:09 +03:00
// BLOCK_RELAY connections to addresses from anchors.dat gets the highest
// priority. Then we open OUTBOUND_FULL_RELAY priority until we
2020-08-13 21:54:38 -07: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
2020-09-29 20:19:57 -07:00
// block-relay-only peer (to confirm our tip is current, see below) or the next_feeler
2020-09-01 17:05:47 -04:00
// timer to decide if we should open a FEELER.
2020-08-13 21:54:38 -07:00
2020-06-05 09:38:09 +03: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-13 21:54:38 -07: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-29 20:19:57 -07:00
} else if ( now > next_extra_block_relay & & m_start_extra_block_relay_peers ) {
2020-09-01 17:05:47 -04:00
// 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:
2020-04-15 19:06:59 -04:00
// - we do this all the time on an exponential timer, rather than just when
2020-09-01 17:05:47 -04:00
// 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).
2020-04-15 19:06:59 -04:00
next_extra_block_relay = GetExponentialRand ( now , EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL ) ;
2020-09-01 17:05:47 -04:00
conn_type = ConnectionType : : BLOCK_RELAY ;
2020-09-29 20:19:57 -07:00
} else if ( now > next_feeler ) {
2020-04-15 19:06:59 -04:00
next_feeler = GetExponentialRand ( now , FEELER_INTERVAL ) ;
2020-08-13 21:54:38 -07:00
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-03 23:41:47 -04:00
2016-10-27 13:55:39 -04:00
addrman . ResolveCollisions ( ) ;
2022-03-24 19:56:00 +01:00
const auto current_time { NodeClock : : now ( ) } ;
2012-01-04 23:39:45 +01:00
int nTries = 0 ;
2016-12-27 17:12:44 -05:00
while ( ! interruptNet )
2010-08-29 16:58:15 +00:00
{
2020-06-05 09:38:09 +03: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 ) | |
2023-04-14 11:01:43 -07:00
outbound_ipv46_peer_netgroups . count ( m_netgroupman . GetGroup ( addr ) ) ) continue ;
2020-06-05 09:38:09 +03:00
addrConnect = addr ;
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " Trying to make an anchor connection to %s \n " , addrConnect . ToStringAddrPort ( ) ) ;
2020-06-05 09:38:09 +03:00
break ;
}
2020-09-12 18: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 ;
2021-08-25 15:40:59 -07:00
CAddress addr ;
2022-03-28 14:20:04 +02:00
NodeSeconds addr_last_try { 0 s } ;
2020-10-16 14:05:09 -04:00
if ( fFeeler ) {
// First, try to get a tried table collision address. This returns
// an empty (invalid) address if there are no collisions to try.
2021-08-25 15:40:59 -07:00
std : : tie ( addr , addr_last_try ) = addrman . SelectTriedCollision ( ) ;
2020-10-16 14:05:09 -04:00
if ( ! addr . IsValid ( ) ) {
// No tried table collisions. Select a new table address
// for our feeler.
2021-08-25 15:40:59 -07:00
std : : tie ( addr , addr_last_try ) = addrman . Select ( true ) ;
2020-10-16 14:05:09 -04:00
} 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.
2021-08-25 15:40:59 -07:00
std : : tie ( addr , addr_last_try ) = addrman . Select ( true ) ;
2020-10-16 14:05:09 -04:00
}
} else {
// Not a feeler
2021-08-25 15:40:59 -07:00
std : : tie ( addr , addr_last_try ) = addrman . Select ( ) ;
2016-10-27 13:55:39 -04:00
}
2010-08-29 16:58:15 +00:00
2023-04-14 11:01:43 -07:00
// Require outbound IPv4/IPv6 connections, other than feelers, to be to distinct network groups
if ( ! fFeeler & & outbound_ipv46_peer_netgroups . count ( m_netgroupman . GetGroup ( addr ) ) ) {
2019-02-26 15:04:48 -05:00
break ;
}
2019-03-01 16:15:50 -05:00
// if we selected an invalid or local address, restart
2019-02-26 15:04:48 -05:00
if ( ! addr . IsValid ( ) | | IsLocal ( addr ) ) {
2012-01-04 23:39:45 +01:00
break ;
2019-02-26 15:04:48 -05:00
}
2010-08-29 16:58:15 +00:00
2019-01-09 16:41:37 -08:00
if ( ! IsReachable ( addr ) )
2012-05-04 16:46:22 +02:00
continue ;
2012-01-04 23:39:45 +01:00
// only consider very recently tried nodes after 30 failed attempts
2022-03-24 19:56:00 +01:00
if ( current_time - addr_last_try < 10 min & & nTries < 30 ) {
2012-01-04 23:39:45 +01:00
continue ;
2022-03-28 14:20:04 +02:00
}
2012-01-04 23:39:45 +01:00
2017-10-04 17:59:30 -04:00
// for non-feelers, require all the services we'll want,
// for feelers, only require they be a full node (only because most
// SPV clients don't have a good address DB available)
if ( ! fFeeler & & ! HasAllDesirableServiceFlags ( addr . nServices ) ) {
continue ;
} else if ( fFeeler & & ! MayHaveUsefulAddressDB ( addr . nServices ) ) {
2015-11-17 00:20:49 +01:00
continue ;
2017-05-24 17:00:27 -04:00
}
2015-11-17 00:20:49 +01:00
2021-11-18 09:19:09 +01:00
// Do not connect to bad ports, unless 50 invalid addresses have been selected already.
if ( nTries < 50 & & ( addr . IsIPv4 ( ) | | addr . IsIPv6 ( ) ) & & IsBadPort ( addr . GetPort ( ) ) ) {
2012-01-04 23:39:45 +01:00
continue ;
2021-05-31 17:30:18 +02:00
}
2012-01-04 23:39:45 +01:00
addrConnect = addr ;
break ;
2010-08-29 16:58:15 +00: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.
2022-05-10 09:08:49 +02:00
if ( ! interruptNet . sleep_for ( rng . rand_uniform_duration < CThreadInterrupt : : Clock > ( FEELER_SLEEP_WINDOW ) ) ) {
2016-12-27 17:12:44 -05:00
return ;
2022-05-10 09:08:49 +02:00
}
2022-07-15 14:13:39 +02:00
LogPrint ( BCLog : : NET , " Making feeler connection to %s \n " , addrConnect . ToStringAddrPort ( ) ) ;
2016-06-17 00:10:07 -04:00
}
2023-03-30 20:18:14 +05:30
// Record addrman failure attempts when node has at least 2 persistent outbound connections to peers with
// different netgroups in ipv4/ipv6 networks + all peers in Tor/I2P/CJDNS networks.
// Don't record addrman failure attempts when node is offline. This can be identified since all local
2023-04-14 11:01:43 -07:00
// network connections (if any) belong in the same netgroup, and the size of `outbound_ipv46_peer_netgroups` would only be 1.
const bool count_failures { ( ( int ) outbound_ipv46_peer_netgroups . size ( ) + outbound_privacy_network_peers ) > = std : : min ( nMaxConnections - 1 , 2 ) } ;
OpenNetworkConnection ( addrConnect , count_failures , & grant , /*strDest=*/ nullptr , conn_type ) ;
2016-06-17 00:10:07 -04:00
}
2010-08-29 16:58:15 +00:00
}
}
2020-09-12 18:03:06 +03:00
std : : vector < CAddress > CConnman : : GetCurrentBlockRelayOnlyConns ( ) const
{
std : : vector < CAddress > ret ;
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * pnode : m_nodes ) {
2020-09-12 18:03:06 +03:00
if ( pnode - > IsBlockOnlyConn ( ) ) {
ret . push_back ( pnode - > addr ) ;
}
}
return ret ;
}
2021-04-17 19:17:40 +02:00
std : : vector < AddedNodeInfo > CConnman : : GetAddedNodeInfo ( ) const
2011-12-16 19:48:03 -05:00
{
2016-05-28 15:32:30 +02:00
std : : vector < AddedNodeInfo > ret ;
std : : list < std : : string > lAddresses ( 0 ) ;
2012-07-02 19:55:16 +02:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_added_nodes_mutex ) ;
ret . reserve ( m_added_nodes . size ( ) ) ;
std : : copy ( m_added_nodes . cbegin ( ) , m_added_nodes . cend ( ) , std : : back_inserter ( lAddresses ) ) ;
2012-07-02 19:55:16 +02:00
}
2011-12-16 19:48:03 -05:00
2016-05-28 15:32:30 +02:00
// Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService
std : : map < CService , bool > mapConnected ;
std : : map < std : : string , std : : pair < bool , CService > > mapConnectedByName ;
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( const CNode * pnode : m_nodes ) {
2016-05-28 15:32:30 +02:00
if ( pnode - > addr . IsValid ( ) ) {
2020-07-28 13:39:38 -07:00
mapConnected [ pnode - > addr ] = pnode - > IsInboundConn ( ) ;
2012-07-02 19:55:16 +02:00
}
2021-08-26 10:39:10 +02:00
std : : string addrName { pnode - > m_addr_name } ;
2017-02-06 12:04:34 -05:00
if ( ! addrName . empty ( ) ) {
2020-07-28 13:39:38 -07:00
mapConnectedByName [ std : : move ( addrName ) ] = std : : make_pair ( pnode - > IsInboundConn ( ) , static_cast < const CService & > ( pnode - > addr ) ) ;
2012-04-19 17:38:03 +02:00
}
}
}
2017-06-02 03:18:57 +02:00
for ( const std : : string & strAddNode : lAddresses ) {
2021-05-31 17:30:18 +02:00
CService service ( LookupNumeric ( strAddNode , Params ( ) . GetDefaultPort ( strAddNode ) ) ) ;
2018-01-26 02:48:56 -08:00
AddedNodeInfo addedNode { strAddNode , CService ( ) , false , false } ;
2016-05-28 15:32:30 +02:00
if ( service . IsValid ( ) ) {
// strAddNode is an IP:port
auto it = mapConnected . find ( service ) ;
if ( it ! = mapConnected . end ( ) ) {
2018-01-26 02:48:56 -08:00
addedNode . resolvedAddress = service ;
addedNode . fConnected = true ;
addedNode . fInbound = it - > second ;
2016-05-28 15:32:30 +02:00
}
} else {
// strAddNode is a name
auto it = mapConnectedByName . find ( strAddNode ) ;
if ( it ! = mapConnectedByName . end ( ) ) {
2018-01-26 02:48:56 -08:00
addedNode . resolvedAddress = it - > second . second ;
addedNode . fConnected = true ;
addedNode . fInbound = it - > second . first ;
2012-04-19 17:38:03 +02:00
}
}
2018-01-26 02:48:56 -08:00
ret . emplace_back ( std : : move ( addedNode ) ) ;
2012-04-19 17:38:03 +02:00
}
2016-05-28 15:32:30 +02:00
return ret ;
}
2016-04-16 14:47:18 -04:00
void CConnman : : ThreadOpenAddedConnections ( )
2016-05-28 15:32:30 +02:00
{
2023-01-06 11:23:46 +01:00
AssertLockNotHeld ( m_unused_i2p_sessions_mutex ) ;
2016-12-11 04:39:26 +00:00
while ( true )
2011-12-16 19:48:03 -05:00
{
2016-12-11 04:39:26 +00:00
CSemaphoreGrant grant ( * semAddnode ) ;
2016-05-28 15:32:30 +02:00
std : : vector < AddedNodeInfo > vInfo = GetAddedNodeInfo ( ) ;
2016-12-11 04:39:26 +00:00
bool tried = false ;
2016-05-28 15:32:30 +02:00
for ( const AddedNodeInfo & info : vInfo ) {
if ( ! info . fConnected ) {
2016-12-11 04:39:26 +00:00
if ( ! grant . TryAcquire ( ) ) {
2018-03-18 16:26:45 +02: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 04:39:26 +00: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 10:57:03 -07:00
OpenNetworkConnection ( addr , false , & grant , info . strAddedNode . c_str ( ) , ConnectionType : : MANUAL ) ;
2016-12-27 17:12:44 -05:00
if ( ! interruptNet . sleep_for ( std : : chrono : : milliseconds ( 500 ) ) )
return ;
2016-05-28 15:32:30 +02:00
}
2012-07-02 19:55:16 +02:00
}
2016-12-11 04:39:26 +00:00
// Retry every 60 seconds if a connection was attempted, otherwise two seconds
2017-01-07 09:49:14 -08:00
if ( ! interruptNet . sleep_for ( std : : chrono : : seconds ( tried ? 60 : 2 ) ) )
2016-12-27 17:12:44 -05:00
return ;
2011-12-16 19:48:03 -05:00
}
}
2012-07-26 00:48:39 +00:00
// if successful, this moves the passed grant to the constructed node
2020-04-30 10:57:03 -07:00
void CConnman : : OpenNetworkConnection ( const CAddress & addrConnect , bool fCountFailure , CSemaphoreGrant * grantOutbound , const char * pszDest , ConnectionType conn_type )
2010-08-29 16:58:15 +00:00
{
2023-01-06 11:23:46 +01:00
AssertLockNotHeld ( m_unused_i2p_sessions_mutex ) ;
2020-04-29 14:55:59 -07:00
assert ( conn_type ! = ConnectionType : : INBOUND ) ;
2010-08-29 16:58:15 +00:00
//
// Initiate outbound network connection
//
2016-12-27 17:12:44 -05:00
if ( interruptNet ) {
2018-02-01 14:04:49 -05:00
return ;
2016-12-27 17:12:44 -05:00
}
2013-03-26 02:33:25 +01:00
if ( ! fNetworkActive ) {
2018-02-01 14:04:49 -05:00
return ;
2013-03-26 02:33:25 +01:00
}
2014-05-24 11:14:52 +02:00
if ( ! pszDest ) {
2020-06-10 17:11:38 -07:00
bool banned_or_discouraged = m_banman & & ( m_banman - > IsDiscouraged ( addrConnect ) | | m_banman - > IsBanned ( addrConnect ) ) ;
2020-10-16 11:10:17 -04:00
if ( IsLocal ( addrConnect ) | | banned_or_discouraged | | AlreadyConnectedToAddress ( addrConnect ) ) {
2018-02-01 14:04:49 -05:00
return ;
2020-06-10 17:11:38 -07:00
}
2015-05-31 15:44:22 +02:00
} else if ( FindNode ( std : : string ( pszDest ) ) )
2018-02-01 14:04:49 -05:00
return ;
2010-08-29 16:58:15 +00:00
2020-04-29 17:33:06 -07:00
CNode * pnode = ConnectNode ( addrConnect , pszDest , fCountFailure , conn_type ) ;
2013-03-06 22:31:26 -05:00
2010-08-29 16:58:15 +00:00
if ( ! pnode )
2018-02-01 14:04:49 -05:00
return ;
2012-05-10 18:44:07 +02:00
if ( grantOutbound )
grantOutbound - > MoveTo ( pnode - > grantOutbound ) ;
2010-08-29 16:58:15 +00:00
2020-07-20 14:01:05 +01:00
m_msgproc - > InitializeNode ( * pnode , nLocalServices ) ;
2017-01-24 16:51:22 -05:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
m_nodes . push_back ( pnode ) ;
2017-01-24 16:51:22 -05:00
}
2010-08-29 16:58:15 +00:00
}
2022-09-07 13:57:18 +10:00
Mutex NetEventsInterface : : g_msgproc_mutex ;
2016-04-16 14:47:18 -04:00
void CConnman : : ThreadMessageHandler ( )
2010-08-29 16:58:15 +00:00
{
2022-09-07 13:57:18 +10:00
LOCK ( NetEventsInterface : : g_msgproc_mutex ) ;
2016-12-27 17:12:44 -05:00
while ( ! flagInterruptMsgProc )
2010-08-29 16:58:15 +00:00
{
2016-12-31 02:05:26 -05:00
bool fMoreWork = false ;
2013-11-15 12:24:34 +01:00
2010-08-29 16:58:15 +00:00
{
2021-04-26 16:22:07 +02:00
// Randomize the order in which we process messages from/to our peers.
// This prevents attacks in which an attacker exploits having multiple
2021-08-28 20:57:52 +02:00
// consecutive connections in the m_nodes list.
2021-04-26 16:22:07 +02:00
const NodesSnapshot snap { * this , /*shuffle=*/ true } ;
2013-03-01 01:41:28 +01:00
2021-04-26 16:22:07 +02:00
for ( CNode * pnode : snap . Nodes ( ) ) {
if ( pnode - > fDisconnect )
continue ;
2017-07-06 13:40:09 -04:00
2021-04-26 16:22:07 +02:00
// Receive messages
bool fMoreNodeWork = m_msgproc - > ProcessMessages ( pnode , flagInterruptMsgProc ) ;
fMoreWork | = ( fMoreNodeWork & & ! pnode - > fPauseSend ) ;
if ( flagInterruptMsgProc )
return ;
// Send messages
2022-09-13 12:22:18 +10:00
m_msgproc - > SendMessages ( pnode ) ;
2010-08-29 16:58:15 +00:00
2021-04-26 16:22:07 +02:00
if ( flagInterruptMsgProc )
return ;
}
2010-08-29 16:58:15 +00:00
}
2013-11-15 12:24:34 +01:00
2017-11-08 17:07:40 -05:00
WAIT_LOCK ( mutexMsgProc , lock ) ;
2016-12-31 02:05:26 -05:00
if ( ! fMoreWork ) {
2019-05-30 13:44:02 +10:00
condMsgProc . wait_until ( lock , std : : chrono : : steady_clock : : now ( ) + std : : chrono : : milliseconds ( 100 ) , [ this ] ( ) EXCLUSIVE_LOCKS_REQUIRED ( mutexMsgProc ) { return fMsgProcWake ; } ) ;
2016-12-27 17:12:44 -05:00
}
2016-12-31 02:05:26 -05:00
fMsgProcWake = false ;
2010-08-29 16:58:15 +00:00
}
}
2020-11-24 11:28:52 +01:00
void CConnman : : ThreadI2PAcceptIncoming ( )
{
static constexpr auto err_wait_begin = 1 s ;
static constexpr auto err_wait_cap = 5 min ;
auto err_wait = err_wait_begin ;
bool advertising_listen_addr = false ;
i2p : : Connection conn ;
while ( ! interruptNet ) {
if ( ! m_i2p_sam_session - > Listen ( conn ) ) {
if ( advertising_listen_addr & & conn . me . IsValid ( ) ) {
RemoveLocal ( conn . me ) ;
advertising_listen_addr = false ;
}
interruptNet . sleep_for ( err_wait ) ;
if ( err_wait < err_wait_cap ) {
err_wait * = 2 ;
}
continue ;
}
if ( ! advertising_listen_addr ) {
2021-05-11 12:44:46 +02:00
AddLocal ( conn . me , LOCAL_MANUAL ) ;
2020-11-24 11:28:52 +01:00
advertising_listen_addr = true ;
}
if ( ! m_i2p_sam_session - > Accept ( conn ) ) {
continue ;
}
2021-04-13 12:14:57 +02:00
CreateNodeFromAcceptedSocket ( std : : move ( conn . sock ) , NetPermissionFlags : : None ,
2020-11-24 11:28:52 +01:00
CAddress { conn . me , NODE_NONE } , CAddress { conn . peer , NODE_NONE } ) ;
}
}
2020-04-11 18:47:17 +03:00
bool CConnman : : BindListenPort ( const CService & addrBind , bilingual_str & strError , NetPermissionFlags permissions )
2010-08-29 16:58:15 +00:00
{
int nOne = 1 ;
// Create socket for listening for incoming connections
2012-05-11 15:28:59 +02:00
struct sockaddr_storage sockaddr ;
socklen_t len = sizeof ( sockaddr ) ;
if ( ! addrBind . GetSockAddr ( ( struct sockaddr * ) & sockaddr , & len ) )
{
2022-07-15 14:13:39 +02:00
strError = strprintf ( Untranslated ( " Bind address family for %s not supported " ) , addrBind . ToStringAddrPort ( ) ) ;
2022-05-25 11:31:58 +02:00
LogPrintLevel ( BCLog : : NET , BCLog : : Level : : Error , " %s \n " , strError . original ) ;
2012-05-11 15:28:59 +02:00
return false ;
}
2020-12-23 16:40:11 +01:00
std : : unique_ptr < Sock > sock = CreateSock ( addrBind ) ;
if ( ! sock ) {
2022-04-18 18:01:24 +08:00
strError = strprintf ( Untranslated ( " Couldn't open socket for incoming connections (socket returned error %s) " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
2022-05-25 11:31:58 +02:00
LogPrintLevel ( BCLog : : NET , BCLog : : Level : : Error , " %s \n " , strError . original ) ;
2010-08-29 16:58:15 +00:00
return false ;
}
2018-01-26 02:48:56 -08:00
2010-08-29 16:58:15 +00:00
// Allow binding if the port is still in TIME_WAIT state after
2015-08-20 15:50:13 -04:00
// the program was closed and restarted.
2021-04-13 13:28:10 +02:00
if ( sock - > SetSockOpt ( SOL_SOCKET , SO_REUSEADDR , ( sockopt_arg_type ) & nOne , sizeof ( int ) ) = = SOCKET_ERROR ) {
strError = strprintf ( Untranslated ( " Error setting SO_REUSEADDR on socket: %s, continuing anyway " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
LogPrintf ( " %s \n " , strError . original ) ;
}
2010-08-29 16:58:15 +00:00
2012-05-11 15:28:59 +02:00
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if ( addrBind . IsIPv6 ( ) ) {
# ifdef IPV6_V6ONLY
2021-04-13 13:28:10 +02:00
if ( sock - > SetSockOpt ( IPPROTO_IPV6 , IPV6_V6ONLY , ( sockopt_arg_type ) & nOne , sizeof ( int ) ) = = SOCKET_ERROR ) {
strError = strprintf ( Untranslated ( " Error setting IPV6_V6ONLY on socket: %s, continuing anyway " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
LogPrintf ( " %s \n " , strError . original ) ;
}
2013-07-13 13:05:04 +02:00
# endif
2012-05-11 15:28:59 +02:00
# ifdef WIN32
2014-06-24 09:03:18 +02:00
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED ;
2021-04-13 13:28:10 +02:00
if ( sock - > SetSockOpt ( IPPROTO_IPV6 , IPV6_PROTECTION_LEVEL , ( const char * ) & nProtLevel , sizeof ( int ) ) = = SOCKET_ERROR ) {
strError = strprintf ( Untranslated ( " Error setting IPV6_PROTECTION_LEVEL on socket: %s, continuing anyway " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
LogPrintf ( " %s \n " , strError . original ) ;
}
2012-05-11 15:28:59 +02:00
# endif
}
2021-04-13 16:31:04 +02:00
if ( sock - > Bind ( reinterpret_cast < struct sockaddr * > ( & sockaddr ) , len ) = = SOCKET_ERROR ) {
2010-08-29 16:58:15 +00:00
int nErr = WSAGetLastError ( ) ;
if ( nErr = = WSAEADDRINUSE )
2022-07-15 14:13:39 +02:00
strError = strprintf ( _ ( " Unable to bind to %s on this computer. %s is probably already running. " ) , addrBind . ToStringAddrPort ( ) , PACKAGE_NAME ) ;
2010-08-29 16:58:15 +00:00
else
2022-07-15 14:13:39 +02:00
strError = strprintf ( _ ( " Unable to bind to %s on this computer (bind returned error %s) " ) , addrBind . ToStringAddrPort ( ) , NetworkErrorString ( nErr ) ) ;
2022-05-25 11:31:58 +02:00
LogPrintLevel ( BCLog : : NET , BCLog : : Level : : Error , " %s \n " , strError . original ) ;
2010-08-29 16:58:15 +00:00
return false ;
}
2022-07-15 14:13:39 +02:00
LogPrintf ( " Bound to %s \n " , addrBind . ToStringAddrPort ( ) ) ;
2010-08-29 16:58:15 +00:00
// Listen for incoming connections
2021-04-13 16:43:04 +02:00
if ( sock - > Listen ( SOMAXCONN ) = = SOCKET_ERROR )
2010-08-29 16:58:15 +00:00
{
2022-04-18 18:01:24 +08:00
strError = strprintf ( _ ( " Listening for incoming connections failed (listen returned error %s) " ) , NetworkErrorString ( WSAGetLastError ( ) ) ) ;
2022-05-25 11:31:58 +02:00
LogPrintLevel ( BCLog : : NET , BCLog : : Level : : Error , " %s \n " , strError . original ) ;
2010-08-29 16:58:15 +00:00
return false ;
}
2021-04-23 12:15:15 +02:00
vhListenSocket . emplace_back ( std : : move ( sock ) , permissions ) ;
2010-08-29 16:58:15 +00:00
return true ;
}
2018-02-07 17:42:39 -05:00
void Discover ( )
2010-08-29 16:58:15 +00:00
{
2012-05-24 19:02:21 +02:00
if ( ! fDiscover )
2012-02-19 20:44:35 +01:00
return ;
2010-08-29 16:58:15 +00:00
2011-10-07 11:02:21 -04:00
# ifdef WIN32
2012-07-26 00:48:39 +00:00
// Get local host IP
2014-11-13 15:23:15 +01:00
char pszHostName [ 256 ] = " " ;
2010-08-29 16:58:15 +00:00
if ( gethostname ( pszHostName , sizeof ( pszHostName ) ) ! = SOCKET_ERROR )
{
2022-10-07 11:10:35 -03:00
const std : : vector < CNetAddr > addresses { LookupHost ( pszHostName , 0 , true ) } ;
for ( const CNetAddr & addr : addresses )
2012-05-01 01:44:59 +02:00
{
2022-10-07 11:10:35 -03:00
if ( AddLocal ( addr , LOCAL_IF ) )
LogPrintf ( " %s: %s - %s \n " , __func__ , pszHostName , addr . ToStringAddr ( ) ) ;
2012-05-01 01:44:59 +02:00
}
2010-08-29 16:58:15 +00:00
}
2018-07-19 14:21:05 -04:00
# elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS)
2010-08-29 16:58:15 +00:00
// Get local host ip
struct ifaddrs * myaddrs ;
if ( getifaddrs ( & myaddrs ) = = 0 )
{
2017-08-07 07:36:37 +02:00
for ( struct ifaddrs * ifa = myaddrs ; ifa ! = nullptr ; ifa = ifa - > ifa_next )
2010-08-29 16:58:15 +00:00
{
2017-08-07 07:36:37 +02:00
if ( ifa - > ifa_addr = = nullptr ) continue ;
2010-08-29 16:58:15 +00:00
if ( ( ifa - > ifa_flags & IFF_UP ) = = 0 ) continue ;
if ( strcmp ( ifa - > ifa_name , " lo " ) = = 0 ) continue ;
if ( strcmp ( ifa - > ifa_name , " lo0 " ) = = 0 ) continue ;
if ( ifa - > ifa_addr - > sa_family = = AF_INET )
{
struct sockaddr_in * s4 = ( struct sockaddr_in * ) ( ifa - > ifa_addr ) ;
2012-02-12 13:45:24 +01:00
CNetAddr addr ( s4 - > sin_addr ) ;
2012-03-31 17:58:25 +02:00
if ( AddLocal ( addr , LOCAL_IF ) )
2022-07-15 13:49:17 +02:00
LogPrintf ( " %s: IPv4 %s: %s \n " , __func__ , ifa - > ifa_name , addr . ToStringAddr ( ) ) ;
2010-08-29 16:58:15 +00:00
}
else if ( ifa - > ifa_addr - > sa_family = = AF_INET6 )
{
struct sockaddr_in6 * s6 = ( struct sockaddr_in6 * ) ( ifa - > ifa_addr ) ;
2012-02-12 13:45:24 +01:00
CNetAddr addr ( s6 - > sin6_addr ) ;
2012-03-31 17:58:25 +02:00
if ( AddLocal ( addr , LOCAL_IF ) )
2022-07-15 13:49:17 +02:00
LogPrintf ( " %s: IPv6 %s: %s \n " , __func__ , ifa - > ifa_name , addr . ToStringAddr ( ) ) ;
2010-08-29 16:58:15 +00:00
}
}
freeifaddrs ( myaddrs ) ;
}
# endif
2012-02-19 20:44:35 +01:00
}
2013-03-26 02:33:25 +01:00
void CConnman : : SetNetworkActive ( bool active )
{
2020-07-09 10:12:19 +03:00
LogPrintf ( " %s: %s \n " , __func__ , active ) ;
2013-03-26 02:33:25 +01:00
2017-07-14 15:00:19 +01:00
if ( fNetworkActive = = active ) {
return ;
}
fNetworkActive = active ;
2013-03-26 02:33:25 +01:00
2021-08-18 13:41:39 +08:00
if ( m_client_interface ) {
m_client_interface - > NotifyNetworkActiveChanged ( fNetworkActive ) ;
2021-08-18 13:37:27 +08:00
}
2013-03-26 02:33:25 +01:00
}
2021-08-31 18:40:18 +01:00
CConnman : : CConnman ( uint64_t nSeed0In , uint64_t nSeed1In , AddrMan & addrman_in ,
const NetGroupManager & netgroupman , bool network_active )
: addrman ( addrman_in )
, m_netgroupman { netgroupman }
, nSeed0 ( nSeed0In )
, nSeed1 ( nSeed1In )
2016-04-16 14:47:18 -04:00
{
2017-10-23 13:36:15 -04:00
SetTryNewOutboundPeer ( false ) ;
[net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest& request)
When running test_bitcoin under Valgrind I found the following issue:
```
$ valgrind src/test/test_bitcoin
...
==10465== Use of uninitialised value of size 8
==10465== at 0x6D09B61: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B1BB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<unsigned long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B36C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D17699: std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x4CAAD7: operator<< (ostream:171)
==10465== by 0x4CAAD7: formatValue<ServiceFlags> (tinyformat.h:345)
==10465== by 0x4CAAD7: void tinyformat::detail::FormatArg::formatImpl<ServiceFlags>(std::ostream&, char const*, char const*, int, void const*) (tinyformat.h:523)
==10465== by 0x1924D4: format (tinyformat.h:510)
==10465== by 0x1924D4: tinyformat::detail::formatImpl(std::ostream&, char const*, tinyformat::detail::FormatArg const*, int) (tinyformat.h:803)
==10465== by 0x553A55: vformat (tinyformat.h:947)
==10465== by 0x553A55: format<ServiceFlags> (tinyformat.h:957)
==10465== by 0x553A55: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > tinyformat::format<ServiceFlags>(char const*, ServiceFlags const&) (tinyformat.h:966)
==10465== by 0x54C952: getnetworkinfo(JSONRPCRequest const&) (net.cpp:462)
==10465== by 0x28EDB5: CallRPC(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (rpc_tests.cpp:31)
==10465== by 0x293947: rpc_tests::rpc_togglenetwork::test_method() (rpc_tests.cpp:88)
==10465== by 0x2950E5: rpc_tests::rpc_togglenetwork_invoker() (rpc_tests.cpp:84)
==10465== by 0x182496: invoke<void (*)()> (callback.hpp:56)
==10465== by 0x182496: boost::unit_test::ut_detail::callback0_impl_t<boost::unit_test::ut_detail::unused, void (*)()>::invoke() (callback.hpp:89)
...
```
The read of the uninitialized variable nLocalServices is triggered by g_connman->GetLocalServices()
in getnetworkinfo(const JSONRPCRequest& request) (net.cpp:462):
```c++
UniValue getnetworkinfo(const JSONRPCRequest& request)
{
...
if(g_connman)
obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
...
}
```
The reason for the uninitialized nLocalServices is that CConnman::Start(...) is not called
by the tests, and hence the initialization normally performed by CConnman::Start(...) is
not done.
This commit adds a method Init(const Options& connOptions) which is called by both the
constructor and CConnman::Start(...). This method initializes nLocalServices and the other
relevant values from the supplied Options object.
2017-08-02 14:02:36 +02:00
Options connOptions ;
Init ( connOptions ) ;
2020-07-09 10:07:47 +03:00
SetNetworkActive ( network_active ) ;
2016-04-16 14:47:18 -04:00
}
2016-04-17 20:20:34 -04:00
NodeId CConnman : : GetNewNodeId ( )
2016-04-16 17:43:11 -04:00
{
2016-04-17 20:20:34 -04:00
return nLastNodeId . fetch_add ( 1 , std : : memory_order_relaxed ) ;
}
2016-04-16 17:43:11 -04:00
2017-06-01 12:34:02 +02:00
2021-09-13 13:02:05 +02:00
bool CConnman : : Bind ( const CService & addr_ , unsigned int flags , NetPermissionFlags permissions )
{
const CService addr { MaybeFlipIPv6toCJDNS ( addr_ ) } ;
2020-04-11 18:47:17 +03:00
bilingual_str strError ;
2019-06-20 18:37:51 +09:00
if ( ! BindListenPort ( addr , strError , permissions ) ) {
2021-08-18 13:41:39 +08:00
if ( ( flags & BF_REPORT_ERROR ) & & m_client_interface ) {
m_client_interface - > ThreadSafeMessageBox ( strError , " " , CClientUIInterface : : MSG_ERROR ) ;
2017-06-01 12:34:02 +02:00
}
return false ;
}
2020-09-29 18:02:44 +03:00
2021-03-21 22:46:50 +01:00
if ( addr . IsRoutable ( ) & & fDiscover & & ! ( flags & BF_DONT_ADVERTISE ) & & ! NetPermissions : : HasFlag ( permissions , NetPermissionFlags : : NoBan ) ) {
2020-09-29 18:02:44 +03:00
AddLocal ( addr , LOCAL_BIND ) ;
}
2017-06-01 12:34:02 +02:00
return true ;
}
2020-10-22 20:34:31 +02:00
bool CConnman : : InitBinds ( const Options & options )
2019-06-20 18:37:51 +09:00
{
2017-06-01 12:34:02 +02:00
bool fBound = false ;
2020-10-22 20:34:31 +02:00
for ( const auto & addrBind : options . vBinds ) {
2022-07-29 13:23:29 +02:00
fBound | = Bind ( addrBind , BF_REPORT_ERROR , NetPermissionFlags : : None ) ;
2017-06-01 12:34:02 +02:00
}
2020-10-22 20:34:31 +02:00
for ( const auto & addrBind : options . vWhiteBinds ) {
2022-07-29 13:23:29 +02:00
fBound | = Bind ( addrBind . m_service , BF_REPORT_ERROR , addrBind . m_flags ) ;
2017-06-01 12:34:02 +02:00
}
2020-10-22 20:34:31 +02:00
for ( const auto & addr_bind : options . onion_binds ) {
2022-07-29 13:23:29 +02:00
fBound | = Bind ( addr_bind , BF_DONT_ADVERTISE , NetPermissionFlags : : None ) ;
2020-10-22 20:34:31 +02:00
}
if ( options . bind_on_any ) {
2017-06-01 12:34:02 +02:00
struct in_addr inaddr_any ;
2020-09-22 13:42:47 +03:00
inaddr_any . s_addr = htonl ( INADDR_ANY ) ;
2018-07-16 16:29:27 +10:00
struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT ;
2021-03-21 22:46:50 +01:00
fBound | = Bind ( CService ( inaddr6_any , GetListenPort ( ) ) , BF_NONE , NetPermissionFlags : : None ) ;
fBound | = Bind ( CService ( inaddr_any , GetListenPort ( ) ) , ! fBound ? BF_REPORT_ERROR : BF_NONE , NetPermissionFlags : : None ) ;
2017-06-01 12:34:02 +02: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 14:02:36 +02:00
bool CConnman : : Start ( CScheduler & scheduler , const Options & connOptions )
2016-04-17 20:20:34 -04:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
[net] Fix use of uninitialized value in getnetworkinfo(const JSONRPCRequest& request)
When running test_bitcoin under Valgrind I found the following issue:
```
$ valgrind src/test/test_bitcoin
...
==10465== Use of uninitialised value of size 8
==10465== at 0x6D09B61: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B1BB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<unsigned long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D0B36C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x6D17699: std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==10465== by 0x4CAAD7: operator<< (ostream:171)
==10465== by 0x4CAAD7: formatValue<ServiceFlags> (tinyformat.h:345)
==10465== by 0x4CAAD7: void tinyformat::detail::FormatArg::formatImpl<ServiceFlags>(std::ostream&, char const*, char const*, int, void const*) (tinyformat.h:523)
==10465== by 0x1924D4: format (tinyformat.h:510)
==10465== by 0x1924D4: tinyformat::detail::formatImpl(std::ostream&, char const*, tinyformat::detail::FormatArg const*, int) (tinyformat.h:803)
==10465== by 0x553A55: vformat (tinyformat.h:947)
==10465== by 0x553A55: format<ServiceFlags> (tinyformat.h:957)
==10465== by 0x553A55: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > tinyformat::format<ServiceFlags>(char const*, ServiceFlags const&) (tinyformat.h:966)
==10465== by 0x54C952: getnetworkinfo(JSONRPCRequest const&) (net.cpp:462)
==10465== by 0x28EDB5: CallRPC(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (rpc_tests.cpp:31)
==10465== by 0x293947: rpc_tests::rpc_togglenetwork::test_method() (rpc_tests.cpp:88)
==10465== by 0x2950E5: rpc_tests::rpc_togglenetwork_invoker() (rpc_tests.cpp:84)
==10465== by 0x182496: invoke<void (*)()> (callback.hpp:56)
==10465== by 0x182496: boost::unit_test::ut_detail::callback0_impl_t<boost::unit_test::ut_detail::unused, void (*)()>::invoke() (callback.hpp:89)
...
```
The read of the uninitialized variable nLocalServices is triggered by g_connman->GetLocalServices()
in getnetworkinfo(const JSONRPCRequest& request) (net.cpp:462):
```c++
UniValue getnetworkinfo(const JSONRPCRequest& request)
{
...
if(g_connman)
obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
...
}
```
The reason for the uninitialized nLocalServices is that CConnman::Start(...) is not called
by the tests, and hence the initialization normally performed by CConnman::Start(...) is
not done.
This commit adds a method Init(const Options& connOptions) which is called by both the
constructor and CConnman::Start(...). This method initializes nLocalServices and the other
relevant values from the supplied Options object.
2017-08-02 14:02:36 +02:00
Init ( connOptions ) ;
2020-10-22 20:34:31 +02:00
if ( fListen & & ! InitBinds ( connOptions ) ) {
2021-08-18 13:41:39 +08:00
if ( m_client_interface ) {
m_client_interface - > ThreadSafeMessageBox (
2020-04-11 18:47:17 +03:00
_ ( " Failed to listen on any port. Use -listen=0 if you want this. " ) ,
2017-06-01 12:34:02 +02:00
" " , CClientUIInterface : : MSG_ERROR ) ;
}
return false ;
}
2021-11-08 17:34:32 +01:00
Proxy i2p_sam ;
2022-06-08 17:59:32 +02:00
if ( GetProxy ( NET_I2P , i2p_sam ) & & connOptions . m_i2p_accept_incoming ) {
2021-05-04 13:00:25 +02:00
m_i2p_sam_session = std : : make_unique < i2p : : sam : : Session > ( gArgs . GetDataDirNet ( ) / " i2p_private_key " ,
2020-12-04 18:03:05 +01:00
i2p_sam . proxy , & interruptNet ) ;
}
2017-05-27 12:00:37 +02:00
for ( const auto & strDest : connOptions . vSeedNodes ) {
2020-07-17 14:56:34 -07:00
AddAddrFetch ( strDest ) ;
2017-05-27 12:00:37 +02:00
}
2020-09-12 18:05:54 +03:00
if ( m_use_addrman_outgoing ) {
// Load addresses from anchors.dat
2021-05-04 13:00:25 +02:00
m_anchors = ReadAnchors ( gArgs . GetDataDirNet ( ) / ANCHORS_DATABASE_FILENAME ) ;
2020-09-12 18:05:54 +03:00
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 ( ) ) ;
}
2021-08-18 13:41:39 +08:00
if ( m_client_interface ) {
m_client_interface - > InitMessage ( _ ( " Starting network threads… " ) . translated ) ;
2021-08-18 13:37:27 +08:00
}
2016-07-22 16:01:12 +02:00
2014-09-18 14:08:43 +02:00
fAddressesInitialized = true ;
2017-08-07 07:36:37 +02:00
if ( semOutbound = = nullptr ) {
2012-05-10 18:44:07 +02:00
// initialize semaphore
2021-03-10 17:28:08 +08:00
semOutbound = std : : make_unique < CSemaphore > ( std : : min ( m_max_outbound , nMaxConnections ) ) ;
2012-05-10 18:44:07 +02:00
}
2017-08-07 07:36:37 +02:00
if ( semAddnode = = nullptr ) {
2016-12-11 04:39:26 +00:00
// initialize semaphore
2021-03-10 17:28:08 +08:00
semAddnode = std : : make_unique < CSemaphore > ( nMaxAddnode ) ;
2016-12-11 04:39:26 +00:00
}
2012-05-10 18:44:07 +02:00
2010-08-29 16:58:15 +00:00
//
// Start threads
//
2017-07-06 13:40:09 -04:00
assert ( m_msgproc ) ;
2016-12-27 17:13:31 -05:00
InterruptSocks5 ( false ) ;
2016-12-27 17:12:44 -05:00
interruptNet . reset ( ) ;
flagInterruptMsgProc = false ;
2010-08-29 16:58:15 +00:00
2016-12-31 02:05:26 -05:00
{
2017-11-08 17:07:40 -05:00
LOCK ( mutexMsgProc ) ;
2016-12-31 02:05:26 -05:00
fMsgProcWake = false ;
}
2016-12-27 17:11:57 -05:00
// Send and receive from sockets, accept connections
2021-04-13 21:22:52 +03:00
threadSocketHandler = std : : thread ( & util : : TraceThread , " net " , [ this ] { ThreadSocketHandler ( ) ; } ) ;
2010-08-29 16:58:15 +00:00
2020-09-05 09:51:33 -07:00
if ( ! gArgs . GetBoolArg ( " -dnsseed " , DEFAULT_DNSSEED ) )
2013-09-18 20:38:08 +10:00
LogPrintf ( " DNS seeding disabled \n " ) ;
2011-11-21 12:25:00 -05:00
else
2021-04-13 21:22:52 +03:00
threadDNSAddressSeed = std : : thread ( & util : : TraceThread , " dnsseed " , [ this ] { ThreadDNSAddressSeed ( ) ; } ) ;
2010-08-29 16:58:15 +00:00
2020-04-29 14:55:59 -07:00
// Initiate manual connections
2021-04-13 21:22:52 +03:00
threadOpenAddedConnections = std : : thread ( & util : : TraceThread , " addcon " , [ this ] { ThreadOpenAddedConnections ( ) ; } ) ;
2011-12-16 19:48:03 -05:00
2017-06-15 09:39:07 +02:00
if ( connOptions . m_use_addrman_outgoing & & ! connOptions . m_specified_outgoing . empty ( ) ) {
2021-08-18 13:41:39 +08:00
if ( m_client_interface ) {
m_client_interface - > ThreadSafeMessageBox (
2022-02-24 02:59:38 +02:00
_ ( " Cannot provide specific connections and have addrman find outgoing connections at the same time. " ) ,
2017-06-15 09:39:07 +02:00
" " , CClientUIInterface : : MSG_ERROR ) ;
}
return false ;
}
2021-04-13 21:22:52 +03:00
if ( connOptions . m_use_addrman_outgoing | | ! connOptions . m_specified_outgoing . empty ( ) ) {
threadOpenConnections = std : : thread (
& util : : TraceThread , " opencon " ,
[ this , connect = connOptions . m_specified_outgoing ] { ThreadOpenConnections ( connect ) ; } ) ;
}
2010-08-29 16:58:15 +00:00
// Process messages
2021-04-13 21:22:52 +03:00
threadMessageHandler = std : : thread ( & util : : TraceThread , " msghand " , [ this ] { ThreadMessageHandler ( ) ; } ) ;
2010-08-29 16:58:15 +00:00
2022-06-08 17:59:32 +02:00
if ( m_i2p_sam_session ) {
2020-11-24 11:28:52 +01:00
threadI2PAcceptIncoming =
2021-04-13 21:22:52 +03:00
std : : thread ( & util : : TraceThread , " i2paccept " , [ this ] { ThreadI2PAcceptIncoming ( ) ; } ) ;
2020-11-24 11:28:52 +01:00
}
2016-04-16 17:43:11 -04:00
// Dump network addresses
2020-03-06 18:06:50 -05:00
scheduler . scheduleEvery ( [ this ] { DumpAddresses ( ) ; } , DUMP_PEERS_INTERVAL ) ;
2016-04-16 17:43:11 -04:00
2016-04-16 14:47:18 -04:00
return true ;
2010-08-29 16:58:15 +00:00
}
class CNetCleanup
{
public :
2022-05-11 16:02:15 +01:00
CNetCleanup ( ) = default ;
2014-05-24 11:14:52 +02:00
2010-08-29 16:58:15 +00:00
~ CNetCleanup ( )
{
2011-10-07 11:02:21 -04:00
# ifdef WIN32
2010-08-29 16:58:15 +00:00
// Shutdown Windows Sockets
WSACleanup ( ) ;
# endif
}
2019-05-26 11:01:58 +02:00
} ;
static CNetCleanup instance_of_cnetcleanup ;
2012-08-13 05:26:30 +02:00
2016-12-27 17:12:44 -05:00
void CConnman : : Interrupt ( )
2016-04-16 14:47:18 -04:00
{
2016-12-27 17:12:44 -05:00
{
2019-05-30 13:44:02 +10:00
LOCK ( mutexMsgProc ) ;
2016-12-27 17:12:44 -05:00
flagInterruptMsgProc = true ;
}
condMsgProc . notify_all ( ) ;
interruptNet ( ) ;
2016-12-27 17:13:31 -05:00
InterruptSocks5 ( true ) ;
2016-12-27 17:12:44 -05:00
2017-03-08 14:55:28 -05:00
if ( semOutbound ) {
2019-03-09 12:55:06 -05:00
for ( int i = 0 ; i < m_max_outbound ; i + + ) {
2016-04-16 14:47:18 -04:00
semOutbound - > post ( ) ;
2017-03-08 14:55:28 -05:00
}
}
2017-03-08 14:41:57 -05:00
2017-03-08 14:55:28 -05:00
if ( semAddnode ) {
for ( int i = 0 ; i < nMaxAddnode ; i + + ) {
2017-03-08 14:41:57 -05:00
semAddnode - > post ( ) ;
2017-03-08 14:55:28 -05:00
}
}
2016-12-27 17:12:44 -05:00
}
2020-03-28 10:44:53 -04:00
void CConnman : : StopThreads ( )
2016-12-27 17:12:44 -05:00
{
2020-11-24 11:28:52 +01:00
if ( threadI2PAcceptIncoming . joinable ( ) ) {
threadI2PAcceptIncoming . join ( ) ;
}
2016-12-27 17:12:44 -05: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 10:44:53 -04:00
}
2016-04-16 14:47:18 -04:00
2020-03-28 10:44:53 -04:00
void CConnman : : StopNodes ( )
{
if ( fAddressesInitialized ) {
2017-10-05 12:46:54 -04:00
DumpAddresses ( ) ;
2016-04-16 17:43:11 -04:00
fAddressesInitialized = false ;
2020-09-12 18: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 ) ;
}
2021-05-04 13:00:25 +02:00
DumpAnchors ( gArgs . GetDataDirNet ( ) / ANCHORS_DATABASE_FILENAME , anchors_to_dump ) ;
2020-09-12 18:05:54 +03:00
}
2016-04-16 17:43:11 -04:00
}
2021-04-12 14:54:58 +03:00
// Delete peer connections.
2021-04-12 14:54:58 +03:00
std : : vector < CNode * > nodes ;
2021-08-28 20:57:52 +02:00
WITH_LOCK ( m_nodes_mutex , nodes . swap ( m_nodes ) ) ;
2021-04-12 14:54:58 +03:00
for ( CNode * pnode : nodes ) {
2017-02-06 14:05:45 -05:00
pnode - > CloseSocketDisconnect ( ) ;
2016-05-24 18:59:16 -04:00
DeleteNode ( pnode ) ;
}
2021-04-12 14:54:58 +03:00
2021-08-28 20:57:52 +02:00
for ( CNode * pnode : m_nodes_disconnected ) {
2016-05-24 18:59:16 -04:00
DeleteNode ( pnode ) ;
}
2021-08-28 20:57:52 +02:00
m_nodes_disconnected . clear ( ) ;
2016-04-16 14:47:18 -04:00
vhListenSocket . clear ( ) ;
2017-08-09 16:07:22 +02:00
semOutbound . reset ( ) ;
semAddnode . reset ( ) ;
2016-04-16 14:47:18 -04:00
}
2016-05-24 18:59:16 -04:00
void CConnman : : DeleteNode ( CNode * pnode )
{
assert ( pnode ) ;
2020-10-23 10:28:33 +01:00
m_msgproc - > FinalizeNode ( * pnode ) ;
2016-05-24 18:59:16 -04:00
delete pnode ;
}
2016-04-16 14:47:18 -04:00
CConnman : : ~ CConnman ( )
{
2016-12-27 17:12:44 -05:00
Interrupt ( ) ;
2016-09-13 14:42:55 -04:00
Stop ( ) ;
2016-04-16 14:47:18 -04:00
}
2012-08-13 05:26:30 +02:00
2021-05-02 19:05:42 +02:00
std : : vector < CAddress > CConnman : : GetAddresses ( size_t max_addresses , size_t max_pct , std : : optional < Network > network ) const
2016-04-16 17:43:11 -04:00
{
2021-05-02 19:05:42 +02:00
std : : vector < CAddress > addresses = addrman . GetAddr ( max_addresses , max_pct , network ) ;
2020-07-04 11:25:51 +03: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 17:43:11 -04:00
}
2020-08-11 12:41:26 +03: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-11-24 15:36:27 +01:00
auto local_socket_bytes = requestor . addrBind . GetAddrBytes ( ) ;
2020-08-11 12:41:26 +03:00
uint64_t cache_id = GetDeterministicRandomizer ( RANDOMIZER_ID_ADDRCACHE )
2022-04-12 13:46:59 +02:00
. Write ( requestor . ConnectedThroughNetwork ( ) )
2020-08-11 12:41:26 +03:00
. Write ( local_socket_bytes . data ( ) , local_socket_bytes . size ( ) )
2022-04-12 13:47:48 +02:00
// For outbound connections, the port of the bound address is randomly
// assigned by the OS and would therefore not be useful for seeding.
. Write ( requestor . IsInboundConn ( ) ? requestor . addrBind . GetPort ( ) : 0 )
2020-08-11 12:41:26 +03:00
. Finalize ( ) ;
2020-05-16 21:05:44 -04:00
const auto current_time = GetTime < std : : chrono : : microseconds > ( ) ;
2020-08-11 13:39:56 +03: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.
2022-04-02 16:01:40 +01:00
cache_entry . m_addrs_response_cache = GetAddresses ( max_addresses , max_pct , /*network=*/ std : : nullopt ) ;
2020-08-11 10:42:26 +03: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 13:39:56 +03: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 13:39:56 +03:00
return cache_entry . m_addrs_response_cache ;
2020-05-16 21:05:44 -04:00
}
2016-04-16 18:12:58 -04:00
bool CConnman : : AddNode ( const std : : string & strNode )
{
2021-08-28 20:57:52 +02:00
LOCK ( m_added_nodes_mutex ) ;
for ( const std : : string & it : m_added_nodes ) {
2017-07-20 11:32:47 +02:00
if ( strNode = = it ) return false ;
2016-04-16 18:12:58 -04:00
}
2021-08-28 20:57:52 +02:00
m_added_nodes . push_back ( strNode ) ;
2016-04-16 18:12:58 -04:00
return true ;
}
bool CConnman : : RemoveAddedNode ( const std : : string & strNode )
{
2021-08-28 20:57:52 +02:00
LOCK ( m_added_nodes_mutex ) ;
for ( std : : vector < std : : string > : : iterator it = m_added_nodes . begin ( ) ; it ! = m_added_nodes . end ( ) ; + + it ) {
2016-04-16 18:12:58 -04:00
if ( strNode = = * it ) {
2021-08-28 20:57:52 +02:00
m_added_nodes . erase ( it ) ;
2016-04-16 18:12:58 -04:00
return true ;
}
}
return false ;
}
2021-04-17 19:17:40 +02:00
size_t CConnman : : GetNodeCount ( ConnectionDirection flags ) const
2016-04-16 18:30:03 -04:00
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
2019-10-16 17:37:19 +00:00
if ( flags = = ConnectionDirection : : Both ) // Shortcut if we want total
2021-08-28 20:57:52 +02:00
return m_nodes . size ( ) ;
2016-04-16 18:30:03 -04:00
int nNum = 0 ;
2021-08-28 20:57:52 +02:00
for ( const auto & pnode : m_nodes ) {
2019-10-16 17:37:19 +00:00
if ( flags & ( pnode - > IsInboundConn ( ) ? ConnectionDirection : : In : ConnectionDirection : : Out ) ) {
2016-04-16 18:30:03 -04:00
nNum + + ;
2017-07-20 11:32:47 +02:00
}
}
2016-04-16 18:30:03 -04:00
return nNum ;
}
2023-04-03 15:42:15 -03:00
uint32_t CConnman : : GetMappedAS ( const CNetAddr & addr ) const
{
return m_netgroupman . GetMappedAS ( addr ) ;
}
2021-04-17 19:17:40 +02:00
void CConnman : : GetNodeStats ( std : : vector < CNodeStats > & vstats ) const
2016-04-16 18:30:03 -04:00
{
vstats . clear ( ) ;
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
vstats . reserve ( m_nodes . size ( ) ) ;
for ( CNode * pnode : m_nodes ) {
2017-02-06 11:44:38 -05:00
vstats . emplace_back ( ) ;
2021-09-01 11:24:46 +01:00
pnode - > CopyStats ( vstats . back ( ) ) ;
2023-04-03 15:42:15 -03:00
vstats . back ( ) . m_mapped_as = GetMappedAS ( pnode - > addr ) ;
2016-04-16 18:30:03 -04:00
}
}
bool CConnman : : DisconnectNode ( const std : : string & strNode )
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
2016-04-16 18:30:03 -04:00
if ( CNode * pnode = FindNode ( strNode ) ) {
2020-12-18 07:18:28 +10:00
LogPrint ( BCLog : : NET , " disconnect by address%s matched peer=%d; disconnecting \n " , ( fLogIPs ? strprintf ( " =%s " , strNode ) : " " ) , pnode - > GetId ( ) ) ;
2016-04-16 18:30:03 -04:00
pnode - > fDisconnect = true ;
return true ;
}
return false ;
}
2017-10-04 18:25:34 -04:00
bool CConnman : : DisconnectNode ( const CSubNet & subnet )
{
bool disconnected = false ;
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( CNode * pnode : m_nodes ) {
2017-10-04 18:25:34 -04:00
if ( subnet . Match ( pnode - > addr ) ) {
2020-12-18 07:18:28 +10:00
LogPrint ( BCLog : : NET , " disconnect by subnet%s matched peer=%d; disconnecting \n " , ( fLogIPs ? strprintf ( " =%s " , subnet . ToString ( ) ) : " " ) , pnode - > GetId ( ) ) ;
2017-10-04 18:25:34 -04:00
pnode - > fDisconnect = true ;
disconnected = true ;
}
}
return disconnected ;
}
bool CConnman : : DisconnectNode ( const CNetAddr & addr )
{
return DisconnectNode ( CSubNet ( addr ) ) ;
}
2016-04-16 18:30:03 -04:00
bool CConnman : : DisconnectNode ( NodeId id )
{
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( CNode * pnode : m_nodes ) {
2017-04-11 12:13:55 -04:00
if ( id = = pnode - > GetId ( ) ) {
2020-12-18 07:18:28 +10:00
LogPrint ( BCLog : : NET , " disconnect by id peer=%d; disconnecting \n " , pnode - > GetId ( ) ) ;
2016-04-16 18:30:03 -04:00
pnode - > fDisconnect = true ;
return true ;
}
}
return false ;
}
2016-04-18 21:44:42 -04:00
void CConnman : : RecordBytesRecv ( uint64_t bytes )
2013-08-23 02:09:32 +10:00
{
nTotalBytesRecv + = bytes ;
}
2016-04-18 21:44:42 -04:00
void CConnman : : RecordBytesSent ( uint64_t bytes )
2013-08-23 02:09:32 +10:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2022-01-25 18:05:04 -03:00
LOCK ( m_total_bytes_sent_mutex ) ;
2022-01-25 18:18:52 -03:00
2013-08-23 02:09:32 +10:00
nTotalBytesSent + = bytes ;
2015-09-02 17:03:27 +02:00
2020-10-24 19:13:42 +08:00
const auto now = GetTime < std : : chrono : : seconds > ( ) ;
2020-10-24 16:33:26 +08:00
if ( nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME < now )
2015-09-02 17:03:27 +02:00
{
// timeframe expired, reset cycle
nMaxOutboundCycleStartTime = now ;
nMaxOutboundTotalBytesSentInCycle = 0 ;
}
nMaxOutboundTotalBytesSentInCycle + = bytes ;
}
2021-04-17 19:17:40 +02:00
uint64_t CConnman : : GetMaxOutboundTarget ( ) const
2015-09-02 17:03:27 +02:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2022-01-25 18:05:04 -03:00
LOCK ( m_total_bytes_sent_mutex ) ;
2015-09-02 17:03:27 +02:00
return nMaxOutboundLimit ;
}
2021-04-17 19:17:40 +02:00
std : : chrono : : seconds CConnman : : GetMaxOutboundTimeframe ( ) const
2015-09-02 17:03:27 +02:00
{
2020-10-24 16:33:26 +08:00
return MAX_UPLOAD_TIMEFRAME ;
2015-09-02 17:03:27 +02:00
}
2021-04-17 19:17:40 +02:00
std : : chrono : : seconds CConnman : : GetMaxOutboundTimeLeftInCycle ( ) const
2015-09-02 17:03:27 +02:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2022-01-25 18:05:04 -03:00
LOCK ( m_total_bytes_sent_mutex ) ;
2022-01-25 18:18:52 -03:00
return GetMaxOutboundTimeLeftInCycle_ ( ) ;
}
std : : chrono : : seconds CConnman : : GetMaxOutboundTimeLeftInCycle_ ( ) const
{
AssertLockHeld ( m_total_bytes_sent_mutex ) ;
2015-09-02 17:03:27 +02:00
if ( nMaxOutboundLimit = = 0 )
2020-10-24 19:13:42 +08:00
return 0 s ;
2015-09-02 17:03:27 +02:00
2020-10-24 19:13:42 +08:00
if ( nMaxOutboundCycleStartTime . count ( ) = = 0 )
2020-10-24 16:33:26 +08:00
return MAX_UPLOAD_TIMEFRAME ;
2015-09-02 17:03:27 +02:00
2020-10-24 19:13:42 +08: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 17:03:27 +02:00
}
2021-04-17 19:17:40 +02:00
bool CConnman : : OutboundTargetReached ( bool historicalBlockServingLimit ) const
2015-09-02 17:03:27 +02:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2022-01-25 18:05:04 -03:00
LOCK ( m_total_bytes_sent_mutex ) ;
2015-09-02 17:03:27 +02:00
if ( nMaxOutboundLimit = = 0 )
return false ;
if ( historicalBlockServingLimit )
{
2016-01-17 11:03:56 +00:00
// keep a large enough buffer to at least relay each block once
2022-01-25 18:18:52 -03:00
const std : : chrono : : seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle_ ( ) ;
2020-10-24 19:13:42 +08:00
const uint64_t buffer = timeLeftInCycle / std : : chrono : : minutes { 10 } * MAX_BLOCK_SERIALIZED_SIZE ;
2015-09-02 17:03:27 +02:00
if ( buffer > = nMaxOutboundLimit | | nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit - buffer )
return true ;
}
else if ( nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit )
return true ;
return false ;
}
2021-04-17 19:17:40 +02:00
uint64_t CConnman : : GetOutboundTargetBytesLeft ( ) const
2015-09-02 17:03:27 +02:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2022-01-25 18:05:04 -03:00
LOCK ( m_total_bytes_sent_mutex ) ;
2015-09-02 17:03:27 +02:00
if ( nMaxOutboundLimit = = 0 )
return 0 ;
return ( nMaxOutboundTotalBytesSentInCycle > = nMaxOutboundLimit ) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle ;
2013-08-23 02:09:32 +10:00
}
2021-04-17 19:17:40 +02:00
uint64_t CConnman : : GetTotalBytesRecv ( ) const
2013-08-23 02:09:32 +10:00
{
return nTotalBytesRecv ;
}
2021-04-17 19:17:40 +02:00
uint64_t CConnman : : GetTotalBytesSent ( ) const
2013-08-23 02:09:32 +10:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2022-01-25 18:05:04 -03:00
LOCK ( m_total_bytes_sent_mutex ) ;
2013-08-23 02:09:32 +10:00
return nTotalBytesSent ;
}
2013-10-28 16:28:00 +10:00
2016-04-19 00:04:58 -04:00
ServiceFlags CConnman : : GetLocalServices ( ) const
{
return nLocalServices ;
}
2022-06-08 17:26:24 +02:00
CNode : : CNode ( NodeId idIn ,
std : : shared_ptr < Sock > sock ,
const CAddress & addrIn ,
uint64_t nKeyedNetGroupIn ,
uint64_t nLocalHostNonceIn ,
const CAddress & addrBindIn ,
const std : : string & addrNameIn ,
ConnectionType conn_type_in ,
bool inbound_onion ,
2022-08-31 17:04:13 +10:00
CNodeOptions & & node_opts )
2022-05-20 05:37:54 +10:00
: m_deserializer { std : : make_unique < V1TransportDeserializer > ( V1TransportDeserializer ( Params ( ) , idIn , SER_NETWORK , INIT_PROTO_VERSION ) ) } ,
m_serializer { std : : make_unique < V1TransportSerializer > ( V1TransportSerializer ( ) ) } ,
2022-09-01 18:50:26 +10:00
m_permission_flags { node_opts . permission_flags } ,
2022-05-20 05:37:54 +10:00
m_sock { sock } ,
2021-04-23 15:15:23 +02:00
m_connected { GetTime < std : : chrono : : seconds > ( ) } ,
2022-06-08 17:26:24 +02:00
addr { addrIn } ,
addrBind { addrBindIn } ,
2022-07-18 13:28:40 +02:00
m_addr_name { addrNameIn . empty ( ) ? addr . ToStringAddrPort ( ) : addrNameIn } ,
2022-06-08 17:26:24 +02:00
m_inbound_onion { inbound_onion } ,
2022-09-01 18:44:33 +10:00
m_prefer_evict { node_opts . prefer_evict } ,
2022-06-08 17:26:24 +02:00
nKeyedNetGroup { nKeyedNetGroupIn } ,
2023-03-24 15:29:21 +01:00
m_conn_type { conn_type_in } ,
2022-06-08 17:26:24 +02:00
id { idIn } ,
nLocalHostNonce { nLocalHostNonceIn } ,
2023-03-24 15:45:50 +01:00
m_recv_flood_size { node_opts . recv_flood_size } ,
2022-08-31 17:04:13 +10:00
m_i2p_sam_session { std : : move ( node_opts . i2p_sam_session ) }
2014-08-21 05:17:21 +02:00
{
2020-10-21 11:52:19 +02:00
if ( inbound_onion ) assert ( conn_type_in = = ConnectionType : : INBOUND ) ;
2020-08-10 14:48:54 -07:00
2017-06-02 03:18:57 +02:00
for ( const std : : string & msg : getAllNetMessageTypes ( ) )
2022-04-07 17:13:52 +05:30
mapRecvBytesPerMsgType [ msg ] = 0 ;
mapRecvBytesPerMsgType [ NET_MESSAGE_TYPE_OTHER ] = 0 ;
2014-08-21 05:17:21 +02:00
2016-12-25 20:19:40 +00:00
if ( fLogIPs ) {
2021-08-24 19:54:13 +02:00
LogPrint ( BCLog : : NET , " Added connection to %s peer=%d \n " , m_addr_name , id ) ;
2016-12-25 20:19:40 +00:00
} else {
LogPrint ( BCLog : : NET , " Added connection peer=%d \n " , id ) ;
}
2014-08-21 05:17:21 +02:00
}
2023-03-24 15:45:50 +01:00
void CNode : : MarkReceivedMsgsForProcessing ( )
2023-03-14 17:38:46 +01:00
{
2023-03-14 18:24:58 +01:00
AssertLockNotHeld ( m_msg_process_queue_mutex ) ;
2023-03-14 17:38:46 +01:00
size_t nSizeAdded = 0 ;
for ( const auto & msg : vRecvMsg ) {
// vRecvMsg contains only completed CNetMessage
// the single possible partially deserialized message are held by TransportDeserializer
nSizeAdded + = msg . m_raw_message_size ;
}
2023-03-14 18:24:58 +01:00
LOCK ( m_msg_process_queue_mutex ) ;
m_msg_process_queue . splice ( m_msg_process_queue . end ( ) , vRecvMsg ) ;
m_msg_process_queue_size + = nSizeAdded ;
2023-03-24 15:45:50 +01:00
fPauseRecv = m_msg_process_queue_size > m_recv_flood_size ;
2023-03-14 17:38:46 +01:00
}
2023-03-24 15:45:50 +01:00
std : : optional < std : : pair < CNetMessage , bool > > CNode : : PollMessage ( )
2023-03-14 17:58:59 +01:00
{
2023-03-14 18:24:58 +01:00
LOCK ( m_msg_process_queue_mutex ) ;
if ( m_msg_process_queue . empty ( ) ) return std : : nullopt ;
2023-03-14 17:58:59 +01:00
std : : list < CNetMessage > msgs ;
// Just take one message
2023-03-14 18:24:58 +01:00
msgs . splice ( msgs . begin ( ) , m_msg_process_queue , m_msg_process_queue . begin ( ) ) ;
m_msg_process_queue_size - = msgs . front ( ) . m_raw_message_size ;
2023-03-24 15:45:50 +01:00
fPauseRecv = m_msg_process_queue_size > m_recv_flood_size ;
2023-03-14 17:58:59 +01:00
2023-03-14 18:24:58 +01:00
return std : : make_pair ( std : : move ( msgs . front ( ) ) , ! m_msg_process_queue . empty ( ) ) ;
2023-03-14 17:58:59 +01:00
}
2017-01-20 20:34:57 -05:00
bool CConnman : : NodeFullyConnected ( const CNode * pnode )
{
return pnode & & pnode - > fSuccessfullyConnected & & ! pnode - > fDisconnect ;
}
2016-11-10 20:17:30 -05:00
void CConnman : : PushMessage ( CNode * pnode , CSerializedNetMsg & & msg )
2016-09-12 20:00:33 -04:00
{
2022-01-25 18:18:52 -03:00
AssertLockNotHeld ( m_total_bytes_sent_mutex ) ;
2016-11-10 20:17:30 -05:00
size_t nMessageSize = msg . data . size ( ) ;
2021-05-20 16:54:54 +02:00
LogPrint ( BCLog : : NET , " sending %s (%d bytes) peer=%d \n " , msg . m_type , nMessageSize , pnode - > GetId ( ) ) ;
2020-07-13 14:00:03 -04:00
if ( gArgs . GetBoolArg ( " -capturemessages " , false ) ) {
2021-09-15 11:10:51 +02:00
CaptureMessage ( pnode - > addr , msg . m_type , msg . data , /*is_incoming=*/ false ) ;
2020-07-13 14:00:03 -04:00
}
2016-09-12 20:00:33 -04:00
2021-05-20 16:54:54 +02:00
TRACE6 ( net , outbound_message ,
pnode - > GetId ( ) ,
2021-08-26 10:39:10 +02:00
pnode - > m_addr_name . c_str ( ) ,
2021-05-20 16:54:54 +02:00
pnode - > ConnectionTypeAsString ( ) . c_str ( ) ,
msg . m_type . c_str ( ) ,
msg . data . size ( ) ,
msg . data . data ( )
) ;
2019-08-07 15:56:24 +02:00
// make sure we use the appropriate network transport format
2016-11-10 20:17:30 -05:00
std : : vector < unsigned char > serializedHeader ;
2019-08-07 15:56:24 +02:00
pnode - > m_serializer - > prepareForTransport ( msg , serializedHeader ) ;
size_t nTotalSize = nMessageSize + serializedHeader . size ( ) ;
2016-09-12 20:00:33 -04:00
size_t nBytesSent = 0 ;
{
LOCK ( pnode - > cs_vSend ) ;
bool optimisticSend ( pnode - > vSendMsg . empty ( ) ) ;
2020-05-10 19:48:11 +02:00
//log total amount of bytes per message type
2023-03-14 17:48:32 +01:00
pnode - > AccountForSentBytes ( msg . m_type , nTotalSize ) ;
2016-11-10 20:17:30 -05:00
pnode - > nSendSize + = nTotalSize ;
2020-07-22 08:59:16 -04:00
if ( pnode - > nSendSize > nSendBufferMaxSize ) pnode - > fPauseSend = true ;
2016-11-10 20:17:30 -05:00
pnode - > vSendMsg . push_back ( std : : move ( serializedHeader ) ) ;
2020-07-22 08:59:16 -04:00
if ( nMessageSize ) pnode - > vSendMsg . push_back ( std : : move ( msg . data ) ) ;
2016-09-12 20:00:33 -04:00
// If write queue empty, attempt "optimistic write"
2020-07-22 08:59:16 -04:00
if ( optimisticSend ) nBytesSent = SocketSendData ( * pnode ) ;
2016-09-12 20:00:33 -04:00
}
2020-07-22 08:59:16 -04:00
if ( nBytesSent ) RecordBytesSent ( nBytesSent ) ;
2016-09-12 20:00:33 -04:00
}
2016-04-16 19:13:12 -04:00
bool CConnman : : ForNode ( NodeId id , std : : function < bool ( CNode * pnode ) > func )
{
CNode * found = nullptr ;
2021-08-28 20:57:52 +02:00
LOCK ( m_nodes_mutex ) ;
for ( auto & & pnode : m_nodes ) {
2017-04-11 12:13:55 -04:00
if ( pnode - > GetId ( ) = = id ) {
2016-04-16 19:13:12 -04:00
found = pnode ;
break ;
}
}
2017-01-20 20:34:57 -05:00
return found ! = nullptr & & NodeFullyConnected ( found ) & & func ( found ) ;
2016-04-16 19:13:12 -04:00
}
2017-01-24 02:32:52 +01:00
CSipHasher CConnman : : GetDeterministicRandomizer ( uint64_t id ) const
2016-05-25 15:38:32 +02:00
{
2016-09-09 12:48:10 +02:00
return CSipHasher ( nSeed0 , nSeed1 ) . Write ( id ) ;
}
2016-05-25 15:38:32 +02:00
2021-09-01 12:12:52 +01:00
uint64_t CConnman : : CalculateKeyedNetGroup ( const CAddress & address ) const
2016-09-09 12:48:10 +02:00
{
2021-09-01 12:12:52 +01:00
std : : vector < unsigned char > vchNetGroup ( m_netgroupman . GetGroup ( address ) ) ;
2016-05-25 15:38:32 +02:00
2017-02-19 13:18:04 -05:00
return GetDeterministicRandomizer ( RANDOMIZER_ID_NETGROUP ) . Write ( vchNetGroup . data ( ) , vchNetGroup . size ( ) ) . Finalize ( ) ;
2016-05-25 15:38:32 +02:00
}
2020-07-13 13:20:47 -04:00
2021-07-22 18:23:21 +02:00
void CaptureMessageToFile ( const CAddress & addr ,
const std : : string & msg_type ,
2021-07-29 17:47:15 +02:00
Span < const unsigned char > data ,
2021-07-22 18:23:21 +02:00
bool is_incoming )
2020-07-13 13:20:47 -04:00
{
// Note: This function captures the message at the time of processing,
// not at socket receive/send time.
// This ensures that the messages are always in order from an application
// layer (processing) perspective.
auto now = GetTime < std : : chrono : : microseconds > ( ) ;
2022-02-17 12:54:39 +01:00
// Windows folder names cannot include a colon
2022-07-15 14:13:39 +02:00
std : : string clean_addr = addr . ToStringAddrPort ( ) ;
2020-07-13 13:20:47 -04:00
std : : replace ( clean_addr . begin ( ) , clean_addr . end ( ) , ' : ' , ' _ ' ) ;
2022-03-03 14:40:18 -05:00
fs : : path base_path = gArgs . GetDataDirNet ( ) / " message_capture " / fs : : u8path ( clean_addr ) ;
2020-07-13 13:20:47 -04:00
fs : : create_directories ( base_path ) ;
fs : : path path = base_path / ( is_incoming ? " msgs_recv.dat " : " msgs_sent.dat " ) ;
2022-06-06 17:22:59 +02:00
AutoFile f { fsbridge : : fopen ( path , " ab " ) } ;
2020-07-13 13:20:47 -04:00
ser_writedata64 ( f , now . count ( ) ) ;
2022-01-02 11:31:25 +01:00
f . write ( MakeByteSpan ( msg_type ) ) ;
2020-07-13 13:20:47 -04:00
for ( auto i = msg_type . length ( ) ; i < CMessageHeader : : COMMAND_SIZE ; + + i ) {
2021-05-31 14:57:32 +02:00
f < < uint8_t { ' \0 ' } ;
2020-07-13 13:20:47 -04:00
}
uint32_t size = data . size ( ) ;
ser_writedata32 ( f , size ) ;
2022-01-02 11:31:25 +01:00
f . write ( AsBytes ( data ) ) ;
2020-07-13 13:20:47 -04:00
}
2021-07-22 18:23:21 +02:00
std : : function < void ( const CAddress & addr ,
const std : : string & msg_type ,
2021-07-29 17:47:15 +02:00
Span < const unsigned char > data ,
2021-07-22 18:23:21 +02:00
bool is_incoming ) >
CaptureMessage = CaptureMessageToFile ;