LCOV - code coverage report
Current view: top level - src - net.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 1718 2067 83.1 %
Date: 2022-04-21 14:51:19 Functions: 133 140 95.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 695 1078 64.5 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2009-2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2021 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #if defined(HAVE_CONFIG_H)
#       7                 :            : #include <config/bitcoin-config.h>
#       8                 :            : #endif
#       9                 :            : 
#      10                 :            : #include <net.h>
#      11                 :            : 
#      12                 :            : #include <addrdb.h>
#      13                 :            : #include <addrman.h>
#      14                 :            : #include <banman.h>
#      15                 :            : #include <clientversion.h>
#      16                 :            : #include <compat.h>
#      17                 :            : #include <consensus/consensus.h>
#      18                 :            : #include <crypto/sha256.h>
#      19                 :            : #include <fs.h>
#      20                 :            : #include <i2p.h>
#      21                 :            : #include <net_permissions.h>
#      22                 :            : #include <netaddress.h>
#      23                 :            : #include <netbase.h>
#      24                 :            : #include <node/ui_interface.h>
#      25                 :            : #include <protocol.h>
#      26                 :            : #include <random.h>
#      27                 :            : #include <scheduler.h>
#      28                 :            : #include <util/sock.h>
#      29                 :            : #include <util/strencodings.h>
#      30                 :            : #include <util/syscall_sandbox.h>
#      31                 :            : #include <util/system.h>
#      32                 :            : #include <util/thread.h>
#      33                 :            : #include <util/trace.h>
#      34                 :            : #include <util/translation.h>
#      35                 :            : 
#      36                 :            : #ifdef WIN32
#      37                 :            : #include <string.h>
#      38                 :            : #else
#      39                 :            : #include <fcntl.h>
#      40                 :            : #endif
#      41                 :            : 
#      42                 :            : #if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
#      43                 :            : #include <ifaddrs.h>
#      44                 :            : #endif
#      45                 :            : 
#      46                 :            : #ifdef USE_POLL
#      47                 :            : #include <poll.h>
#      48                 :            : #endif
#      49                 :            : 
#      50                 :            : #include <algorithm>
#      51                 :            : #include <array>
#      52                 :            : #include <cstdint>
#      53                 :            : #include <functional>
#      54                 :            : #include <optional>
#      55                 :            : #include <unordered_map>
#      56                 :            : 
#      57                 :            : #include <math.h>
#      58                 :            : 
#      59                 :            : /** Maximum number of block-relay-only anchor connections */
#      60                 :            : static constexpr size_t MAX_BLOCK_RELAY_ONLY_ANCHORS = 2;
#      61                 :            : 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.");
#      62                 :            : /** Anchor IP address database file name */
#      63                 :            : const char* const ANCHORS_DATABASE_FILENAME = "anchors.dat";
#      64                 :            : 
#      65                 :            : // How often to dump addresses to peers.dat
#      66                 :            : static constexpr std::chrono::minutes DUMP_PEERS_INTERVAL{15};
#      67                 :            : 
#      68                 :            : /** Number of DNS seeds to query when the number of connections is low. */
#      69                 :            : static constexpr int DNSSEEDS_TO_QUERY_AT_ONCE = 3;
#      70                 :            : 
#      71                 :            : /** How long to delay before querying DNS seeds
#      72                 :            :  *
#      73                 :            :  * If we have more than THRESHOLD entries in addrman, then it's likely
#      74                 :            :  * that we got those addresses from having previously connected to the P2P
#      75                 :            :  * network, and that we'll be able to successfully reconnect to the P2P
#      76                 :            :  * network via contacting one of them. So if that's the case, spend a
#      77                 :            :  * little longer trying to connect to known peers before querying the
#      78                 :            :  * DNS seeds.
#      79                 :            :  */
#      80                 :            : static constexpr std::chrono::seconds DNSSEEDS_DELAY_FEW_PEERS{11};
#      81                 :            : static constexpr std::chrono::minutes DNSSEEDS_DELAY_MANY_PEERS{5};
#      82                 :            : static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" peers
#      83                 :            : 
#      84                 :            : /** The default timeframe for -maxuploadtarget. 1 day. */
#      85                 :            : static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24};
#      86                 :            : 
#      87                 :            : // We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#      88                 :          0 : #define FEELER_SLEEP_WINDOW 1
#      89                 :            : 
#      90                 :            : /** Used to pass flags to the Bind() function */
#      91                 :            : enum BindFlags {
#      92                 :            :     BF_NONE         = 0,
#      93                 :            :     BF_EXPLICIT     = (1U << 0),
#      94                 :            :     BF_REPORT_ERROR = (1U << 1),
#      95                 :            :     /**
#      96                 :            :      * Do not call AddLocal() for our special addresses, e.g., for incoming
#      97                 :            :      * Tor connections, to prevent gossiping them over the network.
#      98                 :            :      */
#      99                 :            :     BF_DONT_ADVERTISE = (1U << 2),
#     100                 :            : };
#     101                 :            : 
#     102                 :            : // The set of sockets cannot be modified while waiting
#     103                 :            : // The sleep time needs to be small to avoid new sockets stalling
#     104                 :            : static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50;
#     105                 :            : 
#     106                 :            : const std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
#     107                 :            : 
#     108                 :            : static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
#     109                 :            : static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
#     110                 :            : static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8]
#     111                 :            : //
#     112                 :            : // Global state variables
#     113                 :            : //
#     114                 :            : bool fDiscover = true;
#     115                 :            : bool fListen = true;
#     116                 :            : Mutex g_maplocalhost_mutex;
#     117                 :            : std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex);
#     118                 :            : static bool vfLimited[NET_MAX] GUARDED_BY(g_maplocalhost_mutex) = {};
#     119                 :            : std::string strSubVersion;
#     120                 :            : 
#     121                 :            : void CConnman::AddAddrFetch(const std::string& strDest)
#     122                 :          6 : {
#     123                 :          6 :     LOCK(m_addr_fetches_mutex);
#     124                 :          6 :     m_addr_fetches.push_back(strDest);
#     125                 :          6 : }
#     126                 :            : 
#     127                 :            : uint16_t GetListenPort()
#     128                 :       1300 : {
#     129                 :            :     // If -bind= is provided with ":port" part, use that (first one if multiple are provided).
#     130         [ +  + ]:       1300 :     for (const std::string& bind_arg : gArgs.GetArgs("-bind")) {
#     131                 :       1293 :         CService bind_addr;
#     132                 :       1293 :         constexpr uint16_t dummy_port = 0;
#     133                 :            : 
#     134         [ +  - ]:       1293 :         if (Lookup(bind_arg, bind_addr, dummy_port, /*fAllowLookup=*/false)) {
#     135         [ +  + ]:       1293 :             if (bind_addr.GetPort() != dummy_port) {
#     136                 :          8 :                 return bind_addr.GetPort();
#     137                 :          8 :             }
#     138                 :       1293 :         }
#     139                 :       1293 :     }
#     140                 :            : 
#     141                 :            :     // Otherwise, if -whitebind= without NetPermissionFlags::NoBan is provided, use that
#     142                 :            :     // (-whitebind= is required to have ":port").
#     143         [ +  + ]:       1292 :     for (const std::string& whitebind_arg : gArgs.GetArgs("-whitebind")) {
#     144                 :          1 :         NetWhitebindPermissions whitebind;
#     145                 :          1 :         bilingual_str error;
#     146         [ +  - ]:          1 :         if (NetWhitebindPermissions::TryParse(whitebind_arg, whitebind, error)) {
#     147         [ +  - ]:          1 :             if (!NetPermissions::HasFlag(whitebind.m_flags, NetPermissionFlags::NoBan)) {
#     148                 :          1 :                 return whitebind.m_service.GetPort();
#     149                 :          1 :             }
#     150                 :          1 :         }
#     151                 :          1 :     }
#     152                 :            : 
#     153                 :            :     // Otherwise, if -port= is provided, use that. Otherwise use the default port.
#     154                 :       1291 :     return static_cast<uint16_t>(gArgs.GetIntArg("-port", Params().GetDefaultPort()));
#     155                 :       1292 : }
#     156                 :            : 
#     157                 :            : // find 'best' local address for a particular peer
#     158                 :            : bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
#     159                 :       1291 : {
#     160         [ -  + ]:       1291 :     if (!fListen)
#     161                 :          0 :         return false;
#     162                 :            : 
#     163                 :       1291 :     int nBestScore = -1;
#     164                 :       1291 :     int nBestReachability = -1;
#     165                 :       1291 :     {
#     166                 :       1291 :         LOCK(g_maplocalhost_mutex);
#     167         [ +  + ]:       1291 :         for (const auto& entry : mapLocalHost)
#     168                 :          2 :         {
#     169                 :          2 :             int nScore = entry.second.nScore;
#     170                 :          2 :             int nReachability = entry.first.GetReachabilityFrom(paddrPeer);
#     171 [ +  - ][ #  # ]:          2 :             if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
#                 [ #  # ]
#     172                 :          2 :             {
#     173                 :          2 :                 addr = CService(entry.first, entry.second.nPort);
#     174                 :          2 :                 nBestReachability = nReachability;
#     175                 :          2 :                 nBestScore = nScore;
#     176                 :          2 :             }
#     177                 :          2 :         }
#     178                 :       1291 :     }
#     179                 :       1291 :     return nBestScore >= 0;
#     180                 :       1291 : }
#     181                 :            : 
#     182                 :            : //! Convert the serialized seeds into usable address objects.
#     183                 :            : static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
#     184                 :          3 : {
#     185                 :            :     // It'll only connect to one or two seed nodes because once it connects,
#     186                 :            :     // it'll get a pile of addresses with newer timestamps.
#     187                 :            :     // Seed nodes are given a random 'last seen time' of between one and two
#     188                 :            :     // weeks ago.
#     189                 :          3 :     const int64_t nOneWeek = 7*24*60*60;
#     190                 :          3 :     std::vector<CAddress> vSeedsOut;
#     191                 :          3 :     FastRandomContext rng;
#     192                 :          3 :     CDataStream s(vSeedsIn, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
#     193         [ -  + ]:          3 :     while (!s.eof()) {
#     194                 :          0 :         CService endpoint;
#     195                 :          0 :         s >> endpoint;
#     196                 :          0 :         CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)};
#     197                 :          0 :         addr.nTime = GetTime() - rng.randrange(nOneWeek) - nOneWeek;
#     198         [ #  # ]:          0 :         LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToString());
#     199                 :          0 :         vSeedsOut.push_back(addr);
#     200                 :          0 :     }
#     201                 :          3 :     return vSeedsOut;
#     202                 :          3 : }
#     203                 :            : 
#     204                 :            : // get best local address for a particular peer as a CAddress
#     205                 :            : // Otherwise, return the unroutable 0.0.0.0 but filled in with
#     206                 :            : // the normal parameters, since the IP may be changed to a useful
#     207                 :            : // one by discovery.
#     208                 :            : CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
#     209                 :       1291 : {
#     210                 :       1291 :     CAddress ret(CService(CNetAddr(),GetListenPort()), nLocalServices);
#     211                 :       1291 :     CService addr;
#     212         [ +  + ]:       1291 :     if (GetLocal(addr, paddrPeer))
#     213                 :          2 :     {
#     214                 :          2 :         ret = CAddress(addr, nLocalServices);
#     215                 :          2 :     }
#     216                 :       1291 :     ret.nTime = GetAdjustedTime();
#     217                 :       1291 :     return ret;
#     218                 :       1291 : }
#     219                 :            : 
#     220                 :            : static int GetnScore(const CService& addr)
#     221                 :          0 : {
#     222                 :          0 :     LOCK(g_maplocalhost_mutex);
#     223                 :          0 :     const auto it = mapLocalHost.find(addr);
#     224         [ #  # ]:          0 :     return (it != mapLocalHost.end()) ? it->second.nScore : 0;
#     225                 :          0 : }
#     226                 :            : 
#     227                 :            : // Is our peer's addrLocal potentially useful as an external IP source?
#     228                 :            : bool IsPeerAddrLocalGood(CNode *pnode)
#     229                 :       1291 : {
#     230                 :       1291 :     CService addrLocal = pnode->GetAddrLocal();
#     231 [ +  + ][ +  - ]:       1291 :     return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() &&
#                 [ +  - ]
#     232         [ +  - ]:       1291 :            IsReachable(addrLocal.GetNetwork());
#     233                 :       1291 : }
#     234                 :            : 
#     235                 :            : std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
#     236                 :       1028 : {
#     237                 :       1028 :     CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices());
#     238         [ +  + ]:       1028 :     if (gArgs.GetBoolArg("-addrmantest", false)) {
#     239                 :            :         // use IPv4 loopback during addrmantest
#     240                 :          5 :         addrLocal = CAddress(CService(LookupNumeric("127.0.0.1", GetListenPort())), pnode->GetLocalServices());
#     241                 :          5 :     }
#     242                 :            :     // If discovery is enabled, sometimes give our peer the address it
#     243                 :            :     // tells us that it sees us as in case it has a better idea of our
#     244                 :            :     // address than we do.
#     245                 :       1028 :     FastRandomContext rng;
#     246 [ +  + ][ +  - ]:       1028 :     if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
#     247 [ #  # ][ #  # ]:          8 :          rng.randbits((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3 : 1) == 0))
#     248                 :          8 :     {
#     249         [ +  + ]:          8 :         if (pnode->IsInboundConn()) {
#     250                 :            :             // For inbound connections, assume both the address and the port
#     251                 :            :             // as seen from the peer.
#     252                 :          2 :             addrLocal = CAddress{pnode->GetAddrLocal(), addrLocal.nServices};
#     253                 :          6 :         } else {
#     254                 :            :             // For outbound connections, assume just the address as seen from
#     255                 :            :             // the peer and leave the port in `addrLocal` as returned by
#     256                 :            :             // `GetLocalAddress()` above. The peer has no way to observe our
#     257                 :            :             // listening port when we have initiated the connection.
#     258                 :          6 :             addrLocal.SetIP(pnode->GetAddrLocal());
#     259                 :          6 :         }
#     260                 :          8 :     }
#     261 [ +  + ][ +  + ]:       1028 :     if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false))
#                 [ +  + ]
#     262                 :         13 :     {
#     263         [ +  - ]:         13 :         LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), pnode->GetId());
#     264                 :         13 :         return addrLocal;
#     265                 :         13 :     }
#     266                 :            :     // Address is unroutable. Don't advertise.
#     267                 :       1015 :     return std::nullopt;
#     268                 :       1028 : }
#     269                 :            : 
#     270                 :            : /**
#     271                 :            :  * If an IPv6 address belongs to the address range used by the CJDNS network and
#     272                 :            :  * the CJDNS network is reachable (-cjdnsreachable config is set), then change
#     273                 :            :  * the type from NET_IPV6 to NET_CJDNS.
#     274                 :            :  * @param[in] service Address to potentially convert.
#     275                 :            :  * @return a copy of `service` either unmodified or changed to CJDNS.
#     276                 :            :  */
#     277                 :            : CService MaybeFlipIPv6toCJDNS(const CService& service)
#     278                 :       3223 : {
#     279                 :       3223 :     CService ret{service};
#     280 [ +  + ][ +  + ]:       3223 :     if (ret.m_net == NET_IPV6 && ret.m_addr[0] == 0xfc && IsReachable(NET_CJDNS)) {
#                 [ +  - ]
#     281                 :          1 :         ret.m_net = NET_CJDNS;
#     282                 :          1 :     }
#     283                 :       3223 :     return ret;
#     284                 :       3223 : }
#     285                 :            : 
#     286                 :            : // learn a new local address
#     287                 :            : bool AddLocal(const CService& addr_, int nScore)
#     288                 :          2 : {
#     289                 :          2 :     CService addr{MaybeFlipIPv6toCJDNS(addr_)};
#     290                 :            : 
#     291         [ -  + ]:          2 :     if (!addr.IsRoutable())
#     292                 :          0 :         return false;
#     293                 :            : 
#     294 [ -  + ][ #  # ]:          2 :     if (!fDiscover && nScore < LOCAL_MANUAL)
#     295                 :          0 :         return false;
#     296                 :            : 
#     297         [ -  + ]:          2 :     if (!IsReachable(addr))
#     298                 :          0 :         return false;
#     299                 :            : 
#     300                 :          2 :     LogPrintf("AddLocal(%s,%i)\n", addr.ToString(), nScore);
#     301                 :            : 
#     302                 :          2 :     {
#     303                 :          2 :         LOCK(g_maplocalhost_mutex);
#     304                 :          2 :         const auto [it, is_newly_added] = mapLocalHost.emplace(addr, LocalServiceInfo());
#     305                 :          2 :         LocalServiceInfo &info = it->second;
#     306 [ +  - ][ #  # ]:          2 :         if (is_newly_added || nScore >= info.nScore) {
#     307         [ +  - ]:          2 :             info.nScore = nScore + (is_newly_added ? 0 : 1);
#     308                 :          2 :             info.nPort = addr.GetPort();
#     309                 :          2 :         }
#     310                 :          2 :     }
#     311                 :            : 
#     312                 :          2 :     return true;
#     313                 :          2 : }
#     314                 :            : 
#     315                 :            : bool AddLocal(const CNetAddr &addr, int nScore)
#     316                 :          0 : {
#     317                 :          0 :     return AddLocal(CService(addr, GetListenPort()), nScore);
#     318                 :          0 : }
#     319                 :            : 
#     320                 :            : void RemoveLocal(const CService& addr)
#     321                 :          2 : {
#     322                 :          2 :     LOCK(g_maplocalhost_mutex);
#     323                 :          2 :     LogPrintf("RemoveLocal(%s)\n", addr.ToString());
#     324                 :          2 :     mapLocalHost.erase(addr);
#     325                 :          2 : }
#     326                 :            : 
#     327                 :            : void SetReachable(enum Network net, bool reachable)
#     328                 :       2253 : {
#     329 [ +  + ][ +  + ]:       2253 :     if (net == NET_UNROUTABLE || net == NET_INTERNAL)
#     330                 :         10 :         return;
#     331                 :       2243 :     LOCK(g_maplocalhost_mutex);
#     332                 :       2243 :     vfLimited[net] = !reachable;
#     333                 :       2243 : }
#     334                 :            : 
#     335                 :            : bool IsReachable(enum Network net)
#     336                 :       2130 : {
#     337                 :       2130 :     LOCK(g_maplocalhost_mutex);
#     338                 :       2130 :     return !vfLimited[net];
#     339                 :       2130 : }
#     340                 :            : 
#     341                 :            : bool IsReachable(const CNetAddr &addr)
#     342                 :       1267 : {
#     343                 :       1267 :     return IsReachable(addr.GetNetwork());
#     344                 :       1267 : }
#     345                 :            : 
#     346                 :            : /** vote for a local address */
#     347                 :            : bool SeenLocal(const CService& addr)
#     348                 :          0 : {
#     349                 :          0 :     LOCK(g_maplocalhost_mutex);
#     350                 :          0 :     const auto it = mapLocalHost.find(addr);
#     351         [ #  # ]:          0 :     if (it == mapLocalHost.end()) return false;
#     352                 :          0 :     ++it->second.nScore;
#     353                 :          0 :     return true;
#     354                 :          0 : }
#     355                 :            : 
#     356                 :            : 
#     357                 :            : /** check whether a given address is potentially local */
#     358                 :            : bool IsLocal(const CService& addr)
#     359                 :          6 : {
#     360                 :          6 :     LOCK(g_maplocalhost_mutex);
#     361                 :          6 :     return mapLocalHost.count(addr) > 0;
#     362                 :          6 : }
#     363                 :            : 
#     364                 :            : CNode* CConnman::FindNode(const CNetAddr& ip)
#     365                 :          0 : {
#     366                 :          0 :     LOCK(m_nodes_mutex);
#     367         [ #  # ]:          0 :     for (CNode* pnode : m_nodes) {
#     368         [ #  # ]:          0 :       if (static_cast<CNetAddr>(pnode->addr) == ip) {
#     369                 :          0 :             return pnode;
#     370                 :          0 :         }
#     371                 :          0 :     }
#     372                 :          0 :     return nullptr;
#     373                 :          0 : }
#     374                 :            : 
#     375                 :            : CNode* CConnman::FindNode(const CSubNet& subNet)
#     376                 :          0 : {
#     377                 :          0 :     LOCK(m_nodes_mutex);
#     378         [ #  # ]:          0 :     for (CNode* pnode : m_nodes) {
#     379         [ #  # ]:          0 :         if (subNet.Match(static_cast<CNetAddr>(pnode->addr))) {
#     380                 :          0 :             return pnode;
#     381                 :          0 :         }
#     382                 :          0 :     }
#     383                 :          0 :     return nullptr;
#     384                 :          0 : }
#     385                 :            : 
#     386                 :            : CNode* CConnman::FindNode(const std::string& addrName)
#     387                 :        441 : {
#     388                 :        441 :     LOCK(m_nodes_mutex);
#     389         [ +  + ]:        441 :     for (CNode* pnode : m_nodes) {
#     390         [ +  + ]:        418 :         if (pnode->m_addr_name == addrName) {
#     391                 :          1 :             return pnode;
#     392                 :          1 :         }
#     393                 :        418 :     }
#     394                 :        440 :     return nullptr;
#     395                 :        441 : }
#     396                 :            : 
#     397                 :            : CNode* CConnman::FindNode(const CService& addr)
#     398                 :        427 : {
#     399                 :        427 :     LOCK(m_nodes_mutex);
#     400         [ +  + ]:        427 :     for (CNode* pnode : m_nodes) {
#     401         [ -  + ]:        397 :         if (static_cast<CService>(pnode->addr) == addr) {
#     402                 :          0 :             return pnode;
#     403                 :          0 :         }
#     404                 :        397 :     }
#     405                 :        427 :     return nullptr;
#     406                 :        427 : }
#     407                 :            : 
#     408                 :            : bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
#     409                 :          0 : {
#     410 [ #  # ][ #  # ]:          0 :     return FindNode(static_cast<CNetAddr>(addr)) || FindNode(addr.ToStringIPPort());
#     411                 :          0 : }
#     412                 :            : 
#     413                 :            : bool CConnman::CheckIncomingNonce(uint64_t nonce)
#     414                 :        672 : {
#     415                 :        672 :     LOCK(m_nodes_mutex);
#     416         [ +  + ]:       1606 :     for (const CNode* pnode : m_nodes) {
#     417 [ +  + ][ -  + ]:       1606 :         if (!pnode->fSuccessfullyConnected && !pnode->IsInboundConn() && pnode->GetLocalNonce() == nonce)
#                 [ #  # ]
#     418                 :          0 :             return false;
#     419                 :       1606 :     }
#     420                 :        672 :     return true;
#     421                 :        672 : }
#     422                 :            : 
#     423                 :            : /** Get the bind address for a socket as CAddress */
#     424                 :            : static CAddress GetBindAddress(SOCKET sock)
#     425                 :       1108 : {
#     426                 :       1108 :     CAddress addr_bind;
#     427                 :       1108 :     struct sockaddr_storage sockaddr_bind;
#     428                 :       1108 :     socklen_t sockaddr_bind_len = sizeof(sockaddr_bind);
#     429         [ +  - ]:       1108 :     if (sock != INVALID_SOCKET) {
#     430         [ +  - ]:       1108 :         if (!getsockname(sock, (struct sockaddr*)&sockaddr_bind, &sockaddr_bind_len)) {
#     431                 :       1108 :             addr_bind.SetSockAddr((const struct sockaddr*)&sockaddr_bind);
#     432                 :       1108 :         } else {
#     433         [ #  # ]:          0 :             LogPrint(BCLog::NET, "Warning: getsockname failed\n");
#     434                 :          0 :         }
#     435                 :       1108 :     }
#     436                 :       1108 :     return addr_bind;
#     437                 :       1108 : }
#     438                 :            : 
#     439                 :            : CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type)
#     440                 :        439 : {
#     441                 :        439 :     assert(conn_type != ConnectionType::INBOUND);
#     442                 :            : 
#     443         [ -  + ]:        439 :     if (pszDest == nullptr) {
#     444         [ #  # ]:          0 :         if (IsLocal(addrConnect))
#     445                 :          0 :             return nullptr;
#     446                 :            : 
#     447                 :            :         // Look for an existing connection
#     448                 :          0 :         CNode* pnode = FindNode(static_cast<CService>(addrConnect));
#     449         [ #  # ]:          0 :         if (pnode)
#     450                 :          0 :         {
#     451                 :          0 :             LogPrintf("Failed to open new connection, already connected\n");
#     452                 :          0 :             return nullptr;
#     453                 :          0 :         }
#     454                 :          0 :     }
#     455                 :            : 
#     456                 :            :     /// debug print
#     457 [ +  - ][ +  - ]:        439 :     LogPrint(BCLog::NET, "trying connection %s lastseen=%.1fhrs\n",
#                 [ +  - ]
#     458                 :        439 :         pszDest ? pszDest : addrConnect.ToString(),
#     459                 :        439 :         pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
#     460                 :            : 
#     461                 :            :     // Resolve
#     462         [ +  - ]:        439 :     const uint16_t default_port{pszDest != nullptr ? Params().GetDefaultPort(pszDest) :
#     463                 :        439 :                                                      Params().GetDefaultPort()};
#     464         [ +  - ]:        439 :     if (pszDest) {
#     465                 :        439 :         std::vector<CService> resolved;
#     466 [ +  + ][ +  + ]:        439 :         if (Lookup(pszDest, resolved,  default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) {
#         [ +  - ][ +  + ]
#                 [ +  - ]
#     467                 :        429 :             const CService rnd{resolved[GetRand(resolved.size())]};
#     468                 :        429 :             addrConnect = CAddress{MaybeFlipIPv6toCJDNS(rnd), NODE_NONE};
#     469         [ +  + ]:        429 :             if (!addrConnect.IsValid()) {
#     470         [ +  - ]:          2 :                 LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToString(), pszDest);
#     471                 :          2 :                 return nullptr;
#     472                 :          2 :             }
#     473                 :            :             // It is possible that we already have a connection to the IP/port pszDest resolved to.
#     474                 :            :             // In that case, drop the connection that was just created.
#     475                 :        427 :             LOCK(m_nodes_mutex);
#     476                 :        427 :             CNode* pnode = FindNode(static_cast<CService>(addrConnect));
#     477         [ -  + ]:        427 :             if (pnode) {
#     478                 :          0 :                 LogPrintf("Failed to open new connection, already connected\n");
#     479                 :          0 :                 return nullptr;
#     480                 :          0 :             }
#     481                 :        427 :         }
#     482                 :        439 :     }
#     483                 :            : 
#     484                 :            :     // Connect
#     485                 :        437 :     bool connected = false;
#     486                 :        437 :     std::unique_ptr<Sock> sock;
#     487                 :        437 :     Proxy proxy;
#     488                 :        437 :     CAddress addr_bind;
#     489                 :        437 :     assert(!addr_bind.IsValid());
#     490                 :            : 
#     491         [ +  + ]:        437 :     if (addrConnect.IsValid()) {
#     492                 :        427 :         bool proxyConnectionFailed = false;
#     493                 :            : 
#     494 [ +  + ][ +  - ]:        427 :         if (addrConnect.GetNetwork() == NET_I2P && m_i2p_sam_session.get() != nullptr) {
#     495                 :          2 :             i2p::Connection conn;
#     496         [ -  + ]:          2 :             if (m_i2p_sam_session->Connect(addrConnect, conn, proxyConnectionFailed)) {
#     497                 :          0 :                 connected = true;
#     498                 :          0 :                 sock = std::move(conn.sock);
#     499                 :          0 :                 addr_bind = CAddress{conn.me, NODE_NONE};
#     500                 :          0 :             }
#     501         [ +  + ]:        425 :         } else if (GetProxy(addrConnect.GetNetwork(), proxy)) {
#     502                 :         15 :             sock = CreateSock(proxy.proxy);
#     503         [ -  + ]:         15 :             if (!sock) {
#     504                 :          0 :                 return nullptr;
#     505                 :          0 :             }
#     506                 :         15 :             connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(),
#     507                 :         15 :                                             *sock, nConnectTimeout, proxyConnectionFailed);
#     508                 :        410 :         } else {
#     509                 :            :             // no proxy needed (none set for target network)
#     510                 :        410 :             sock = CreateSock(addrConnect);
#     511         [ -  + ]:        410 :             if (!sock) {
#     512                 :          0 :                 return nullptr;
#     513                 :          0 :             }
#     514                 :        410 :             connected = ConnectSocketDirectly(addrConnect, *sock, nConnectTimeout,
#     515                 :        410 :                                               conn_type == ConnectionType::MANUAL);
#     516                 :        410 :         }
#     517         [ +  + ]:        427 :         if (!proxyConnectionFailed) {
#     518                 :            :             // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
#     519                 :            :             // the proxy, mark this as an attempt.
#     520                 :        426 :             addrman.Attempt(addrConnect, fCountFailure);
#     521                 :        426 :         }
#     522 [ +  - ][ +  + ]:        427 :     } else if (pszDest && GetNameProxy(proxy)) {
#     523                 :          5 :         sock = CreateSock(proxy.proxy);
#     524         [ -  + ]:          5 :         if (!sock) {
#     525                 :          0 :             return nullptr;
#     526                 :          0 :         }
#     527                 :          5 :         std::string host;
#     528                 :          5 :         uint16_t port{default_port};
#     529                 :          5 :         SplitHostPort(std::string(pszDest), port, host);
#     530                 :          5 :         bool proxyConnectionFailed;
#     531                 :          5 :         connected = ConnectThroughProxy(proxy, host, port, *sock, nConnectTimeout,
#     532                 :          5 :                                         proxyConnectionFailed);
#     533                 :          5 :     }
#     534         [ +  + ]:        437 :     if (!connected) {
#     535                 :          8 :         return nullptr;
#     536                 :          8 :     }
#     537                 :            : 
#     538                 :            :     // Add node
#     539                 :        429 :     NodeId id = GetNewNodeId();
#     540                 :        429 :     uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
#     541         [ +  - ]:        429 :     if (!addr_bind.IsValid()) {
#     542                 :        429 :         addr_bind = GetBindAddress(sock->Get());
#     543                 :        429 :     }
#     544                 :        429 :     CNode* pnode = new CNode(id,
#     545                 :        429 :                              nLocalServices,
#     546                 :        429 :                              std::move(sock),
#     547                 :        429 :                              addrConnect,
#     548                 :        429 :                              CalculateKeyedNetGroup(addrConnect),
#     549                 :        429 :                              nonce,
#     550                 :        429 :                              addr_bind,
#     551         [ +  - ]:        429 :                              pszDest ? pszDest : "",
#     552                 :        429 :                              conn_type,
#     553                 :        429 :                              /*inbound_onion=*/false);
#     554                 :        429 :     pnode->AddRef();
#     555                 :            : 
#     556                 :            :     // We're making a new connection, harvest entropy from the time (and our peer count)
#     557                 :        429 :     RandAddEvent((uint32_t)id);
#     558                 :            : 
#     559                 :        429 :     return pnode;
#     560                 :        437 : }
#     561                 :            : 
#     562                 :            : void CNode::CloseSocketDisconnect()
#     563                 :       1346 : {
#     564                 :       1346 :     fDisconnect = true;
#     565                 :       1346 :     LOCK(m_sock_mutex);
#     566         [ +  + ]:       1346 :     if (m_sock) {
#     567         [ +  - ]:       1107 :         LogPrint(BCLog::NET, "disconnecting peer=%d\n", id);
#     568                 :       1107 :         m_sock.reset();
#     569                 :       1107 :     }
#     570                 :       1346 : }
#     571                 :            : 
#     572                 :        679 : void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const {
#     573         [ +  + ]:        679 :     for (const auto& subnet : vWhitelistedRange) {
#     574         [ +  - ]:        157 :         if (subnet.m_subnet.Match(addr)) NetPermissions::AddFlag(flags, subnet.m_flags);
#     575                 :        157 :     }
#     576                 :        679 : }
#     577                 :            : 
#     578                 :            : std::string ConnectionTypeAsString(ConnectionType conn_type)
#     579                 :      15344 : {
#     580         [ -  + ]:      15344 :     switch (conn_type) {
#     581         [ +  + ]:       7556 :     case ConnectionType::INBOUND:
#     582                 :       7556 :         return "inbound";
#     583         [ +  + ]:       7619 :     case ConnectionType::MANUAL:
#     584                 :       7619 :         return "manual";
#     585         [ -  + ]:          0 :     case ConnectionType::FEELER:
#     586                 :          0 :         return "feeler";
#     587         [ +  + ]:         86 :     case ConnectionType::OUTBOUND_FULL_RELAY:
#     588                 :         86 :         return "outbound-full-relay";
#     589         [ +  + ]:         75 :     case ConnectionType::BLOCK_RELAY:
#     590                 :         75 :         return "block-relay-only";
#     591         [ +  + ]:          8 :     case ConnectionType::ADDR_FETCH:
#     592                 :          8 :         return "addr-fetch";
#     593                 :      15344 :     } // no default case, so the compiler can warn about missing cases
#     594                 :            : 
#     595                 :          0 :     assert(false);
#     596                 :          0 : }
#     597                 :            : 
#     598                 :            : CService CNode::GetAddrLocal() const
#     599                 :      16174 : {
#     600                 :      16174 :     AssertLockNotHeld(m_addr_local_mutex);
#     601                 :      16174 :     LOCK(m_addr_local_mutex);
#     602                 :      16174 :     return addrLocal;
#     603                 :      16174 : }
#     604                 :            : 
#     605                 :       1086 : void CNode::SetAddrLocal(const CService& addrLocalIn) {
#     606                 :       1086 :     AssertLockNotHeld(m_addr_local_mutex);
#     607                 :       1086 :     LOCK(m_addr_local_mutex);
#     608         [ -  + ]:       1086 :     if (addrLocal.IsValid()) {
#     609                 :          0 :         error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString());
#     610                 :       1086 :     } else {
#     611                 :       1086 :         addrLocal = addrLocalIn;
#     612                 :       1086 :     }
#     613                 :       1086 : }
#     614                 :            : 
#     615                 :            : Network CNode::ConnectedThroughNetwork() const
#     616                 :      14904 : {
#     617         [ +  + ]:      14904 :     return m_inbound_onion ? NET_ONION : addr.GetNetClass();
#     618                 :      14904 : }
#     619                 :            : 
#     620                 :            : #undef X
#     621                 :     327250 : #define X(name) stats.name = name
#     622                 :            : void CNode::CopyStats(CNodeStats& stats)
#     623                 :      14875 : {
#     624                 :      14875 :     stats.nodeid = this->GetId();
#     625                 :      14875 :     X(nServices);
#     626                 :      14875 :     X(addr);
#     627                 :      14875 :     X(addrBind);
#     628                 :      14875 :     stats.m_network = ConnectedThroughNetwork();
#     629                 :      14875 :     X(m_last_send);
#     630                 :      14875 :     X(m_last_recv);
#     631                 :      14875 :     X(m_last_tx_time);
#     632                 :      14875 :     X(m_last_block_time);
#     633                 :      14875 :     X(m_connected);
#     634                 :      14875 :     X(nTimeOffset);
#     635                 :      14875 :     X(m_addr_name);
#     636                 :      14875 :     X(nVersion);
#     637                 :      14875 :     {
#     638                 :      14875 :         LOCK(m_subver_mutex);
#     639                 :      14875 :         X(cleanSubVer);
#     640                 :      14875 :     }
#     641                 :      14875 :     stats.fInbound = IsInboundConn();
#     642                 :      14875 :     X(m_bip152_highbandwidth_to);
#     643                 :      14875 :     X(m_bip152_highbandwidth_from);
#     644                 :      14875 :     {
#     645                 :      14875 :         LOCK(cs_vSend);
#     646                 :      14875 :         X(mapSendBytesPerMsgCmd);
#     647                 :      14875 :         X(nSendBytes);
#     648                 :      14875 :     }
#     649                 :      14875 :     {
#     650                 :      14875 :         LOCK(cs_vRecv);
#     651                 :      14875 :         X(mapRecvBytesPerMsgCmd);
#     652                 :      14875 :         X(nRecvBytes);
#     653                 :      14875 :     }
#     654                 :      14875 :     X(m_permissionFlags);
#     655                 :            : 
#     656                 :      14875 :     X(m_last_ping_time);
#     657                 :      14875 :     X(m_min_ping_time);
#     658                 :            : 
#     659                 :            :     // Leave string empty if addrLocal invalid (not filled in yet)
#     660                 :      14875 :     CService addrLocalUnlocked = GetAddrLocal();
#     661         [ +  + ]:      14875 :     stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : "";
#     662                 :            : 
#     663                 :      14875 :     X(m_conn_type);
#     664                 :      14875 : }
#     665                 :            : #undef X
#     666                 :            : 
#     667                 :            : bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete)
#     668                 :     130067 : {
#     669                 :     130067 :     complete = false;
#     670                 :     130067 :     const auto time = GetTime<std::chrono::microseconds>();
#     671                 :     130067 :     LOCK(cs_vRecv);
#     672                 :     130067 :     m_last_recv = std::chrono::duration_cast<std::chrono::seconds>(time);
#     673                 :     130067 :     nRecvBytes += msg_bytes.size();
#     674         [ +  + ]:     371104 :     while (msg_bytes.size() > 0) {
#     675                 :            :         // absorb network data
#     676                 :     241041 :         int handled = m_deserializer->Read(msg_bytes);
#     677         [ +  + ]:     241041 :         if (handled < 0) {
#     678                 :            :             // Serious header problem, disconnect from the peer.
#     679                 :          4 :             return false;
#     680                 :          4 :         }
#     681                 :            : 
#     682         [ +  + ]:     241037 :         if (m_deserializer->Complete()) {
#     683                 :            :             // decompose a transport agnostic CNetMessage from the deserializer
#     684                 :     111710 :             bool reject_message{false};
#     685                 :     111710 :             CNetMessage msg = m_deserializer->GetMessage(time, reject_message);
#     686         [ +  + ]:     111710 :             if (reject_message) {
#     687                 :            :                 // Message deserialization failed.  Drop the message but don't disconnect the peer.
#     688                 :            :                 // store the size of the corrupt message
#     689                 :         82 :                 mapRecvBytesPerMsgCmd.at(NET_MESSAGE_COMMAND_OTHER) += msg.m_raw_message_size;
#     690                 :         82 :                 continue;
#     691                 :         82 :             }
#     692                 :            : 
#     693                 :            :             // Store received bytes per message command
#     694                 :            :             // to prevent a memory DOS, only allow valid commands
#     695                 :     111628 :             auto i = mapRecvBytesPerMsgCmd.find(msg.m_type);
#     696         [ -  + ]:     111628 :             if (i == mapRecvBytesPerMsgCmd.end()) {
#     697                 :          0 :                 i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER);
#     698                 :          0 :             }
#     699                 :     111628 :             assert(i != mapRecvBytesPerMsgCmd.end());
#     700                 :          0 :             i->second += msg.m_raw_message_size;
#     701                 :            : 
#     702                 :            :             // push the message to the process queue,
#     703                 :     111628 :             vRecvMsg.push_back(std::move(msg));
#     704                 :            : 
#     705                 :     111628 :             complete = true;
#     706                 :     111628 :         }
#     707                 :     241037 :     }
#     708                 :            : 
#     709                 :     130063 :     return true;
#     710                 :     130067 : }
#     711                 :            : 
#     712                 :            : int V1TransportDeserializer::readHeader(Span<const uint8_t> msg_bytes)
#     713                 :     111715 : {
#     714                 :            :     // copy data to temporary parsing buffer
#     715                 :     111715 :     unsigned int nRemaining = CMessageHeader::HEADER_SIZE - nHdrPos;
#     716                 :     111715 :     unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size());
#     717                 :            : 
#     718                 :     111715 :     memcpy(&hdrbuf[nHdrPos], msg_bytes.data(), nCopy);
#     719                 :     111715 :     nHdrPos += nCopy;
#     720                 :            : 
#     721                 :            :     // if header incomplete, exit
#     722         [ +  + ]:     111715 :     if (nHdrPos < CMessageHeader::HEADER_SIZE)
#     723                 :          1 :         return nCopy;
#     724                 :            : 
#     725                 :            :     // deserialize to CMessageHeader
#     726                 :     111714 :     try {
#     727                 :     111714 :         hdrbuf >> hdr;
#     728                 :     111714 :     }
#     729                 :     111714 :     catch (const std::exception&) {
#     730         [ #  # ]:          0 :         LogPrint(BCLog::NET, "Header error: Unable to deserialize, peer=%d\n", m_node_id);
#     731                 :          0 :         return -1;
#     732                 :          0 :     }
#     733                 :            : 
#     734                 :            :     // Check start string, network magic
#     735         [ +  + ]:     111714 :     if (memcmp(hdr.pchMessageStart, m_chain_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
#     736         [ +  - ]:          3 :         LogPrint(BCLog::NET, "Header error: Wrong MessageStart %s received, peer=%d\n", HexStr(hdr.pchMessageStart), m_node_id);
#     737                 :          3 :         return -1;
#     738                 :          3 :     }
#     739                 :            : 
#     740                 :            :     // reject messages larger than MAX_SIZE or MAX_PROTOCOL_MESSAGE_LENGTH
#     741 [ -  + ][ +  + ]:     111711 :     if (hdr.nMessageSize > MAX_SIZE || hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {
#     742         [ +  - ]:          1 :         LogPrint(BCLog::NET, "Header error: Size too large (%s, %u bytes), peer=%d\n", SanitizeString(hdr.GetCommand()), hdr.nMessageSize, m_node_id);
#     743                 :          1 :         return -1;
#     744                 :          1 :     }
#     745                 :            : 
#     746                 :            :     // switch state to reading message data
#     747                 :     111710 :     in_data = true;
#     748                 :            : 
#     749                 :     111710 :     return nCopy;
#     750                 :     111711 : }
#     751                 :            : 
#     752                 :            : int V1TransportDeserializer::readData(Span<const uint8_t> msg_bytes)
#     753                 :     129326 : {
#     754                 :     129326 :     unsigned int nRemaining = hdr.nMessageSize - nDataPos;
#     755                 :     129326 :     unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size());
#     756                 :            : 
#     757         [ +  + ]:     129326 :     if (vRecv.size() < nDataPos + nCopy) {
#     758                 :            :         // Allocate up to 256 KiB ahead, but never more than the total message size.
#     759                 :     111730 :         vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
#     760                 :     111730 :     }
#     761                 :            : 
#     762                 :     129326 :     hasher.Write(msg_bytes.first(nCopy));
#     763                 :     129326 :     memcpy(&vRecv[nDataPos], msg_bytes.data(), nCopy);
#     764                 :     129326 :     nDataPos += nCopy;
#     765                 :            : 
#     766                 :     129326 :     return nCopy;
#     767                 :     129326 : }
#     768                 :            : 
#     769                 :            : const uint256& V1TransportDeserializer::GetMessageHash() const
#     770                 :     111710 : {
#     771                 :     111710 :     assert(Complete());
#     772         [ +  - ]:     111710 :     if (data_hash.IsNull())
#     773                 :     111710 :         hasher.Finalize(data_hash);
#     774                 :     111710 :     return data_hash;
#     775                 :     111710 : }
#     776                 :            : 
#     777                 :            : CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds time, bool& reject_message)
#     778                 :     111710 : {
#     779                 :            :     // Initialize out parameter
#     780                 :     111710 :     reject_message = false;
#     781                 :            :     // decompose a single CNetMessage from the TransportDeserializer
#     782                 :     111710 :     CNetMessage msg(std::move(vRecv));
#     783                 :            : 
#     784                 :            :     // store command string, time, and sizes
#     785                 :     111710 :     msg.m_type = hdr.GetCommand();
#     786                 :     111710 :     msg.m_time = time;
#     787                 :     111710 :     msg.m_message_size = hdr.nMessageSize;
#     788                 :     111710 :     msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
#     789                 :            : 
#     790                 :     111710 :     uint256 hash = GetMessageHash();
#     791                 :            : 
#     792                 :            :     // We just received a message off the wire, harvest entropy from the time (and the message checksum)
#     793                 :     111710 :     RandAddEvent(ReadLE32(hash.begin()));
#     794                 :            : 
#     795                 :            :     // Check checksum and header command string
#     796         [ +  + ]:     111710 :     if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) {
#     797         [ +  - ]:          1 :         LogPrint(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n",
#     798                 :          1 :                  SanitizeString(msg.m_type), msg.m_message_size,
#     799                 :          1 :                  HexStr(Span{hash}.first(CMessageHeader::CHECKSUM_SIZE)),
#     800                 :          1 :                  HexStr(hdr.pchChecksum),
#     801                 :          1 :                  m_node_id);
#     802                 :          1 :         reject_message = true;
#     803         [ +  + ]:     111709 :     } else if (!hdr.IsCommandValid()) {
#     804         [ +  - ]:         81 :         LogPrint(BCLog::NET, "Header error: Invalid message type (%s, %u bytes), peer=%d\n",
#     805                 :         81 :                  SanitizeString(hdr.GetCommand()), msg.m_message_size, m_node_id);
#     806                 :         81 :         reject_message = true;
#     807                 :         81 :     }
#     808                 :            : 
#     809                 :            :     // Always reset the network deserializer (prepare for the next message)
#     810                 :     111710 :     Reset();
#     811                 :     111710 :     return msg;
#     812                 :     111710 : }
#     813                 :            : 
#     814                 :     113377 : void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) {
#     815                 :            :     // create dbl-sha256 checksum
#     816                 :     113377 :     uint256 hash = Hash(msg.data);
#     817                 :            : 
#     818                 :            :     // create header
#     819                 :     113377 :     CMessageHeader hdr(Params().MessageStart(), msg.m_type.c_str(), msg.data.size());
#     820                 :     113377 :     memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
#     821                 :            : 
#     822                 :            :     // serialize header
#     823                 :     113377 :     header.reserve(CMessageHeader::HEADER_SIZE);
#     824                 :     113377 :     CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, header, 0, hdr};
#     825                 :     113377 : }
#     826                 :            : 
#     827                 :            : size_t CConnman::SocketSendData(CNode& node) const
#     828                 :     113499 : {
#     829                 :     113499 :     auto it = node.vSendMsg.begin();
#     830                 :     113499 :     size_t nSentSize = 0;
#     831                 :            : 
#     832         [ +  + ]:     335425 :     while (it != node.vSendMsg.end()) {
#     833                 :     222191 :         const auto& data = *it;
#     834                 :     222191 :         assert(data.size() > node.nSendOffset);
#     835                 :          0 :         int nBytes = 0;
#     836                 :     222191 :         {
#     837                 :     222191 :             LOCK(node.m_sock_mutex);
#     838         [ +  + ]:     222191 :             if (!node.m_sock) {
#     839                 :         34 :                 break;
#     840                 :         34 :             }
#     841                 :     222157 :             nBytes = node.m_sock->Send(reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
#     842                 :     222157 :         }
#     843         [ +  + ]:     222157 :         if (nBytes > 0) {
#     844                 :     222155 :             node.m_last_send = GetTime<std::chrono::seconds>();
#     845                 :     222155 :             node.nSendBytes += nBytes;
#     846                 :     222155 :             node.nSendOffset += nBytes;
#     847                 :     222155 :             nSentSize += nBytes;
#     848         [ +  + ]:     222155 :             if (node.nSendOffset == data.size()) {
#     849                 :     221926 :                 node.nSendOffset = 0;
#     850                 :     221926 :                 node.nSendSize -= data.size();
#     851                 :     221926 :                 node.fPauseSend = node.nSendSize > nSendBufferMaxSize;
#     852                 :     221926 :                 it++;
#     853                 :     221926 :             } else {
#     854                 :            :                 // could not send full message; stop sending more
#     855                 :        229 :                 break;
#     856                 :        229 :             }
#     857                 :     222155 :         } else {
#     858         [ +  - ]:          2 :             if (nBytes < 0) {
#     859                 :            :                 // error
#     860                 :          2 :                 int nErr = WSAGetLastError();
#     861 [ +  - ][ +  - ]:          2 :                 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) {
#         [ +  - ][ +  - ]
#     862         [ +  - ]:          2 :                     LogPrint(BCLog::NET, "socket send error for peer=%d: %s\n", node.GetId(), NetworkErrorString(nErr));
#     863                 :          2 :                     node.CloseSocketDisconnect();
#     864                 :          2 :                 }
#     865                 :          2 :             }
#     866                 :            :             // couldn't send anything at all
#     867                 :          2 :             break;
#     868                 :          2 :         }
#     869                 :     222157 :     }
#     870                 :            : 
#     871         [ +  + ]:     113499 :     if (it == node.vSendMsg.end()) {
#     872                 :     113234 :         assert(node.nSendOffset == 0);
#     873                 :          0 :         assert(node.nSendSize == 0);
#     874                 :     113234 :     }
#     875                 :          0 :     node.vSendMsg.erase(node.vSendMsg.begin(), it);
#     876                 :     113499 :     return nSentSize;
#     877                 :     113499 : }
#     878                 :            : 
#     879                 :            : static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
#     880                 :    2329532 : {
#     881                 :    2329532 :     return a.m_min_ping_time > b.m_min_ping_time;
#     882                 :    2329532 : }
#     883                 :            : 
#     884                 :            : static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
#     885                 :    1338752 : {
#     886                 :    1338752 :     return a.m_connected > b.m_connected;
#     887                 :    1338752 : }
#     888                 :            : 
#     889                 :    2709598 : static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) {
#     890                 :    2709598 :     return a.nKeyedNetGroup < b.nKeyedNetGroup;
#     891                 :    2709598 : }
#     892                 :            : 
#     893                 :            : static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
#     894                 :    2499706 : {
#     895                 :            :     // There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.
#     896         [ +  + ]:    2499706 :     if (a.m_last_block_time != b.m_last_block_time) return a.m_last_block_time < b.m_last_block_time;
#     897         [ +  + ]:      87949 :     if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;
#     898                 :      55389 :     return a.m_connected > b.m_connected;
#     899                 :      87949 : }
#     900                 :            : 
#     901                 :            : static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
#     902                 :    2189630 : {
#     903                 :            :     // There is a fall-through here because it is common for a node to have more than a few peers that have not yet relayed txn.
#     904         [ +  + ]:    2189630 :     if (a.m_last_tx_time != b.m_last_tx_time) return a.m_last_tx_time < b.m_last_tx_time;
#     905         [ +  + ]:     128065 :     if (a.m_relay_txs != b.m_relay_txs) return b.m_relay_txs;
#     906         [ +  + ]:      74079 :     if (a.fBloomFilter != b.fBloomFilter) return a.fBloomFilter;
#     907                 :      44339 :     return a.m_connected > b.m_connected;
#     908                 :      74079 : }
#     909                 :            : 
#     910                 :            : // Pick out the potential block-relay only peers, and sort them by last block time.
#     911                 :            : static bool CompareNodeBlockRelayOnlyTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
#     912                 :    2299575 : {
#     913         [ +  + ]:    2299575 :     if (a.m_relay_txs != b.m_relay_txs) return a.m_relay_txs;
#     914         [ +  + ]:    1952795 :     if (a.m_last_block_time != b.m_last_block_time) return a.m_last_block_time < b.m_last_block_time;
#     915         [ +  + ]:      51191 :     if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;
#     916                 :      32631 :     return a.m_connected > b.m_connected;
#     917                 :      51191 : }
#     918                 :            : 
#     919                 :            : /**
#     920                 :            :  * Sort eviction candidates by network/localhost and connection uptime.
#     921                 :            :  * Candidates near the beginning are more likely to be evicted, and those
#     922                 :            :  * near the end are more likely to be protected, e.g. less likely to be evicted.
#     923                 :            :  * - First, nodes that are not `is_local` and that do not belong to `network`,
#     924                 :            :  *   sorted by increasing uptime (from most recently connected to connected longer).
#     925                 :            :  * - Then, nodes that are `is_local` or belong to `network`, sorted by increasing uptime.
#     926                 :            :  */
#     927                 :            : struct CompareNodeNetworkTime {
#     928                 :            :     const bool m_is_local;
#     929                 :            :     const Network m_network;
#     930                 :      14602 :     CompareNodeNetworkTime(bool is_local, Network network) : m_is_local(is_local), m_network(network) {}
#     931                 :            :     bool operator()(const NodeEvictionCandidate& a, const NodeEvictionCandidate& b) const
#     932                 :    8660118 :     {
#     933 [ +  + ][ +  + ]:    8660118 :         if (m_is_local && a.m_is_local != b.m_is_local) return b.m_is_local;
#     934         [ +  + ]:    8389456 :         if ((a.m_network == m_network) != (b.m_network == m_network)) return b.m_network == m_network;
#     935                 :    7404410 :         return a.m_connected > b.m_connected;
#     936                 :    8389456 :     };
#     937                 :            : };
#     938                 :            : 
#     939                 :            : //! Sort an array by the specified comparator, then erase the last K elements where predicate is true.
#     940                 :            : template <typename T, typename Comparator>
#     941                 :            : static void EraseLastKElements(
#     942                 :            :     std::vector<T>& elements, Comparator comparator, size_t k,
#     943                 :     121854 :     std::function<bool(const NodeEvictionCandidate&)> predicate = [](const NodeEvictionCandidate& n) { return true; })
#     944                 :      33776 : {
#     945                 :      33776 :     std::sort(elements.begin(), elements.end(), comparator);
#     946                 :      33776 :     size_t eraseSize = std::min(k, elements.size());
#     947                 :      33776 :     elements.erase(std::remove_if(elements.end() - eraseSize, elements.end(), predicate), elements.end());
#     948                 :      33776 : }
#     949                 :            : 
#     950                 :            : void ProtectEvictionCandidatesByRatio(std::vector<NodeEvictionCandidate>& eviction_candidates)
#     951                 :       3249 : {
#     952                 :            :     // Protect the half of the remaining nodes which have been connected the longest.
#     953                 :            :     // This replicates the non-eviction implicit behavior, and precludes attacks that start later.
#     954                 :            :     // To favorise the diversity of our peer connections, reserve up to half of these protected
#     955                 :            :     // spots for Tor/onion, localhost, I2P, and CJDNS peers, even if they're not longest uptime
#     956                 :            :     // overall. This helps protect these higher-latency peers that tend to be otherwise
#     957                 :            :     // disadvantaged under our eviction criteria.
#     958                 :       3249 :     const size_t initial_size = eviction_candidates.size();
#     959                 :       3249 :     const size_t total_protect_size{initial_size / 2};
#     960                 :            : 
#     961                 :            :     // Disadvantaged networks to protect. In the case of equal counts, earlier array members
#     962                 :            :     // have the first opportunity to recover unused slots from the previous iteration.
#     963                 :       3249 :     struct Net { bool is_local; Network id; size_t count; };
#     964                 :       3249 :     std::array<Net, 4> networks{
#     965                 :       3249 :         {{false, NET_CJDNS, 0}, {false, NET_I2P, 0}, {/*localhost=*/true, NET_MAX, 0}, {false, NET_ONION, 0}}};
#     966                 :            : 
#     967                 :            :     // Count and store the number of eviction candidates per network.
#     968         [ +  + ]:      12996 :     for (Net& n : networks) {
#     969                 :      12996 :         n.count = std::count_if(eviction_candidates.cbegin(), eviction_candidates.cend(),
#     970                 :     980188 :                                 [&n](const NodeEvictionCandidate& c) {
#     971         [ +  + ]:     980188 :                                     return n.is_local ? c.m_is_local : c.m_network == n.id;
#     972                 :     980188 :                                 });
#     973                 :      12996 :     }
#     974                 :            :     // Sort `networks` by ascending candidate count, to give networks having fewer candidates
#     975                 :            :     // the first opportunity to recover unused protected slots from the previous iteration.
#     976                 :      14380 :     std::stable_sort(networks.begin(), networks.end(), [](Net a, Net b) { return a.count < b.count; });
#     977                 :            : 
#     978                 :            :     // Protect up to 25% of the eviction candidates by disadvantaged network.
#     979                 :       3249 :     const size_t max_protect_by_network{total_protect_size / 2};
#     980                 :       3249 :     size_t num_protected{0};
#     981                 :            : 
#     982         [ +  + ]:       8037 :     while (num_protected < max_protect_by_network) {
#     983                 :            :         // Count the number of disadvantaged networks from which we have peers to protect.
#     984                 :      19168 :         auto num_networks = std::count_if(networks.begin(), networks.end(), [](const Net& n) { return n.count; });
#     985         [ +  + ]:       4792 :         if (num_networks == 0) {
#     986                 :          4 :             break;
#     987                 :          4 :         }
#     988                 :       4788 :         const size_t disadvantaged_to_protect{max_protect_by_network - num_protected};
#     989                 :       4788 :         const size_t protect_per_network{std::max(disadvantaged_to_protect / num_networks, static_cast<size_t>(1))};
#     990                 :            :         // Early exit flag if there are no remaining candidates by disadvantaged network.
#     991                 :       4788 :         bool protected_at_least_one{false};
#     992                 :            : 
#     993         [ +  + ]:      15164 :         for (Net& n : networks) {
#     994         [ +  + ]:      15164 :             if (n.count == 0) continue;
#     995                 :      14602 :             const size_t before = eviction_candidates.size();
#     996                 :      14602 :             EraseLastKElements(eviction_candidates, CompareNodeNetworkTime(n.is_local, n.id),
#     997                 :      60290 :                                protect_per_network, [&n](const NodeEvictionCandidate& c) {
#     998         [ +  + ]:      60290 :                                    return n.is_local ? c.m_is_local : c.m_network == n.id;
#     999                 :      60290 :                                });
#    1000                 :      14602 :             const size_t after = eviction_candidates.size();
#    1001         [ +  - ]:      14602 :             if (before > after) {
#    1002                 :      14602 :                 protected_at_least_one = true;
#    1003                 :      14602 :                 const size_t delta{before - after};
#    1004                 :      14602 :                 num_protected += delta;
#    1005         [ +  + ]:      14602 :                 if (num_protected >= max_protect_by_network) {
#    1006                 :       2826 :                     break;
#    1007                 :       2826 :                 }
#    1008                 :      11776 :                 n.count -= delta;
#    1009                 :      11776 :             }
#    1010                 :      14602 :         }
#    1011         [ -  + ]:       4788 :         if (!protected_at_least_one) {
#    1012                 :          0 :             break;
#    1013                 :          0 :         }
#    1014                 :       4788 :     }
#    1015                 :            : 
#    1016                 :            :     // Calculate how many we removed, and update our total number of peers that
#    1017                 :            :     // we want to protect based on uptime accordingly.
#    1018                 :       3249 :     assert(num_protected == initial_size - eviction_candidates.size());
#    1019                 :          0 :     const size_t remaining_to_protect{total_protect_size - num_protected};
#    1020                 :       3249 :     EraseLastKElements(eviction_candidates, ReverseCompareNodeTimeConnected, remaining_to_protect);
#    1021                 :       3249 : }
#    1022                 :            : 
#    1023                 :            : [[nodiscard]] std::optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates)
#    1024                 :       3185 : {
#    1025                 :            :     // Protect connections with certain characteristics
#    1026                 :            : 
#    1027                 :            :     // Deterministically select 4 peers to protect by netgroup.
#    1028                 :            :     // An attacker cannot predict which netgroups will be protected
#    1029                 :       3185 :     EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4);
#    1030                 :            :     // Protect the 8 nodes with the lowest minimum ping time.
#    1031                 :            :     // An attacker cannot manipulate this metric without physically moving nodes closer to the target.
#    1032                 :       3185 :     EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8);
#    1033                 :            :     // Protect 4 nodes that most recently sent us novel transactions accepted into our mempool.
#    1034                 :            :     // An attacker cannot manipulate this metric without performing useful work.
#    1035                 :       3185 :     EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
#    1036                 :            :     // Protect up to 8 non-tx-relay peers that have sent us novel blocks.
#    1037                 :       3185 :     EraseLastKElements(vEvictionCandidates, CompareNodeBlockRelayOnlyTime, 8,
#    1038 [ +  + ][ +  + ]:      22865 :                        [](const NodeEvictionCandidate& n) { return !n.m_relay_txs && n.fRelevantServices; });
#    1039                 :            : 
#    1040                 :            :     // Protect 4 nodes that most recently sent us novel blocks.
#    1041                 :            :     // An attacker cannot manipulate this metric without performing useful work.
#    1042                 :       3185 :     EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4);
#    1043                 :            : 
#    1044                 :            :     // Protect some of the remaining eviction candidates by ratios of desirable
#    1045                 :            :     // or disadvantaged characteristics.
#    1046                 :       3185 :     ProtectEvictionCandidatesByRatio(vEvictionCandidates);
#    1047                 :            : 
#    1048         [ +  + ]:       3185 :     if (vEvictionCandidates.empty()) return std::nullopt;
#    1049                 :            : 
#    1050                 :            :     // If any remaining peers are preferred for eviction consider only them.
#    1051                 :            :     // This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
#    1052                 :            :     //  then we probably don't want to evict it no matter what.
#    1053         [ +  + ]:       5437 :     if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](NodeEvictionCandidate const &n){return n.prefer_evict;})) {
#    1054                 :       2786 :         vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(),
#    1055                 :     122746 :                                   [](NodeEvictionCandidate const &n){return !n.prefer_evict;}),vEvictionCandidates.end());
#    1056                 :       2786 :     }
#    1057                 :            : 
#    1058                 :            :     // Identify the network group with the most connections and youngest member.
#    1059                 :            :     // (vEvictionCandidates is already sorted by reverse connect time)
#    1060                 :       2821 :     uint64_t naMostConnections;
#    1061                 :       2821 :     unsigned int nMostConnections = 0;
#    1062                 :       2821 :     std::chrono::seconds nMostConnectionsTime{0};
#    1063                 :       2821 :     std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
#    1064         [ +  + ]:      61429 :     for (const NodeEvictionCandidate &node : vEvictionCandidates) {
#    1065                 :      61429 :         std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup];
#    1066                 :      61429 :         group.push_back(node);
#    1067                 :      61429 :         const auto grouptime{group[0].m_connected};
#    1068                 :            : 
#    1069 [ +  + ][ +  + ]:      61429 :         if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
#                 [ +  + ]
#    1070                 :       5483 :             nMostConnections = group.size();
#    1071                 :       5483 :             nMostConnectionsTime = grouptime;
#    1072                 :       5483 :             naMostConnections = node.nKeyedNetGroup;
#    1073                 :       5483 :         }
#    1074                 :      61429 :     }
#    1075                 :            : 
#    1076                 :            :     // Reduce to the network group with the most connections
#    1077                 :       2821 :     vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);
#    1078                 :            : 
#    1079                 :            :     // Disconnect from the network group with the most connections
#    1080                 :       2821 :     return vEvictionCandidates.front().id;
#    1081                 :       3185 : }
#    1082                 :            : 
#    1083                 :            : /** Try to find a connection to evict when the node is full.
#    1084                 :            :  *  Extreme care must be taken to avoid opening the node to attacker
#    1085                 :            :  *   triggered network partitioning.
#    1086                 :            :  *  The strategy used here is to protect a small number of peers
#    1087                 :            :  *   for each of several distinct characteristics which are difficult
#    1088                 :            :  *   to forge.  In order to partition a node the attacker must be
#    1089                 :            :  *   simultaneously better at all of them than honest peers.
#    1090                 :            :  */
#    1091                 :            : bool CConnman::AttemptToEvictConnection()
#    1092                 :          1 : {
#    1093                 :          1 :     std::vector<NodeEvictionCandidate> vEvictionCandidates;
#    1094                 :          1 :     {
#    1095                 :            : 
#    1096                 :          1 :         LOCK(m_nodes_mutex);
#    1097         [ +  + ]:         21 :         for (const CNode* node : m_nodes) {
#    1098         [ -  + ]:         21 :             if (node->HasPermission(NetPermissionFlags::NoBan))
#    1099                 :          0 :                 continue;
#    1100         [ -  + ]:         21 :             if (!node->IsInboundConn())
#    1101                 :          0 :                 continue;
#    1102         [ -  + ]:         21 :             if (node->fDisconnect)
#    1103                 :          0 :                 continue;
#    1104                 :         21 :             NodeEvictionCandidate candidate = {node->GetId(), node->m_connected, node->m_min_ping_time,
#    1105                 :         21 :                                                node->m_last_block_time, node->m_last_tx_time,
#    1106                 :         21 :                                                HasAllDesirableServiceFlags(node->nServices),
#    1107                 :         21 :                                                node->m_relays_txs.load(), node->m_bloom_filter_loaded.load(),
#    1108                 :         21 :                                                node->nKeyedNetGroup, node->m_prefer_evict, node->addr.IsLocal(),
#    1109                 :         21 :                                                node->ConnectedThroughNetwork()};
#    1110                 :         21 :             vEvictionCandidates.push_back(candidate);
#    1111                 :         21 :         }
#    1112                 :          1 :     }
#    1113                 :          1 :     const std::optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates));
#    1114         [ -  + ]:          1 :     if (!node_id_to_evict) {
#    1115                 :          0 :         return false;
#    1116                 :          0 :     }
#    1117                 :          1 :     LOCK(m_nodes_mutex);
#    1118         [ +  - ]:          8 :     for (CNode* pnode : m_nodes) {
#    1119         [ +  + ]:          8 :         if (pnode->GetId() == *node_id_to_evict) {
#    1120         [ +  - ]:          1 :             LogPrint(BCLog::NET, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId());
#    1121                 :          1 :             pnode->fDisconnect = true;
#    1122                 :          1 :             return true;
#    1123                 :          1 :         }
#    1124                 :          8 :     }
#    1125                 :          0 :     return false;
#    1126                 :          1 : }
#    1127                 :            : 
#    1128                 :        679 : void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
#    1129                 :        679 :     struct sockaddr_storage sockaddr;
#    1130                 :        679 :     socklen_t len = sizeof(sockaddr);
#    1131                 :        679 :     auto sock = hListenSocket.sock->Accept((struct sockaddr*)&sockaddr, &len);
#    1132                 :        679 :     CAddress addr;
#    1133                 :            : 
#    1134         [ -  + ]:        679 :     if (!sock) {
#    1135                 :          0 :         const int nErr = WSAGetLastError();
#    1136         [ #  # ]:          0 :         if (nErr != WSAEWOULDBLOCK) {
#    1137                 :          0 :             LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
#    1138                 :          0 :         }
#    1139                 :          0 :         return;
#    1140                 :          0 :     }
#    1141                 :            : 
#    1142         [ -  + ]:        679 :     if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
#    1143                 :          0 :         LogPrintf("Warning: Unknown socket family\n");
#    1144                 :        679 :     } else {
#    1145                 :        679 :         addr = CAddress{MaybeFlipIPv6toCJDNS(addr), NODE_NONE};
#    1146                 :        679 :     }
#    1147                 :            : 
#    1148                 :        679 :     const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(sock->Get())), NODE_NONE};
#    1149                 :            : 
#    1150                 :        679 :     NetPermissionFlags permissionFlags = NetPermissionFlags::None;
#    1151                 :        679 :     hListenSocket.AddSocketPermissionFlags(permissionFlags);
#    1152                 :            : 
#    1153                 :        679 :     CreateNodeFromAcceptedSocket(std::move(sock), permissionFlags, addr_bind, addr);
#    1154                 :        679 : }
#    1155                 :            : 
#    1156                 :            : void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
#    1157                 :            :                                             NetPermissionFlags permissionFlags,
#    1158                 :            :                                             const CAddress& addr_bind,
#    1159                 :            :                                             const CAddress& addr)
#    1160                 :        679 : {
#    1161                 :        679 :     int nInbound = 0;
#    1162                 :        679 :     int nMaxInbound = nMaxConnections - m_max_outbound;
#    1163                 :            : 
#    1164                 :        679 :     AddWhitelistPermissionFlags(permissionFlags, addr);
#    1165         [ +  + ]:        679 :     if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::Implicit)) {
#    1166                 :          6 :         NetPermissions::ClearFlag(permissionFlags, NetPermissionFlags::Implicit);
#    1167         [ +  + ]:          6 :         if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::ForceRelay);
#    1168         [ +  + ]:          6 :         if (gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::Relay);
#    1169                 :          6 :         NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::Mempool);
#    1170                 :          6 :         NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::NoBan);
#    1171                 :          6 :     }
#    1172                 :            : 
#    1173                 :        679 :     {
#    1174                 :        679 :         LOCK(m_nodes_mutex);
#    1175         [ +  + ]:        941 :         for (const CNode* pnode : m_nodes) {
#    1176         [ +  + ]:        941 :             if (pnode->IsInboundConn()) nInbound++;
#    1177                 :        941 :         }
#    1178                 :        679 :     }
#    1179                 :            : 
#    1180         [ -  + ]:        679 :     if (!fNetworkActive) {
#    1181         [ #  # ]:          0 :         LogPrint(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToString());
#    1182                 :          0 :         return;
#    1183                 :          0 :     }
#    1184                 :            : 
#    1185         [ -  + ]:        679 :     if (!IsSelectableSocket(sock->Get()))
#    1186                 :          0 :     {
#    1187                 :          0 :         LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString());
#    1188                 :          0 :         return;
#    1189                 :          0 :     }
#    1190                 :            : 
#    1191                 :            :     // According to the internet TCP_NODELAY is not carried into accepted sockets
#    1192                 :            :     // on all platforms.  Set it again here just to be sure.
#    1193                 :        679 :     SetSocketNoDelay(sock->Get());
#    1194                 :            : 
#    1195                 :            :     // Don't accept connections from banned peers.
#    1196 [ +  - ][ +  + ]:        679 :     bool banned = m_banman && m_banman->IsBanned(addr);
#    1197 [ +  + ][ +  + ]:        679 :     if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::NoBan) && banned)
#    1198                 :          1 :     {
#    1199         [ +  - ]:          1 :         LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
#    1200                 :          1 :         return;
#    1201                 :          1 :     }
#    1202                 :            : 
#    1203                 :            :     // Only accept connections from discouraged peers if our inbound slots aren't (almost) full.
#    1204 [ +  - ][ -  + ]:        678 :     bool discouraged = m_banman && m_banman->IsDiscouraged(addr);
#    1205 [ +  + ][ +  + ]:        678 :     if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::NoBan) && nInbound + 1 >= nMaxInbound && discouraged)
#                 [ -  + ]
#    1206                 :          0 :     {
#    1207         [ #  # ]:          0 :         LogPrint(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToString());
#    1208                 :          0 :         return;
#    1209                 :          0 :     }
#    1210                 :            : 
#    1211         [ +  + ]:        678 :     if (nInbound >= nMaxInbound)
#    1212                 :          1 :     {
#    1213         [ -  + ]:          1 :         if (!AttemptToEvictConnection()) {
#    1214                 :            :             // No connection to evict, disconnect the new connection
#    1215         [ #  # ]:          0 :             LogPrint(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n");
#    1216                 :          0 :             return;
#    1217                 :          0 :         }
#    1218                 :          1 :     }
#    1219                 :            : 
#    1220                 :        678 :     NodeId id = GetNewNodeId();
#    1221                 :        678 :     uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
#    1222                 :            : 
#    1223                 :        678 :     ServiceFlags nodeServices = nLocalServices;
#    1224         [ +  + ]:        678 :     if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::BloomFilter)) {
#    1225                 :          2 :         nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM);
#    1226                 :          2 :     }
#    1227                 :            : 
#    1228                 :        678 :     const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
#    1229                 :        678 :     CNode* pnode = new CNode(id,
#    1230                 :        678 :                              nodeServices,
#    1231                 :        678 :                              std::move(sock),
#    1232                 :        678 :                              addr,
#    1233                 :        678 :                              CalculateKeyedNetGroup(addr),
#    1234                 :        678 :                              nonce,
#    1235                 :        678 :                              addr_bind,
#    1236                 :        678 :                              /*addrNameIn=*/"",
#    1237                 :        678 :                              ConnectionType::INBOUND,
#    1238                 :        678 :                              inbound_onion);
#    1239                 :        678 :     pnode->AddRef();
#    1240                 :        678 :     pnode->m_permissionFlags = permissionFlags;
#    1241                 :        678 :     pnode->m_prefer_evict = discouraged;
#    1242                 :        678 :     m_msgproc->InitializeNode(pnode);
#    1243                 :            : 
#    1244         [ +  - ]:        678 :     LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
#    1245                 :            : 
#    1246                 :        678 :     {
#    1247                 :        678 :         LOCK(m_nodes_mutex);
#    1248                 :        678 :         m_nodes.push_back(pnode);
#    1249                 :        678 :     }
#    1250                 :            : 
#    1251                 :            :     // We received a new connection, harvest entropy from the time (and our peer count)
#    1252                 :        678 :     RandAddEvent((uint32_t)id);
#    1253                 :        678 : }
#    1254                 :            : 
#    1255                 :            : bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
#    1256                 :         55 : {
#    1257                 :         55 :     std::optional<int> max_connections;
#    1258         [ -  + ]:         55 :     switch (conn_type) {
#    1259         [ -  + ]:          0 :     case ConnectionType::INBOUND:
#    1260         [ -  + ]:          0 :     case ConnectionType::MANUAL:
#    1261                 :          0 :         return false;
#    1262         [ +  + ]:         34 :     case ConnectionType::OUTBOUND_FULL_RELAY:
#    1263                 :         34 :         max_connections = m_max_outbound_full_relay;
#    1264                 :         34 :         break;
#    1265         [ +  + ]:         18 :     case ConnectionType::BLOCK_RELAY:
#    1266                 :         18 :         max_connections = m_max_outbound_block_relay;
#    1267                 :         18 :         break;
#    1268                 :            :     // no limit for ADDR_FETCH because -seednode has no limit either
#    1269         [ +  + ]:          2 :     case ConnectionType::ADDR_FETCH:
#    1270                 :          2 :         break;
#    1271                 :            :     // no limit for FEELER connections since they're short-lived
#    1272         [ +  + ]:          1 :     case ConnectionType::FEELER:
#    1273                 :          1 :         break;
#    1274                 :         55 :     } // no default case, so the compiler can warn about missing cases
#    1275                 :            : 
#    1276                 :            :     // Count existing connections
#    1277                 :         55 :     int existing_connections = WITH_LOCK(m_nodes_mutex,
#    1278                 :         55 :                                          return std::count_if(m_nodes.begin(), m_nodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
#    1279                 :            : 
#    1280                 :            :     // Max connections of specified type already exist
#    1281 [ +  + ][ -  + ]:         55 :     if (max_connections != std::nullopt && existing_connections >= max_connections) return false;
#    1282                 :            : 
#    1283                 :            :     // Max total outbound connections already exist
#    1284                 :         55 :     CSemaphoreGrant grant(*semOutbound, true);
#    1285         [ -  + ]:         55 :     if (!grant) return false;
#    1286                 :            : 
#    1287                 :         55 :     OpenNetworkConnection(CAddress(), false, &grant, address.c_str(), conn_type);
#    1288                 :         55 :     return true;
#    1289                 :         55 : }
#    1290                 :            : 
#    1291                 :            : void CConnman::DisconnectNodes()
#    1292                 :     316051 : {
#    1293                 :     316051 :     {
#    1294                 :     316051 :         LOCK(m_nodes_mutex);
#    1295                 :            : 
#    1296         [ +  + ]:     316051 :         if (!fNetworkActive) {
#    1297                 :            :             // Disconnect any connected nodes
#    1298         [ +  + ]:         11 :             for (CNode* pnode : m_nodes) {
#    1299         [ +  - ]:          3 :                 if (!pnode->fDisconnect) {
#    1300         [ +  - ]:          3 :                     LogPrint(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId());
#    1301                 :          3 :                     pnode->fDisconnect = true;
#    1302                 :          3 :                 }
#    1303                 :          3 :             }
#    1304                 :         11 :         }
#    1305                 :            : 
#    1306                 :            :         // Disconnect unused nodes
#    1307                 :     316051 :         std::vector<CNode*> nodes_copy = m_nodes;
#    1308         [ +  + ]:     316051 :         for (CNode* pnode : nodes_copy)
#    1309                 :     498773 :         {
#    1310         [ +  + ]:     498773 :             if (pnode->fDisconnect)
#    1311                 :        416 :             {
#    1312                 :            :                 // remove from m_nodes
#    1313                 :        416 :                 m_nodes.erase(remove(m_nodes.begin(), m_nodes.end(), pnode), m_nodes.end());
#    1314                 :            : 
#    1315                 :            :                 // release outbound grant (if any)
#    1316                 :        416 :                 pnode->grantOutbound.Release();
#    1317                 :            : 
#    1318                 :            :                 // close socket and cleanup
#    1319                 :        416 :                 pnode->CloseSocketDisconnect();
#    1320                 :            : 
#    1321                 :            :                 // hold in disconnected pool until all refs are released
#    1322                 :        416 :                 pnode->Release();
#    1323                 :        416 :                 m_nodes_disconnected.push_back(pnode);
#    1324                 :        416 :             }
#    1325                 :     498773 :         }
#    1326                 :     316051 :     }
#    1327                 :     316051 :     {
#    1328                 :            :         // Delete disconnected nodes
#    1329                 :     316051 :         std::list<CNode*> nodes_disconnected_copy = m_nodes_disconnected;
#    1330         [ +  + ]:     316051 :         for (CNode* pnode : nodes_disconnected_copy)
#    1331                 :        424 :         {
#    1332                 :            :             // Destroy the object only after other threads have stopped using it.
#    1333         [ +  + ]:        424 :             if (pnode->GetRefCount() <= 0) {
#    1334                 :        416 :                 m_nodes_disconnected.remove(pnode);
#    1335                 :        416 :                 DeleteNode(pnode);
#    1336                 :        416 :             }
#    1337                 :        424 :         }
#    1338                 :     316051 :     }
#    1339                 :     316051 : }
#    1340                 :            : 
#    1341                 :            : void CConnman::NotifyNumConnectionsChanged()
#    1342                 :     316051 : {
#    1343                 :     316051 :     size_t nodes_size;
#    1344                 :     316051 :     {
#    1345                 :     316051 :         LOCK(m_nodes_mutex);
#    1346                 :     316051 :         nodes_size = m_nodes.size();
#    1347                 :     316051 :     }
#    1348         [ +  + ]:     316051 :     if(nodes_size != nPrevNodeCount) {
#    1349                 :       1470 :         nPrevNodeCount = nodes_size;
#    1350         [ +  - ]:       1470 :         if (m_client_interface) {
#    1351                 :       1470 :             m_client_interface->NotifyNumConnectionsChanged(nodes_size);
#    1352                 :       1470 :         }
#    1353                 :       1470 :     }
#    1354                 :     316051 : }
#    1355                 :            : 
#    1356                 :            : bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const
#    1357                 :     814324 : {
#    1358                 :     814324 :     return node.m_connected + m_peer_connect_timeout < now;
#    1359                 :     814324 : }
#    1360                 :            : 
#    1361                 :            : bool CConnman::InactivityCheck(const CNode& node) const
#    1362                 :     497667 : {
#    1363                 :            :     // Tests that see disconnects after using mocktime can start nodes with a
#    1364                 :            :     // large timeout. For example, -peertimeout=999999999.
#    1365                 :     497667 :     const auto now{GetTime<std::chrono::seconds>()};
#    1366                 :     497667 :     const auto last_send{node.m_last_send.load()};
#    1367                 :     497667 :     const auto last_recv{node.m_last_recv.load()};
#    1368                 :            : 
#    1369         [ +  + ]:     497667 :     if (!ShouldRunInactivityChecks(node, now)) return false;
#    1370                 :            : 
#    1371 [ +  + ][ +  + ]:         33 :     if (last_recv.count() == 0 || last_send.count() == 0) {
#    1372         [ +  - ]:          3 :         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());
#    1373                 :          3 :         return true;
#    1374                 :          3 :     }
#    1375                 :            : 
#    1376         [ -  + ]:         30 :     if (now > last_send + TIMEOUT_INTERVAL) {
#    1377         [ #  # ]:          0 :         LogPrint(BCLog::NET, "socket sending timeout: %is peer=%d\n", count_seconds(now - last_send), node.GetId());
#    1378                 :          0 :         return true;
#    1379                 :          0 :     }
#    1380                 :            : 
#    1381         [ -  + ]:         30 :     if (now > last_recv + TIMEOUT_INTERVAL) {
#    1382         [ #  # ]:          0 :         LogPrint(BCLog::NET, "socket receive timeout: %is peer=%d\n", count_seconds(now - last_recv), node.GetId());
#    1383                 :          0 :         return true;
#    1384                 :          0 :     }
#    1385                 :            : 
#    1386         [ +  + ]:         30 :     if (!node.fSuccessfullyConnected) {
#    1387         [ +  - ]:          3 :         LogPrint(BCLog::NET, "version handshake timeout peer=%d\n", node.GetId());
#    1388                 :          3 :         return true;
#    1389                 :          3 :     }
#    1390                 :            : 
#    1391                 :         27 :     return false;
#    1392                 :         30 : }
#    1393                 :            : 
#    1394                 :            : bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
#    1395                 :            :                                  std::set<SOCKET>& recv_set,
#    1396                 :            :                                  std::set<SOCKET>& send_set,
#    1397                 :            :                                  std::set<SOCKET>& error_set)
#    1398                 :     316051 : {
#    1399         [ +  + ]:     372778 :     for (const ListenSocket& hListenSocket : vhListenSocket) {
#    1400                 :     372778 :         recv_set.insert(hListenSocket.sock->Get());
#    1401                 :     372778 :     }
#    1402                 :            : 
#    1403         [ +  + ]:     498358 :     for (CNode* pnode : nodes) {
#    1404                 :            :         // Implement the following logic:
#    1405                 :            :         // * If there is data to send, select() for sending data. As this only
#    1406                 :            :         //   happens when optimistic write failed, we choose to first drain the
#    1407                 :            :         //   write buffer in this case before receiving more. This avoids
#    1408                 :            :         //   needlessly queueing received data, if the remote peer is not themselves
#    1409                 :            :         //   receiving data. This means properly utilizing TCP flow control signalling.
#    1410                 :            :         // * Otherwise, if there is space left in the receive buffer, select() for
#    1411                 :            :         //   receiving data.
#    1412                 :            :         // * Hand off all complete messages to the processor, to be handled without
#    1413                 :            :         //   blocking here.
#    1414                 :            : 
#    1415                 :     498358 :         bool select_recv = !pnode->fPauseRecv;
#    1416                 :     498358 :         bool select_send;
#    1417                 :     498358 :         {
#    1418                 :     498358 :             LOCK(pnode->cs_vSend);
#    1419                 :     498358 :             select_send = !pnode->vSendMsg.empty();
#    1420                 :     498358 :         }
#    1421                 :            : 
#    1422                 :     498358 :         LOCK(pnode->m_sock_mutex);
#    1423         [ -  + ]:     498358 :         if (!pnode->m_sock) {
#    1424                 :          0 :             continue;
#    1425                 :          0 :         }
#    1426                 :            : 
#    1427                 :     498358 :         error_set.insert(pnode->m_sock->Get());
#    1428         [ +  + ]:     498358 :         if (select_send) {
#    1429                 :        232 :             send_set.insert(pnode->m_sock->Get());
#    1430                 :        232 :             continue;
#    1431                 :        232 :         }
#    1432         [ +  - ]:     498126 :         if (select_recv) {
#    1433                 :     498126 :             recv_set.insert(pnode->m_sock->Get());
#    1434                 :     498126 :         }
#    1435                 :     498126 :     }
#    1436                 :            : 
#    1437 [ +  + ][ -  + ]:     316051 :     return !recv_set.empty() || !send_set.empty() || !error_set.empty();
#                 [ -  + ]
#    1438                 :     316051 : }
#    1439                 :            : 
#    1440                 :            : #ifdef USE_POLL
#    1441                 :            : void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
#    1442                 :            :                             std::set<SOCKET>& recv_set,
#    1443                 :            :                             std::set<SOCKET>& send_set,
#    1444                 :            :                             std::set<SOCKET>& error_set)
#    1445                 :            : {
#    1446                 :            :     std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
#    1447                 :            :     if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
#    1448                 :            :         interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
#    1449                 :            :         return;
#    1450                 :            :     }
#    1451                 :            : 
#    1452                 :            :     std::unordered_map<SOCKET, struct pollfd> pollfds;
#    1453                 :            :     for (SOCKET socket_id : recv_select_set) {
#    1454                 :            :         pollfds[socket_id].fd = socket_id;
#    1455                 :            :         pollfds[socket_id].events |= POLLIN;
#    1456                 :            :     }
#    1457                 :            : 
#    1458                 :            :     for (SOCKET socket_id : send_select_set) {
#    1459                 :            :         pollfds[socket_id].fd = socket_id;
#    1460                 :            :         pollfds[socket_id].events |= POLLOUT;
#    1461                 :            :     }
#    1462                 :            : 
#    1463                 :            :     for (SOCKET socket_id : error_select_set) {
#    1464                 :            :         pollfds[socket_id].fd = socket_id;
#    1465                 :            :         // These flags are ignored, but we set them for clarity
#    1466                 :            :         pollfds[socket_id].events |= POLLERR|POLLHUP;
#    1467                 :            :     }
#    1468                 :            : 
#    1469                 :            :     std::vector<struct pollfd> vpollfds;
#    1470                 :            :     vpollfds.reserve(pollfds.size());
#    1471                 :            :     for (auto it : pollfds) {
#    1472                 :            :         vpollfds.push_back(std::move(it.second));
#    1473                 :            :     }
#    1474                 :            : 
#    1475                 :            :     if (poll(vpollfds.data(), vpollfds.size(), SELECT_TIMEOUT_MILLISECONDS) < 0) return;
#    1476                 :            : 
#    1477                 :            :     if (interruptNet) return;
#    1478                 :            : 
#    1479                 :            :     for (struct pollfd pollfd_entry : vpollfds) {
#    1480                 :            :         if (pollfd_entry.revents & POLLIN)            recv_set.insert(pollfd_entry.fd);
#    1481                 :            :         if (pollfd_entry.revents & POLLOUT)           send_set.insert(pollfd_entry.fd);
#    1482                 :            :         if (pollfd_entry.revents & (POLLERR|POLLHUP)) error_set.insert(pollfd_entry.fd);
#    1483                 :            :     }
#    1484                 :            : }
#    1485                 :            : #else
#    1486                 :            : void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
#    1487                 :            :                             std::set<SOCKET>& recv_set,
#    1488                 :            :                             std::set<SOCKET>& send_set,
#    1489                 :            :                             std::set<SOCKET>& error_set)
#    1490                 :     316051 : {
#    1491                 :     316051 :     std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
#    1492         [ +  + ]:     316051 :     if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
#    1493                 :          8 :         interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
#    1494                 :          8 :         return;
#    1495                 :          8 :     }
#    1496                 :            : 
#    1497                 :            :     //
#    1498                 :            :     // Find which sockets have data to receive
#    1499                 :            :     //
#    1500                 :     316043 :     struct timeval timeout;
#    1501                 :     316043 :     timeout.tv_sec  = 0;
#    1502                 :     316043 :     timeout.tv_usec = SELECT_TIMEOUT_MILLISECONDS * 1000; // frequency to poll pnode->vSend
#    1503                 :            : 
#    1504                 :     316043 :     fd_set fdsetRecv;
#    1505                 :     316043 :     fd_set fdsetSend;
#    1506                 :     316043 :     fd_set fdsetError;
#    1507                 :     316043 :     FD_ZERO(&fdsetRecv);
#    1508                 :     316043 :     FD_ZERO(&fdsetSend);
#    1509                 :     316043 :     FD_ZERO(&fdsetError);
#    1510                 :     316043 :     SOCKET hSocketMax = 0;
#    1511                 :            : 
#    1512         [ +  + ]:     870904 :     for (SOCKET hSocket : recv_select_set) {
#    1513                 :     870904 :         FD_SET(hSocket, &fdsetRecv);
#    1514                 :     870904 :         hSocketMax = std::max(hSocketMax, hSocket);
#    1515                 :     870904 :     }
#    1516                 :            : 
#    1517         [ +  + ]:     316043 :     for (SOCKET hSocket : send_select_set) {
#    1518                 :        232 :         FD_SET(hSocket, &fdsetSend);
#    1519                 :        232 :         hSocketMax = std::max(hSocketMax, hSocket);
#    1520                 :        232 :     }
#    1521                 :            : 
#    1522         [ +  + ]:     498358 :     for (SOCKET hSocket : error_select_set) {
#    1523                 :     498358 :         FD_SET(hSocket, &fdsetError);
#    1524                 :     498358 :         hSocketMax = std::max(hSocketMax, hSocket);
#    1525                 :     498358 :     }
#    1526                 :            : 
#    1527                 :     316043 :     int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
#    1528                 :            : 
#    1529         [ +  + ]:     316043 :     if (interruptNet)
#    1530                 :        717 :         return;
#    1531                 :            : 
#    1532         [ -  + ]:     315326 :     if (nSelect == SOCKET_ERROR)
#    1533                 :          0 :     {
#    1534                 :          0 :         int nErr = WSAGetLastError();
#    1535                 :          0 :         LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
#    1536         [ #  # ]:          0 :         for (unsigned int i = 0; i <= hSocketMax; i++)
#    1537                 :          0 :             FD_SET(i, &fdsetRecv);
#    1538                 :          0 :         FD_ZERO(&fdsetSend);
#    1539                 :          0 :         FD_ZERO(&fdsetError);
#    1540         [ #  # ]:          0 :         if (!interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS)))
#    1541                 :          0 :             return;
#    1542                 :          0 :     }
#    1543                 :            : 
#    1544         [ +  + ]:     869347 :     for (SOCKET hSocket : recv_select_set) {
#    1545                 :     869347 :         if (FD_ISSET(hSocket, &fdsetRecv)) {
#    1546                 :     130979 :             recv_set.insert(hSocket);
#    1547                 :     130979 :         }
#    1548                 :     869347 :     }
#    1549                 :            : 
#    1550         [ +  + ]:     315326 :     for (SOCKET hSocket : send_select_set) {
#    1551                 :        232 :         if (FD_ISSET(hSocket, &fdsetSend)) {
#    1552                 :        229 :             send_set.insert(hSocket);
#    1553                 :        229 :         }
#    1554                 :        232 :     }
#    1555                 :            : 
#    1556         [ +  + ]:     497667 :     for (SOCKET hSocket : error_select_set) {
#    1557                 :     497667 :         if (FD_ISSET(hSocket, &fdsetError)) {
#    1558                 :          0 :             error_set.insert(hSocket);
#    1559                 :          0 :         }
#    1560                 :     497667 :     }
#    1561                 :     315326 : }
#    1562                 :            : #endif
#    1563                 :            : 
#    1564                 :            : void CConnman::SocketHandler()
#    1565                 :     316051 : {
#    1566                 :     316051 :     std::set<SOCKET> recv_set;
#    1567                 :     316051 :     std::set<SOCKET> send_set;
#    1568                 :     316051 :     std::set<SOCKET> error_set;
#    1569                 :            : 
#    1570                 :     316051 :     {
#    1571                 :     316051 :         const NodesSnapshot snap{*this, /*shuffle=*/false};
#    1572                 :            : 
#    1573                 :            :         // Check for the readiness of the already connected sockets and the
#    1574                 :            :         // listening sockets in one call ("readiness" as in poll(2) or
#    1575                 :            :         // select(2)). If none are ready, wait for a short while and return
#    1576                 :            :         // empty sets.
#    1577                 :     316051 :         SocketEvents(snap.Nodes(), recv_set, send_set, error_set);
#    1578                 :            : 
#    1579                 :            :         // Service (send/receive) each of the already connected nodes.
#    1580                 :     316051 :         SocketHandlerConnected(snap.Nodes(), recv_set, send_set, error_set);
#    1581                 :     316051 :     }
#    1582                 :            : 
#    1583                 :            :     // Accept new connections from listening sockets.
#    1584                 :     316051 :     SocketHandlerListening(recv_set);
#    1585                 :     316051 : }
#    1586                 :            : 
#    1587                 :            : void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
#    1588                 :            :                                       const std::set<SOCKET>& recv_set,
#    1589                 :            :                                       const std::set<SOCKET>& send_set,
#    1590                 :            :                                       const std::set<SOCKET>& error_set)
#    1591                 :     316051 : {
#    1592         [ +  + ]:     498047 :     for (CNode* pnode : nodes) {
#    1593         [ +  + ]:     498047 :         if (interruptNet)
#    1594                 :        380 :             return;
#    1595                 :            : 
#    1596                 :            :         //
#    1597                 :            :         // Receive
#    1598                 :            :         //
#    1599                 :     497667 :         bool recvSet = false;
#    1600                 :     497667 :         bool sendSet = false;
#    1601                 :     497667 :         bool errorSet = false;
#    1602                 :     497667 :         {
#    1603                 :     497667 :             LOCK(pnode->m_sock_mutex);
#    1604         [ -  + ]:     497667 :             if (!pnode->m_sock) {
#    1605                 :          0 :                 continue;
#    1606                 :          0 :             }
#    1607                 :     497667 :             recvSet = recv_set.count(pnode->m_sock->Get()) > 0;
#    1608                 :     497667 :             sendSet = send_set.count(pnode->m_sock->Get()) > 0;
#    1609                 :     497667 :             errorSet = error_set.count(pnode->m_sock->Get()) > 0;
#    1610                 :     497667 :         }
#    1611 [ +  + ][ -  + ]:     497667 :         if (recvSet || errorSet)
#    1612                 :     130300 :         {
#    1613                 :            :             // typical socket buffer is 8K-64K
#    1614                 :     130300 :             uint8_t pchBuf[0x10000];
#    1615                 :     130300 :             int nBytes = 0;
#    1616                 :     130300 :             {
#    1617                 :     130300 :                 LOCK(pnode->m_sock_mutex);
#    1618         [ -  + ]:     130300 :                 if (!pnode->m_sock) {
#    1619                 :          0 :                     continue;
#    1620                 :          0 :                 }
#    1621                 :     130300 :                 nBytes = pnode->m_sock->Recv(pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
#    1622                 :     130300 :             }
#    1623         [ +  + ]:     130300 :             if (nBytes > 0)
#    1624                 :     130067 :             {
#    1625                 :     130067 :                 bool notify = false;
#    1626         [ +  + ]:     130067 :                 if (!pnode->ReceiveMsgBytes({pchBuf, (size_t)nBytes}, notify)) {
#    1627                 :          4 :                     pnode->CloseSocketDisconnect();
#    1628                 :          4 :                 }
#    1629                 :     130067 :                 RecordBytesRecv(nBytes);
#    1630         [ +  + ]:     130067 :                 if (notify) {
#    1631                 :     107652 :                     size_t nSizeAdded = 0;
#    1632                 :     107652 :                     auto it(pnode->vRecvMsg.begin());
#    1633         [ +  + ]:     219280 :                     for (; it != pnode->vRecvMsg.end(); ++it) {
#    1634                 :            :                         // vRecvMsg contains only completed CNetMessage
#    1635                 :            :                         // the single possible partially deserialized message are held by TransportDeserializer
#    1636                 :     111628 :                         nSizeAdded += it->m_raw_message_size;
#    1637                 :     111628 :                     }
#    1638                 :     107652 :                     {
#    1639                 :     107652 :                         LOCK(pnode->cs_vProcessMsg);
#    1640                 :     107652 :                         pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);
#    1641                 :     107652 :                         pnode->nProcessQueueSize += nSizeAdded;
#    1642                 :     107652 :                         pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;
#    1643                 :     107652 :                     }
#    1644                 :     107652 :                     WakeMessageHandler();
#    1645                 :     107652 :                 }
#    1646                 :     130067 :             }
#    1647         [ +  + ]:        233 :             else if (nBytes == 0)
#    1648                 :        214 :             {
#    1649                 :            :                 // socket closed gracefully
#    1650         [ +  - ]:        214 :                 if (!pnode->fDisconnect) {
#    1651         [ +  - ]:        214 :                     LogPrint(BCLog::NET, "socket closed for peer=%d\n", pnode->GetId());
#    1652                 :        214 :                 }
#    1653                 :        214 :                 pnode->CloseSocketDisconnect();
#    1654                 :        214 :             }
#    1655         [ +  - ]:         19 :             else if (nBytes < 0)
#    1656                 :         19 :             {
#    1657                 :            :                 // error
#    1658                 :         19 :                 int nErr = WSAGetLastError();
#    1659 [ +  - ][ +  - ]:         19 :                 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
#         [ +  - ][ +  - ]
#    1660                 :         19 :                 {
#    1661         [ +  - ]:         19 :                     if (!pnode->fDisconnect) {
#    1662         [ +  - ]:         19 :                         LogPrint(BCLog::NET, "socket recv error for peer=%d: %s\n", pnode->GetId(), NetworkErrorString(nErr));
#    1663                 :         19 :                     }
#    1664                 :         19 :                     pnode->CloseSocketDisconnect();
#    1665                 :         19 :                 }
#    1666                 :         19 :             }
#    1667                 :     130300 :         }
#    1668                 :            : 
#    1669         [ +  + ]:     497667 :         if (sendSet) {
#    1670                 :            :             // Send data
#    1671                 :        229 :             size_t bytes_sent = WITH_LOCK(pnode->cs_vSend, return SocketSendData(*pnode));
#    1672         [ +  - ]:        229 :             if (bytes_sent) RecordBytesSent(bytes_sent);
#    1673                 :        229 :         }
#    1674                 :            : 
#    1675         [ +  + ]:     497667 :         if (InactivityCheck(*pnode)) pnode->fDisconnect = true;
#    1676                 :     497667 :     }
#    1677                 :     316051 : }
#    1678                 :            : 
#    1679                 :            : void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set)
#    1680                 :     316051 : {
#    1681         [ +  + ]:     372629 :     for (const ListenSocket& listen_socket : vhListenSocket) {
#    1682         [ +  + ]:     372629 :         if (interruptNet) {
#    1683                 :        717 :             return;
#    1684                 :        717 :         }
#    1685         [ +  + ]:     371912 :         if (recv_set.count(listen_socket.sock->Get()) > 0) {
#    1686                 :        679 :             AcceptConnection(listen_socket);
#    1687                 :        679 :         }
#    1688                 :     371912 :     }
#    1689                 :     316051 : }
#    1690                 :            : 
#    1691                 :            : void CConnman::ThreadSocketHandler()
#    1692                 :        719 : {
#    1693                 :        719 :     SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET);
#    1694         [ +  + ]:     316770 :     while (!interruptNet)
#    1695                 :     316051 :     {
#    1696                 :     316051 :         DisconnectNodes();
#    1697                 :     316051 :         NotifyNumConnectionsChanged();
#    1698                 :     316051 :         SocketHandler();
#    1699                 :     316051 :     }
#    1700                 :        719 : }
#    1701                 :            : 
#    1702                 :            : void CConnman::WakeMessageHandler()
#    1703                 :     155420 : {
#    1704                 :     155420 :     {
#    1705                 :     155420 :         LOCK(mutexMsgProc);
#    1706                 :     155420 :         fMsgProcWake = true;
#    1707                 :     155420 :     }
#    1708                 :     155420 :     condMsgProc.notify_one();
#    1709                 :     155420 : }
#    1710                 :            : 
#    1711                 :            : void CConnman::ThreadDNSAddressSeed()
#    1712                 :         10 : {
#    1713                 :         10 :     SetSyscallSandboxPolicy(SyscallSandboxPolicy::INITIALIZATION_DNS_SEED);
#    1714                 :         10 :     FastRandomContext rng;
#    1715                 :         10 :     std::vector<std::string> seeds = Params().DNSSeeds();
#    1716                 :         10 :     Shuffle(seeds.begin(), seeds.end(), rng);
#    1717                 :         10 :     int seeds_right_now = 0; // Number of seeds left before testing if we have enough connections
#    1718                 :         10 :     int found = 0;
#    1719                 :            : 
#    1720         [ +  + ]:         10 :     if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) {
#    1721                 :            :         // When -forcednsseed is provided, query all.
#    1722                 :          1 :         seeds_right_now = seeds.size();
#    1723         [ +  + ]:          9 :     } else if (addrman.size() == 0) {
#    1724                 :            :         // If we have no known peers, query all.
#    1725                 :            :         // This will occur on the first run, or if peers.dat has been
#    1726                 :            :         // deleted.
#    1727                 :          4 :         seeds_right_now = seeds.size();
#    1728                 :          4 :     }
#    1729                 :            : 
#    1730                 :            :     // goal: only query DNS seed if address need is acute
#    1731                 :            :     // * If we have a reasonable number of peers in addrman, spend
#    1732                 :            :     //   some time trying them first. This improves user privacy by
#    1733                 :            :     //   creating fewer identifying DNS requests, reduces trust by
#    1734                 :            :     //   giving seeds less influence on the network topology, and
#    1735                 :            :     //   reduces traffic to the seeds.
#    1736                 :            :     // * When querying DNS seeds query a few at once, this ensures
#    1737                 :            :     //   that we don't give DNS seeds the ability to eclipse nodes
#    1738                 :            :     //   that query them.
#    1739                 :            :     // * If we continue having problems, eventually query all the
#    1740                 :            :     //   DNS seeds, and if that fails too, also try the fixed seeds.
#    1741                 :            :     //   (done in ThreadOpenConnections)
#    1742         [ +  + ]:         10 :     const std::chrono::seconds seeds_wait_time = (addrman.size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
#    1743                 :            : 
#    1744         [ +  + ]:         10 :     for (const std::string& seed : seeds) {
#    1745         [ +  + ]:         10 :         if (seeds_right_now == 0) {
#    1746                 :          5 :             seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
#    1747                 :            : 
#    1748         [ +  - ]:          5 :             if (addrman.size() > 0) {
#    1749                 :          5 :                 LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
#    1750                 :          5 :                 std::chrono::seconds to_wait = seeds_wait_time;
#    1751         [ +  + ]:          6 :                 while (to_wait.count() > 0) {
#    1752                 :            :                     // if sleeping for the MANY_PEERS interval, wake up
#    1753                 :            :                     // early to see if we have enough peers and can stop
#    1754                 :            :                     // this thread entirely freeing up its resources
#    1755                 :          5 :                     std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
#    1756         [ +  + ]:          5 :                     if (!interruptNet.sleep_for(w)) return;
#    1757                 :          2 :                     to_wait -= w;
#    1758                 :            : 
#    1759                 :          2 :                     int nRelevant = 0;
#    1760                 :          2 :                     {
#    1761                 :          2 :                         LOCK(m_nodes_mutex);
#    1762         [ +  + ]:          4 :                         for (const CNode* pnode : m_nodes) {
#    1763 [ +  - ][ +  + ]:          4 :                             if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
#    1764                 :          4 :                         }
#    1765                 :          2 :                     }
#    1766         [ +  + ]:          2 :                     if (nRelevant >= 2) {
#    1767         [ -  + ]:          1 :                         if (found > 0) {
#    1768                 :          0 :                             LogPrintf("%d addresses found from DNS seeds\n", found);
#    1769                 :          0 :                             LogPrintf("P2P peers available. Finished DNS seeding.\n");
#    1770                 :          1 :                         } else {
#    1771                 :          1 :                             LogPrintf("P2P peers available. Skipped DNS seeding.\n");
#    1772                 :          1 :                         }
#    1773                 :          1 :                         return;
#    1774                 :          1 :                     }
#    1775                 :          2 :                 }
#    1776                 :          5 :             }
#    1777                 :          5 :         }
#    1778                 :            : 
#    1779         [ -  + ]:          6 :         if (interruptNet) return;
#    1780                 :            : 
#    1781                 :            :         // hold off on querying seeds if P2P network deactivated
#    1782         [ -  + ]:          6 :         if (!fNetworkActive) {
#    1783                 :          0 :             LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
#    1784                 :          0 :             do {
#    1785         [ #  # ]:          0 :                 if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
#    1786         [ #  # ]:          0 :             } while (!fNetworkActive);
#    1787                 :          0 :         }
#    1788                 :            : 
#    1789                 :          6 :         LogPrintf("Loading addresses from DNS seed %s\n", seed);
#    1790         [ -  + ]:          6 :         if (HaveNameProxy()) {
#    1791                 :          0 :             AddAddrFetch(seed);
#    1792                 :          6 :         } else {
#    1793                 :          6 :             std::vector<CNetAddr> vIPs;
#    1794                 :          6 :             std::vector<CAddress> vAdd;
#    1795                 :          6 :             ServiceFlags requiredServiceBits = GetDesirableServiceFlags(NODE_NONE);
#    1796                 :          6 :             std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
#    1797                 :          6 :             CNetAddr resolveSource;
#    1798         [ -  + ]:          6 :             if (!resolveSource.SetInternal(host)) {
#    1799                 :          0 :                 continue;
#    1800                 :          0 :             }
#    1801                 :          6 :             unsigned int nMaxIPs = 256; // Limits number of IPs learned from a DNS seed
#    1802         [ -  + ]:          6 :             if (LookupHost(host, vIPs, nMaxIPs, true)) {
#    1803         [ #  # ]:          0 :                 for (const CNetAddr& ip : vIPs) {
#    1804                 :          0 :                     int nOneDay = 24*3600;
#    1805                 :          0 :                     CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
#    1806                 :          0 :                     addr.nTime = GetTime() - 3*nOneDay - rng.randrange(4*nOneDay); // use a random age between 3 and 7 days old
#    1807                 :          0 :                     vAdd.push_back(addr);
#    1808                 :          0 :                     found++;
#    1809                 :          0 :                 }
#    1810                 :          0 :                 addrman.Add(vAdd, resolveSource);
#    1811                 :          6 :             } else {
#    1812                 :            :                 // We now avoid directly using results from DNS Seeds which do not support service bit filtering,
#    1813                 :            :                 // instead using them as a addrfetch to get nodes with our desired service bits.
#    1814                 :          6 :                 AddAddrFetch(seed);
#    1815                 :          6 :             }
#    1816                 :          6 :         }
#    1817                 :          6 :         --seeds_right_now;
#    1818                 :          6 :     }
#    1819                 :          6 :     LogPrintf("%d addresses found from DNS seeds\n", found);
#    1820                 :          6 : }
#    1821                 :            : 
#    1822                 :            : void CConnman::DumpAddresses()
#    1823                 :        722 : {
#    1824                 :        722 :     int64_t nStart = GetTimeMillis();
#    1825                 :            : 
#    1826                 :        722 :     DumpPeerAddresses(::gArgs, addrman);
#    1827                 :            : 
#    1828         [ +  - ]:        722 :     LogPrint(BCLog::NET, "Flushed %d addresses to peers.dat  %dms\n",
#    1829                 :        722 :            addrman.size(), GetTimeMillis() - nStart);
#    1830                 :        722 : }
#    1831                 :            : 
#    1832                 :            : void CConnman::ProcessAddrFetch()
#    1833                 :         26 : {
#    1834                 :         26 :     std::string strDest;
#    1835                 :         26 :     {
#    1836                 :         26 :         LOCK(m_addr_fetches_mutex);
#    1837         [ +  + ]:         26 :         if (m_addr_fetches.empty())
#    1838                 :         25 :             return;
#    1839                 :          1 :         strDest = m_addr_fetches.front();
#    1840                 :          1 :         m_addr_fetches.pop_front();
#    1841                 :          1 :     }
#    1842                 :          0 :     CAddress addr;
#    1843                 :          1 :     CSemaphoreGrant grant(*semOutbound, true);
#    1844         [ +  - ]:          1 :     if (grant) {
#    1845                 :          1 :         OpenNetworkConnection(addr, false, &grant, strDest.c_str(), ConnectionType::ADDR_FETCH);
#    1846                 :          1 :     }
#    1847                 :          1 : }
#    1848                 :            : 
#    1849                 :            : bool CConnman::GetTryNewOutboundPeer() const
#    1850                 :         67 : {
#    1851                 :         67 :     return m_try_another_outbound_peer;
#    1852                 :         67 : }
#    1853                 :            : 
#    1854                 :            : void CConnman::SetTryNewOutboundPeer(bool flag)
#    1855                 :        974 : {
#    1856                 :        974 :     m_try_another_outbound_peer = flag;
#    1857 [ +  - ][ +  + ]:        974 :     LogPrint(BCLog::NET, "net: setting try another outbound peer=%s\n", flag ? "true" : "false");
#    1858                 :        974 : }
#    1859                 :            : 
#    1860                 :            : // Return the number of peers we have over our outbound connection limit
#    1861                 :            : // Exclude peers that are marked for disconnect, or are going to be
#    1862                 :            : // disconnected soon (eg ADDR_FETCH and FEELER)
#    1863                 :            : // Also exclude peers that haven't finished initial connection handshake yet
#    1864                 :            : // (so that we don't decide we're over our desired connection limit, and then
#    1865                 :            : // evict some peer that has finished the handshake)
#    1866                 :            : int CConnman::GetExtraFullOutboundCount() const
#    1867                 :        143 : {
#    1868                 :        143 :     int full_outbound_peers = 0;
#    1869                 :        143 :     {
#    1870                 :        143 :         LOCK(m_nodes_mutex);
#    1871         [ +  + ]:        270 :         for (const CNode* pnode : m_nodes) {
#    1872 [ +  - ][ +  + ]:        270 :             if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsFullOutboundConn()) {
#                 [ +  + ]
#    1873                 :         68 :                 ++full_outbound_peers;
#    1874                 :         68 :             }
#    1875                 :        270 :         }
#    1876                 :        143 :     }
#    1877                 :        143 :     return std::max(full_outbound_peers - m_max_outbound_full_relay, 0);
#    1878                 :        143 : }
#    1879                 :            : 
#    1880                 :            : int CConnman::GetExtraBlockRelayCount() const
#    1881                 :        143 : {
#    1882                 :        143 :     int block_relay_peers = 0;
#    1883                 :        143 :     {
#    1884                 :        143 :         LOCK(m_nodes_mutex);
#    1885         [ +  + ]:        270 :         for (const CNode* pnode : m_nodes) {
#    1886 [ +  - ][ +  - ]:        270 :             if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsBlockOnlyConn()) {
#                 [ +  + ]
#    1887                 :         22 :                 ++block_relay_peers;
#    1888                 :         22 :             }
#    1889                 :        270 :         }
#    1890                 :        143 :     }
#    1891                 :        143 :     return std::max(block_relay_peers - m_max_outbound_block_relay, 0);
#    1892                 :        143 : }
#    1893                 :            : 
#    1894                 :            : void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
#    1895                 :         22 : {
#    1896                 :         22 :     SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_OPEN_CONNECTION);
#    1897                 :            :     // Connect to specific addresses
#    1898         [ +  + ]:         22 :     if (!connect.empty())
#    1899                 :          3 :     {
#    1900                 :          3 :         for (int64_t nLoop = 0;; nLoop++)
#    1901                 :          3 :         {
#    1902                 :          3 :             ProcessAddrFetch();
#    1903         [ +  + ]:          3 :             for (const std::string& strAddr : connect)
#    1904                 :          5 :             {
#    1905                 :          5 :                 CAddress addr(CService(), NODE_NONE);
#    1906                 :          5 :                 OpenNetworkConnection(addr, false, nullptr, strAddr.c_str(), ConnectionType::MANUAL);
#    1907 [ +  - ][ -  + ]:          5 :                 for (int i = 0; i < 10 && i < nLoop; i++)
#    1908                 :          0 :                 {
#    1909         [ #  # ]:          0 :                     if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
#    1910                 :          0 :                         return;
#    1911                 :          0 :                 }
#    1912                 :          5 :             }
#    1913         [ +  - ]:          3 :             if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
#    1914                 :          3 :                 return;
#    1915                 :          3 :         }
#    1916                 :          3 :     }
#    1917                 :            : 
#    1918                 :            :     // Initiate network connections
#    1919                 :         19 :     auto start = GetTime<std::chrono::microseconds>();
#    1920                 :            : 
#    1921                 :            :     // Minimum time before next feeler connection (in microseconds).
#    1922                 :         19 :     auto next_feeler = GetExponentialRand(start, FEELER_INTERVAL);
#    1923                 :         19 :     auto next_extra_block_relay = GetExponentialRand(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
#    1924                 :         19 :     const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);
#    1925                 :         19 :     bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);
#    1926                 :            : 
#    1927         [ +  + ]:         19 :     if (!add_fixed_seeds) {
#    1928                 :         16 :         LogPrintf("Fixed seeds are disabled\n");
#    1929                 :         16 :     }
#    1930                 :            : 
#    1931         [ +  - ]:         23 :     while (!interruptNet)
#    1932                 :         23 :     {
#    1933                 :         23 :         ProcessAddrFetch();
#    1934                 :            : 
#    1935         [ +  + ]:         23 :         if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
#    1936                 :         19 :             return;
#    1937                 :            : 
#    1938                 :          4 :         CSemaphoreGrant grant(*semOutbound);
#    1939         [ -  + ]:          4 :         if (interruptNet)
#    1940                 :          0 :             return;
#    1941                 :            : 
#    1942 [ +  + ][ +  - ]:          4 :         if (add_fixed_seeds && addrman.size() == 0) {
#    1943                 :            :             // When the node starts with an empty peers.dat, there are a few other sources of peers before
#    1944                 :            :             // we fallback on to fixed seeds: -dnsseed, -seednode, -addnode
#    1945                 :            :             // If none of those are available, we fallback on to fixed seeds immediately, else we allow
#    1946                 :            :             // 60 seconds for any of those sources to populate addrman.
#    1947                 :          3 :             bool add_fixed_seeds_now = false;
#    1948                 :            :             // It is cheapest to check if enough time has passed first.
#    1949         [ +  + ]:          3 :             if (GetTime<std::chrono::seconds>() > start + std::chrono::minutes{1}) {
#    1950                 :          2 :                 add_fixed_seeds_now = true;
#    1951                 :          2 :                 LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty\n");
#    1952                 :          2 :             }
#    1953                 :            : 
#    1954                 :            :             // Checking !dnsseed is cheaper before locking 2 mutexes.
#    1955 [ +  + ][ +  - ]:          3 :             if (!add_fixed_seeds_now && !dnsseed) {
#    1956                 :          1 :                 LOCK2(m_addr_fetches_mutex, m_added_nodes_mutex);
#    1957 [ +  - ][ +  - ]:          1 :                 if (m_addr_fetches.empty() && m_added_nodes.empty()) {
#    1958                 :          1 :                     add_fixed_seeds_now = true;
#    1959                 :          1 :                     LogPrintf("Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n");
#    1960                 :          1 :                 }
#    1961                 :          1 :             }
#    1962                 :            : 
#    1963         [ +  - ]:          3 :             if (add_fixed_seeds_now) {
#    1964                 :          3 :                 CNetAddr local;
#    1965                 :          3 :                 local.SetInternal("fixedseeds");
#    1966                 :          3 :                 addrman.Add(ConvertSeeds(Params().FixedSeeds()), local);
#    1967                 :          3 :                 add_fixed_seeds = false;
#    1968                 :          3 :             }
#    1969                 :          3 :         }
#    1970                 :            : 
#    1971                 :            :         //
#    1972                 :            :         // Choose an address to connect to based on most recently seen
#    1973                 :            :         //
#    1974                 :          4 :         CAddress addrConnect;
#    1975                 :            : 
#    1976                 :            :         // Only connect out to one peer per network group (/16 for IPv4).
#    1977                 :          4 :         int nOutboundFullRelay = 0;
#    1978                 :          4 :         int nOutboundBlockRelay = 0;
#    1979                 :          4 :         std::set<std::vector<unsigned char> > setConnected;
#    1980                 :            : 
#    1981                 :          4 :         {
#    1982                 :          4 :             LOCK(m_nodes_mutex);
#    1983         [ +  + ]:          5 :             for (const CNode* pnode : m_nodes) {
#    1984         [ -  + ]:          5 :                 if (pnode->IsFullOutboundConn()) nOutboundFullRelay++;
#    1985         [ +  + ]:          5 :                 if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++;
#    1986                 :            : 
#    1987                 :            :                 // Netgroups for inbound and manual peers are not excluded because our goal here
#    1988                 :            :                 // is to not use multiple of our limited outbound slots on a single netgroup
#    1989                 :            :                 // but inbound and manual peers do not use our outbound slots. Inbound peers
#    1990                 :            :                 // also have the added issue that they could be attacker controlled and used
#    1991                 :            :                 // to prevent us from connecting to particular hosts if we used them here.
#    1992         [ -  + ]:          5 :                 switch (pnode->m_conn_type) {
#    1993         [ +  + ]:          3 :                     case ConnectionType::INBOUND:
#    1994         [ -  + ]:          3 :                     case ConnectionType::MANUAL:
#    1995                 :          3 :                         break;
#    1996         [ -  + ]:          0 :                     case ConnectionType::OUTBOUND_FULL_RELAY:
#    1997         [ +  + ]:          2 :                     case ConnectionType::BLOCK_RELAY:
#    1998         [ -  + ]:          2 :                     case ConnectionType::ADDR_FETCH:
#    1999         [ -  + ]:          2 :                     case ConnectionType::FEELER:
#    2000                 :          2 :                         setConnected.insert(pnode->addr.GetGroup(addrman.GetAsmap()));
#    2001                 :          5 :                 } // no default case, so the compiler can warn about missing cases
#    2002                 :          5 :             }
#    2003                 :          4 :         }
#    2004                 :            : 
#    2005                 :          4 :         ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
#    2006                 :          4 :         auto now = GetTime<std::chrono::microseconds>();
#    2007                 :          4 :         bool anchor = false;
#    2008                 :          4 :         bool fFeeler = false;
#    2009                 :            : 
#    2010                 :            :         // Determine what type of connection to open. Opening
#    2011                 :            :         // BLOCK_RELAY connections to addresses from anchors.dat gets the highest
#    2012                 :            :         // priority. Then we open OUTBOUND_FULL_RELAY priority until we
#    2013                 :            :         // meet our full-relay capacity. Then we open BLOCK_RELAY connection
#    2014                 :            :         // until we hit our block-relay-only peer limit.
#    2015                 :            :         // GetTryNewOutboundPeer() gets set when a stale tip is detected, so we
#    2016                 :            :         // try opening an additional OUTBOUND_FULL_RELAY connection. If none of
#    2017                 :            :         // these conditions are met, check to see if it's time to try an extra
#    2018                 :            :         // block-relay-only peer (to confirm our tip is current, see below) or the next_feeler
#    2019                 :            :         // timer to decide if we should open a FEELER.
#    2020                 :            : 
#    2021 [ -  + ][ #  # ]:          4 :         if (!m_anchors.empty() && (nOutboundBlockRelay < m_max_outbound_block_relay)) {
#    2022                 :          0 :             conn_type = ConnectionType::BLOCK_RELAY;
#    2023                 :          0 :             anchor = true;
#    2024         [ +  - ]:          4 :         } else if (nOutboundFullRelay < m_max_outbound_full_relay) {
#    2025                 :            :             // OUTBOUND_FULL_RELAY
#    2026         [ #  # ]:          4 :         } else if (nOutboundBlockRelay < m_max_outbound_block_relay) {
#    2027                 :          0 :             conn_type = ConnectionType::BLOCK_RELAY;
#    2028         [ #  # ]:          0 :         } else if (GetTryNewOutboundPeer()) {
#    2029                 :            :             // OUTBOUND_FULL_RELAY
#    2030 [ #  # ][ #  # ]:          0 :         } else if (now > next_extra_block_relay && m_start_extra_block_relay_peers) {
#    2031                 :            :             // Periodically connect to a peer (using regular outbound selection
#    2032                 :            :             // methodology from addrman) and stay connected long enough to sync
#    2033                 :            :             // headers, but not much else.
#    2034                 :            :             //
#    2035                 :            :             // Then disconnect the peer, if we haven't learned anything new.
#    2036                 :            :             //
#    2037                 :            :             // The idea is to make eclipse attacks very difficult to pull off,
#    2038                 :            :             // because every few minutes we're finding a new peer to learn headers
#    2039                 :            :             // from.
#    2040                 :            :             //
#    2041                 :            :             // This is similar to the logic for trying extra outbound (full-relay)
#    2042                 :            :             // peers, except:
#    2043                 :            :             // - we do this all the time on an exponential timer, rather than just when
#    2044                 :            :             //   our tip is stale
#    2045                 :            :             // - we potentially disconnect our next-youngest block-relay-only peer, if our
#    2046                 :            :             //   newest block-relay-only peer delivers a block more recently.
#    2047                 :            :             //   See the eviction logic in net_processing.cpp.
#    2048                 :            :             //
#    2049                 :            :             // Because we can promote these connections to block-relay-only
#    2050                 :            :             // connections, they do not get their own ConnectionType enum
#    2051                 :            :             // (similar to how we deal with extra outbound peers).
#    2052                 :          0 :             next_extra_block_relay = GetExponentialRand(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
#    2053                 :          0 :             conn_type = ConnectionType::BLOCK_RELAY;
#    2054         [ #  # ]:          0 :         } else if (now > next_feeler) {
#    2055                 :          0 :             next_feeler = GetExponentialRand(now, FEELER_INTERVAL);
#    2056                 :          0 :             conn_type = ConnectionType::FEELER;
#    2057                 :          0 :             fFeeler = true;
#    2058                 :          0 :         } else {
#    2059                 :            :             // skip to next iteration of while loop
#    2060                 :          0 :             continue;
#    2061                 :          0 :         }
#    2062                 :            : 
#    2063                 :          4 :         addrman.ResolveCollisions();
#    2064                 :            : 
#    2065                 :          4 :         int64_t nANow = GetAdjustedTime();
#    2066                 :          4 :         int nTries = 0;
#    2067         [ +  - ]:          4 :         while (!interruptNet)
#    2068                 :          4 :         {
#    2069 [ -  + ][ #  # ]:          4 :             if (anchor && !m_anchors.empty()) {
#    2070                 :          0 :                 const CAddress addr = m_anchors.back();
#    2071                 :          0 :                 m_anchors.pop_back();
#    2072 [ #  # ][ #  # ]:          0 :                 if (!addr.IsValid() || IsLocal(addr) || !IsReachable(addr) ||
#         [ #  # ][ #  # ]
#    2073         [ #  # ]:          0 :                     !HasAllDesirableServiceFlags(addr.nServices) ||
#    2074         [ #  # ]:          0 :                     setConnected.count(addr.GetGroup(addrman.GetAsmap()))) continue;
#    2075                 :          0 :                 addrConnect = addr;
#    2076         [ #  # ]:          0 :                 LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToString());
#    2077                 :          0 :                 break;
#    2078                 :          0 :             }
#    2079                 :            : 
#    2080                 :            :             // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
#    2081                 :            :             // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
#    2082                 :            :             // already-connected network ranges, ...) before trying new addrman addresses.
#    2083                 :          4 :             nTries++;
#    2084         [ -  + ]:          4 :             if (nTries > 100)
#    2085                 :          0 :                 break;
#    2086                 :            : 
#    2087                 :          4 :             CAddress addr;
#    2088                 :          4 :             int64_t addr_last_try{0};
#    2089                 :            : 
#    2090         [ -  + ]:          4 :             if (fFeeler) {
#    2091                 :            :                 // First, try to get a tried table collision address. This returns
#    2092                 :            :                 // an empty (invalid) address if there are no collisions to try.
#    2093                 :          0 :                 std::tie(addr, addr_last_try) = addrman.SelectTriedCollision();
#    2094                 :            : 
#    2095         [ #  # ]:          0 :                 if (!addr.IsValid()) {
#    2096                 :            :                     // No tried table collisions. Select a new table address
#    2097                 :            :                     // for our feeler.
#    2098                 :          0 :                     std::tie(addr, addr_last_try) = addrman.Select(true);
#    2099         [ #  # ]:          0 :                 } else if (AlreadyConnectedToAddress(addr)) {
#    2100                 :            :                     // If test-before-evict logic would have us connect to a
#    2101                 :            :                     // peer that we're already connected to, just mark that
#    2102                 :            :                     // address as Good(). We won't be able to initiate the
#    2103                 :            :                     // connection anyway, so this avoids inadvertently evicting
#    2104                 :            :                     // a currently-connected peer.
#    2105                 :          0 :                     addrman.Good(addr);
#    2106                 :            :                     // Select a new table address for our feeler instead.
#    2107                 :          0 :                     std::tie(addr, addr_last_try) = addrman.Select(true);
#    2108                 :          0 :                 }
#    2109                 :          4 :             } else {
#    2110                 :            :                 // Not a feeler
#    2111                 :          4 :                 std::tie(addr, addr_last_try) = addrman.Select();
#    2112                 :          4 :             }
#    2113                 :            : 
#    2114                 :            :             // Require outbound connections, other than feelers, to be to distinct network groups
#    2115 [ +  - ][ +  + ]:          4 :             if (!fFeeler && setConnected.count(addr.GetGroup(addrman.GetAsmap()))) {
#                 [ +  + ]
#    2116                 :          1 :                 break;
#    2117                 :          1 :             }
#    2118                 :            : 
#    2119                 :            :             // if we selected an invalid or local address, restart
#    2120 [ +  - ][ #  # ]:          3 :             if (!addr.IsValid() || IsLocal(addr)) {
#    2121                 :          3 :                 break;
#    2122                 :          3 :             }
#    2123                 :            : 
#    2124         [ #  # ]:          0 :             if (!IsReachable(addr))
#    2125                 :          0 :                 continue;
#    2126                 :            : 
#    2127                 :            :             // only consider very recently tried nodes after 30 failed attempts
#    2128 [ #  # ][ #  # ]:          0 :             if (nANow - addr_last_try < 600 && nTries < 30)
#    2129                 :          0 :                 continue;
#    2130                 :            : 
#    2131                 :            :             // for non-feelers, require all the services we'll want,
#    2132                 :            :             // for feelers, only require they be a full node (only because most
#    2133                 :            :             // SPV clients don't have a good address DB available)
#    2134 [ #  # ][ #  # ]:          0 :             if (!fFeeler && !HasAllDesirableServiceFlags(addr.nServices)) {
#    2135                 :          0 :                 continue;
#    2136 [ #  # ][ #  # ]:          0 :             } else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) {
#    2137                 :          0 :                 continue;
#    2138                 :          0 :             }
#    2139                 :            : 
#    2140                 :            :             // Do not connect to bad ports, unless 50 invalid addresses have been selected already.
#    2141 [ #  # ][ #  # ]:          0 :             if (nTries < 50 && (addr.IsIPv4() || addr.IsIPv6()) && IsBadPort(addr.GetPort())) {
#         [ #  # ][ #  # ]
#    2142                 :          0 :                 continue;
#    2143                 :          0 :             }
#    2144                 :            : 
#    2145                 :          0 :             addrConnect = addr;
#    2146                 :          0 :             break;
#    2147                 :          0 :         }
#    2148                 :            : 
#    2149         [ -  + ]:          4 :         if (addrConnect.IsValid()) {
#    2150                 :            : 
#    2151         [ #  # ]:          0 :             if (fFeeler) {
#    2152                 :            :                 // Add small amount of random noise before connection to avoid synchronization.
#    2153                 :          0 :                 int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
#    2154         [ #  # ]:          0 :                 if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))
#    2155                 :          0 :                     return;
#    2156         [ #  # ]:          0 :                 LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
#    2157                 :          0 :             }
#    2158                 :            : 
#    2159                 :          0 :             OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, conn_type);
#    2160                 :          0 :         }
#    2161                 :          4 :     }
#    2162                 :         19 : }
#    2163                 :            : 
#    2164                 :            : std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const
#    2165                 :         19 : {
#    2166                 :         19 :     std::vector<CAddress> ret;
#    2167                 :         19 :     LOCK(m_nodes_mutex);
#    2168         [ +  + ]:         19 :     for (const CNode* pnode : m_nodes) {
#    2169         [ +  + ]:          7 :         if (pnode->IsBlockOnlyConn()) {
#    2170                 :          2 :             ret.push_back(pnode->addr);
#    2171                 :          2 :         }
#    2172                 :          7 :     }
#    2173                 :            : 
#    2174                 :         19 :     return ret;
#    2175                 :         19 : }
#    2176                 :            : 
#    2177                 :            : std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
#    2178                 :       5825 : {
#    2179                 :       5825 :     std::vector<AddedNodeInfo> ret;
#    2180                 :            : 
#    2181                 :       5825 :     std::list<std::string> lAddresses(0);
#    2182                 :       5825 :     {
#    2183                 :       5825 :         LOCK(m_added_nodes_mutex);
#    2184                 :       5825 :         ret.reserve(m_added_nodes.size());
#    2185                 :       5825 :         std::copy(m_added_nodes.cbegin(), m_added_nodes.cend(), std::back_inserter(lAddresses));
#    2186                 :       5825 :     }
#    2187                 :            : 
#    2188                 :            : 
#    2189                 :            :     // Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService
#    2190                 :       5825 :     std::map<CService, bool> mapConnected;
#    2191                 :       5825 :     std::map<std::string, std::pair<bool, CService>> mapConnectedByName;
#    2192                 :       5825 :     {
#    2193                 :       5825 :         LOCK(m_nodes_mutex);
#    2194         [ +  + ]:       7837 :         for (const CNode* pnode : m_nodes) {
#    2195         [ +  - ]:       7837 :             if (pnode->addr.IsValid()) {
#    2196                 :       7837 :                 mapConnected[pnode->addr] = pnode->IsInboundConn();
#    2197                 :       7837 :             }
#    2198                 :       7837 :             std::string addrName{pnode->m_addr_name};
#    2199         [ +  - ]:       7837 :             if (!addrName.empty()) {
#    2200                 :       7837 :                 mapConnectedByName[std::move(addrName)] = std::make_pair(pnode->IsInboundConn(), static_cast<const CService&>(pnode->addr));
#    2201                 :       7837 :             }
#    2202                 :       7837 :         }
#    2203                 :       5825 :     }
#    2204                 :            : 
#    2205         [ +  + ]:       5825 :     for (const std::string& strAddNode : lAddresses) {
#    2206                 :          3 :         CService service(LookupNumeric(strAddNode, Params().GetDefaultPort(strAddNode)));
#    2207                 :          3 :         AddedNodeInfo addedNode{strAddNode, CService(), false, false};
#    2208         [ +  + ]:          3 :         if (service.IsValid()) {
#    2209                 :            :             // strAddNode is an IP:port
#    2210                 :          1 :             auto it = mapConnected.find(service);
#    2211         [ -  + ]:          1 :             if (it != mapConnected.end()) {
#    2212                 :          0 :                 addedNode.resolvedAddress = service;
#    2213                 :          0 :                 addedNode.fConnected = true;
#    2214                 :          0 :                 addedNode.fInbound = it->second;
#    2215                 :          0 :             }
#    2216                 :          2 :         } else {
#    2217                 :            :             // strAddNode is a name
#    2218                 :          2 :             auto it = mapConnectedByName.find(strAddNode);
#    2219         [ -  + ]:          2 :             if (it != mapConnectedByName.end()) {
#    2220                 :          0 :                 addedNode.resolvedAddress = it->second.second;
#    2221                 :          0 :                 addedNode.fConnected = true;
#    2222                 :          0 :                 addedNode.fInbound = it->second.first;
#    2223                 :          0 :             }
#    2224                 :          2 :         }
#    2225                 :          3 :         ret.emplace_back(std::move(addedNode));
#    2226                 :          3 :     }
#    2227                 :            : 
#    2228                 :       5825 :     return ret;
#    2229                 :       5825 : }
#    2230                 :            : 
#    2231                 :            : void CConnman::ThreadOpenAddedConnections()
#    2232                 :        719 : {
#    2233                 :        719 :     SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_ADD_CONNECTION);
#    2234                 :       5821 :     while (true)
#    2235                 :       5821 :     {
#    2236                 :       5821 :         CSemaphoreGrant grant(*semAddnode);
#    2237                 :       5821 :         std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
#    2238                 :       5821 :         bool tried = false;
#    2239         [ +  + ]:       5821 :         for (const AddedNodeInfo& info : vInfo) {
#    2240         [ +  - ]:          2 :             if (!info.fConnected) {
#    2241         [ -  + ]:          2 :                 if (!grant.TryAcquire()) {
#    2242                 :            :                     // If we've used up our semaphore and need a new one, let's not wait here since while we are waiting
#    2243                 :            :                     // the addednodeinfo state might change.
#    2244                 :          0 :                     break;
#    2245                 :          0 :                 }
#    2246                 :          2 :                 tried = true;
#    2247                 :          2 :                 CAddress addr(CService(), NODE_NONE);
#    2248                 :          2 :                 OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), ConnectionType::MANUAL);
#    2249         [ +  + ]:          2 :                 if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
#    2250                 :          1 :                     return;
#    2251                 :          2 :             }
#    2252                 :          2 :         }
#    2253                 :            :         // Retry every 60 seconds if a connection was attempted, otherwise two seconds
#    2254 [ +  + ][ +  + ]:       5820 :         if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2)))
#    2255                 :        718 :             return;
#    2256                 :       5820 :     }
#    2257                 :        719 : }
#    2258                 :            : 
#    2259                 :            : // if successful, this moves the passed grant to the constructed node
#    2260                 :            : void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, ConnectionType conn_type)
#    2261                 :        439 : {
#    2262                 :        439 :     assert(conn_type != ConnectionType::INBOUND);
#    2263                 :            : 
#    2264                 :            :     //
#    2265                 :            :     // Initiate outbound network connection
#    2266                 :            :     //
#    2267         [ -  + ]:        439 :     if (interruptNet) {
#    2268                 :          0 :         return;
#    2269                 :          0 :     }
#    2270         [ -  + ]:        439 :     if (!fNetworkActive) {
#    2271                 :          0 :         return;
#    2272                 :          0 :     }
#    2273         [ -  + ]:        439 :     if (!pszDest) {
#    2274 [ #  # ][ #  # ]:          0 :         bool banned_or_discouraged = m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect));
#                 [ #  # ]
#    2275 [ #  # ][ #  # ]:          0 :         if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) {
#                 [ #  # ]
#    2276                 :          0 :             return;
#    2277                 :          0 :         }
#    2278         [ -  + ]:        439 :     } else if (FindNode(std::string(pszDest)))
#    2279                 :          0 :         return;
#    2280                 :            : 
#    2281                 :        439 :     CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type);
#    2282                 :            : 
#    2283         [ +  + ]:        439 :     if (!pnode)
#    2284                 :         10 :         return;
#    2285         [ +  + ]:        429 :     if (grantOutbound)
#    2286                 :         55 :         grantOutbound->MoveTo(pnode->grantOutbound);
#    2287                 :            : 
#    2288                 :        429 :     m_msgproc->InitializeNode(pnode);
#    2289                 :        429 :     {
#    2290                 :        429 :         LOCK(m_nodes_mutex);
#    2291                 :        429 :         m_nodes.push_back(pnode);
#    2292                 :        429 :     }
#    2293                 :        429 : }
#    2294                 :            : 
#    2295                 :            : void CConnman::ThreadMessageHandler()
#    2296                 :        719 : {
#    2297                 :        719 :     SetSyscallSandboxPolicy(SyscallSandboxPolicy::MESSAGE_HANDLER);
#    2298         [ +  + ]:     210176 :     while (!flagInterruptMsgProc)
#    2299                 :     209464 :     {
#    2300                 :     209464 :         bool fMoreWork = false;
#    2301                 :            : 
#    2302                 :     209464 :         {
#    2303                 :            :             // Randomize the order in which we process messages from/to our peers.
#    2304                 :            :             // This prevents attacks in which an attacker exploits having multiple
#    2305                 :            :             // consecutive connections in the m_nodes list.
#    2306                 :     209464 :             const NodesSnapshot snap{*this, /*shuffle=*/true};
#    2307                 :            : 
#    2308         [ +  + ]:     319868 :             for (CNode* pnode : snap.Nodes()) {
#    2309         [ +  + ]:     319868 :                 if (pnode->fDisconnect)
#    2310                 :         23 :                     continue;
#    2311                 :            : 
#    2312                 :            :                 // Receive messages
#    2313                 :     319845 :                 bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc);
#    2314 [ +  + ][ +  - ]:     319845 :                 fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
#    2315         [ +  + ]:     319845 :                 if (flagInterruptMsgProc)
#    2316                 :          6 :                     return;
#    2317                 :            :                 // Send messages
#    2318                 :     319839 :                 {
#    2319                 :     319839 :                     LOCK(pnode->cs_sendProcessing);
#    2320                 :     319839 :                     m_msgproc->SendMessages(pnode);
#    2321                 :     319839 :                 }
#    2322                 :            : 
#    2323         [ +  + ]:     319839 :                 if (flagInterruptMsgProc)
#    2324                 :          1 :                     return;
#    2325                 :     319839 :             }
#    2326                 :     209464 :         }
#    2327                 :            : 
#    2328                 :     209457 :         WAIT_LOCK(mutexMsgProc, lock);
#    2329         [ +  + ]:     209457 :         if (!fMoreWork) {
#    2330                 :     321783 :             condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100), [this]() EXCLUSIVE_LOCKS_REQUIRED(mutexMsgProc) { return fMsgProcWake; });
#    2331                 :     170639 :         }
#    2332                 :     209457 :         fMsgProcWake = false;
#    2333                 :     209457 :     }
#    2334                 :        719 : }
#    2335                 :            : 
#    2336                 :            : void CConnman::ThreadI2PAcceptIncoming()
#    2337                 :          3 : {
#    2338                 :          3 :     static constexpr auto err_wait_begin = 1s;
#    2339                 :          3 :     static constexpr auto err_wait_cap = 5min;
#    2340                 :          3 :     auto err_wait = err_wait_begin;
#    2341                 :            : 
#    2342                 :          3 :     bool advertising_listen_addr = false;
#    2343                 :          3 :     i2p::Connection conn;
#    2344                 :            : 
#    2345         [ +  + ]:          6 :     while (!interruptNet) {
#    2346                 :            : 
#    2347         [ +  - ]:          3 :         if (!m_i2p_sam_session->Listen(conn)) {
#    2348 [ -  + ][ #  # ]:          3 :             if (advertising_listen_addr && conn.me.IsValid()) {
#    2349                 :          0 :                 RemoveLocal(conn.me);
#    2350                 :          0 :                 advertising_listen_addr = false;
#    2351                 :          0 :             }
#    2352                 :            : 
#    2353                 :          3 :             interruptNet.sleep_for(err_wait);
#    2354         [ +  - ]:          3 :             if (err_wait < err_wait_cap) {
#    2355                 :          3 :                 err_wait *= 2;
#    2356                 :          3 :             }
#    2357                 :            : 
#    2358                 :          3 :             continue;
#    2359                 :          3 :         }
#    2360                 :            : 
#    2361         [ #  # ]:          0 :         if (!advertising_listen_addr) {
#    2362                 :          0 :             AddLocal(conn.me, LOCAL_MANUAL);
#    2363                 :          0 :             advertising_listen_addr = true;
#    2364                 :          0 :         }
#    2365                 :            : 
#    2366         [ #  # ]:          0 :         if (!m_i2p_sam_session->Accept(conn)) {
#    2367                 :          0 :             continue;
#    2368                 :          0 :         }
#    2369                 :            : 
#    2370                 :          0 :         CreateNodeFromAcceptedSocket(std::move(conn.sock), NetPermissionFlags::None,
#    2371                 :          0 :                                      CAddress{conn.me, NODE_NONE}, CAddress{conn.peer, NODE_NONE});
#    2372                 :          0 :     }
#    2373                 :          3 : }
#    2374                 :            : 
#    2375                 :            : bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, NetPermissionFlags permissions)
#    2376                 :       1434 : {
#    2377                 :       1434 :     int nOne = 1;
#    2378                 :            : 
#    2379                 :            :     // Create socket for listening for incoming connections
#    2380                 :       1434 :     struct sockaddr_storage sockaddr;
#    2381                 :       1434 :     socklen_t len = sizeof(sockaddr);
#    2382         [ -  + ]:       1434 :     if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
#    2383                 :          0 :     {
#    2384                 :          0 :         strError = strprintf(Untranslated("Error: Bind address family for %s not supported"), addrBind.ToString());
#    2385                 :          0 :         LogPrintf("%s\n", strError.original);
#    2386                 :          0 :         return false;
#    2387                 :          0 :     }
#    2388                 :            : 
#    2389                 :       1434 :     std::unique_ptr<Sock> sock = CreateSock(addrBind);
#    2390         [ -  + ]:       1434 :     if (!sock) {
#    2391                 :          0 :         strError = strprintf(Untranslated("Error: Couldn't open socket for incoming connections (socket returned error %s)"), NetworkErrorString(WSAGetLastError()));
#    2392                 :          0 :         LogPrintf("%s\n", strError.original);
#    2393                 :          0 :         return false;
#    2394                 :          0 :     }
#    2395                 :            : 
#    2396                 :            :     // Allow binding if the port is still in TIME_WAIT state after
#    2397                 :            :     // the program was closed and restarted.
#    2398                 :       1434 :     setsockopt(sock->Get(), SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int));
#    2399                 :            : 
#    2400                 :            :     // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
#    2401                 :            :     // and enable it by default or not. Try to enable it, if possible.
#    2402         [ -  + ]:       1434 :     if (addrBind.IsIPv6()) {
#    2403                 :          0 : #ifdef IPV6_V6ONLY
#    2404                 :          0 :         setsockopt(sock->Get(), IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int));
#    2405                 :          0 : #endif
#    2406                 :            : #ifdef WIN32
#    2407                 :            :         int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
#    2408                 :            :         setsockopt(sock->Get(), IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
#    2409                 :            : #endif
#    2410                 :          0 :     }
#    2411                 :            : 
#    2412         [ +  + ]:       1434 :     if (::bind(sock->Get(), (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
#    2413                 :        568 :     {
#    2414                 :        568 :         int nErr = WSAGetLastError();
#    2415         [ +  - ]:        568 :         if (nErr == WSAEADDRINUSE)
#    2416                 :        568 :             strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), PACKAGE_NAME);
#    2417                 :          0 :         else
#    2418                 :          0 :             strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
#    2419                 :        568 :         LogPrintf("%s\n", strError.original);
#    2420                 :        568 :         return false;
#    2421                 :        568 :     }
#    2422                 :        866 :     LogPrintf("Bound to %s\n", addrBind.ToString());
#    2423                 :            : 
#    2424                 :            :     // Listen for incoming connections
#    2425         [ -  + ]:        866 :     if (listen(sock->Get(), SOMAXCONN) == SOCKET_ERROR)
#    2426                 :          0 :     {
#    2427                 :          0 :         strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
#    2428                 :          0 :         LogPrintf("%s\n", strError.original);
#    2429                 :          0 :         return false;
#    2430                 :          0 :     }
#    2431                 :            : 
#    2432                 :        866 :     vhListenSocket.emplace_back(std::move(sock), permissions);
#    2433                 :        866 :     return true;
#    2434                 :        866 : }
#    2435                 :            : 
#    2436                 :            : void Discover()
#    2437                 :          2 : {
#    2438         [ +  - ]:          2 :     if (!fDiscover)
#    2439                 :          2 :         return;
#    2440                 :            : 
#    2441                 :            : #ifdef WIN32
#    2442                 :            :     // Get local host IP
#    2443                 :            :     char pszHostName[256] = "";
#    2444                 :            :     if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
#    2445                 :            :     {
#    2446                 :            :         std::vector<CNetAddr> vaddr;
#    2447                 :            :         if (LookupHost(pszHostName, vaddr, 0, true))
#    2448                 :            :         {
#    2449                 :            :             for (const CNetAddr &addr : vaddr)
#    2450                 :            :             {
#    2451                 :            :                 if (AddLocal(addr, LOCAL_IF))
#    2452                 :            :                     LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToString());
#    2453                 :            :             }
#    2454                 :            :         }
#    2455                 :            :     }
#    2456                 :            : #elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS)
#    2457                 :            :     // Get local host ip
#    2458                 :          0 :     struct ifaddrs* myaddrs;
#    2459         [ #  # ]:          0 :     if (getifaddrs(&myaddrs) == 0)
#    2460                 :          0 :     {
#    2461         [ #  # ]:          0 :         for (struct ifaddrs* ifa = myaddrs; ifa != nullptr; ifa = ifa->ifa_next)
#    2462                 :          0 :         {
#    2463         [ #  # ]:          0 :             if (ifa->ifa_addr == nullptr) continue;
#    2464         [ #  # ]:          0 :             if ((ifa->ifa_flags & IFF_UP) == 0) continue;
#    2465         [ #  # ]:          0 :             if (strcmp(ifa->ifa_name, "lo") == 0) continue;
#    2466         [ #  # ]:          0 :             if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
#    2467         [ #  # ]:          0 :             if (ifa->ifa_addr->sa_family == AF_INET)
#    2468                 :          0 :             {
#    2469                 :          0 :                 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
#    2470                 :          0 :                 CNetAddr addr(s4->sin_addr);
#    2471         [ #  # ]:          0 :                 if (AddLocal(addr, LOCAL_IF))
#    2472                 :          0 :                     LogPrintf("%s: IPv4 %s: %s\n", __func__, ifa->ifa_name, addr.ToString());
#    2473                 :          0 :             }
#    2474         [ #  # ]:          0 :             else if (ifa->ifa_addr->sa_family == AF_INET6)
#    2475                 :          0 :             {
#    2476                 :          0 :                 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
#    2477                 :          0 :                 CNetAddr addr(s6->sin6_addr);
#    2478         [ #  # ]:          0 :                 if (AddLocal(addr, LOCAL_IF))
#    2479                 :          0 :                     LogPrintf("%s: IPv6 %s: %s\n", __func__, ifa->ifa_name, addr.ToString());
#    2480                 :          0 :             }
#    2481                 :          0 :         }
#    2482                 :          0 :         freeifaddrs(myaddrs);
#    2483                 :          0 :     }
#    2484                 :          0 : #endif
#    2485                 :          0 : }
#    2486                 :            : 
#    2487                 :            : void CConnman::SetNetworkActive(bool active)
#    2488                 :        975 : {
#    2489                 :        975 :     LogPrintf("%s: %s\n", __func__, active);
#    2490                 :            : 
#    2491         [ +  + ]:        975 :     if (fNetworkActive == active) {
#    2492                 :        965 :         return;
#    2493                 :        965 :     }
#    2494                 :            : 
#    2495                 :         10 :     fNetworkActive = active;
#    2496                 :            : 
#    2497         [ +  + ]:         10 :     if (m_client_interface) {
#    2498                 :          3 :         m_client_interface->NotifyNetworkActiveChanged(fNetworkActive);
#    2499                 :          3 :     }
#    2500                 :         10 : }
#    2501                 :            : 
#    2502                 :            : CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in, bool network_active)
#    2503                 :            :     : addrman(addrman_in), nSeed0(nSeed0In), nSeed1(nSeed1In)
#    2504                 :        968 : {
#    2505                 :        968 :     SetTryNewOutboundPeer(false);
#    2506                 :            : 
#    2507                 :        968 :     Options connOptions;
#    2508                 :        968 :     Init(connOptions);
#    2509                 :        968 :     SetNetworkActive(network_active);
#    2510                 :        968 : }
#    2511                 :            : 
#    2512                 :            : NodeId CConnman::GetNewNodeId()
#    2513                 :       1107 : {
#    2514                 :       1107 :     return nLastNodeId.fetch_add(1, std::memory_order_relaxed);
#    2515                 :       1107 : }
#    2516                 :            : 
#    2517                 :            : 
#    2518                 :            : bool CConnman::Bind(const CService& addr_, unsigned int flags, NetPermissionFlags permissions)
#    2519                 :       1434 : {
#    2520                 :       1434 :     const CService addr{MaybeFlipIPv6toCJDNS(addr_)};
#    2521                 :            : 
#    2522 [ -  + ][ #  # ]:       1434 :     if (!(flags & BF_EXPLICIT) && !IsReachable(addr)) {
#    2523                 :          0 :         return false;
#    2524                 :          0 :     }
#    2525                 :       1434 :     bilingual_str strError;
#    2526         [ +  + ]:       1434 :     if (!BindListenPort(addr, strError, permissions)) {
#    2527 [ -  + ][ #  # ]:        568 :         if ((flags & BF_REPORT_ERROR) && m_client_interface) {
#    2528                 :          0 :             m_client_interface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
#    2529                 :          0 :         }
#    2530                 :        568 :         return false;
#    2531                 :        568 :     }
#    2532                 :            : 
#    2533 [ -  + ][ #  # ]:        866 :     if (addr.IsRoutable() && fDiscover && !(flags & BF_DONT_ADVERTISE) && !NetPermissions::HasFlag(permissions, NetPermissionFlags::NoBan)) {
#         [ #  # ][ #  # ]
#    2534                 :          0 :         AddLocal(addr, LOCAL_BIND);
#    2535                 :          0 :     }
#    2536                 :            : 
#    2537                 :        866 :     return true;
#    2538                 :       1434 : }
#    2539                 :            : 
#    2540                 :            : bool CConnman::InitBinds(const Options& options)
#    2541                 :        717 : {
#    2542                 :        717 :     bool fBound = false;
#    2543         [ +  + ]:        717 :     for (const auto& addrBind : options.vBinds) {
#    2544                 :        716 :         fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR), NetPermissionFlags::None);
#    2545                 :        716 :     }
#    2546         [ +  + ]:        717 :     for (const auto& addrBind : options.vWhiteBinds) {
#    2547                 :          1 :         fBound |= Bind(addrBind.m_service, (BF_EXPLICIT | BF_REPORT_ERROR), addrBind.m_flags);
#    2548                 :          1 :     }
#    2549         [ +  + ]:        717 :     for (const auto& addr_bind : options.onion_binds) {
#    2550                 :        717 :         fBound |= Bind(addr_bind, BF_EXPLICIT | BF_DONT_ADVERTISE, NetPermissionFlags::None);
#    2551                 :        717 :     }
#    2552         [ -  + ]:        717 :     if (options.bind_on_any) {
#    2553                 :          0 :         struct in_addr inaddr_any;
#    2554                 :          0 :         inaddr_any.s_addr = htonl(INADDR_ANY);
#    2555                 :          0 :         struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT;
#    2556                 :          0 :         fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE, NetPermissionFlags::None);
#    2557         [ #  # ]:          0 :         fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE, NetPermissionFlags::None);
#    2558                 :          0 :     }
#    2559                 :        717 :     return fBound;
#    2560                 :        717 : }
#    2561                 :            : 
#    2562                 :            : bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
#    2563                 :        719 : {
#    2564                 :        719 :     Init(connOptions);
#    2565                 :            : 
#    2566 [ +  + ][ -  + ]:        719 :     if (fListen && !InitBinds(connOptions)) {
#    2567         [ #  # ]:          0 :         if (m_client_interface) {
#    2568                 :          0 :             m_client_interface->ThreadSafeMessageBox(
#    2569                 :          0 :                 _("Failed to listen on any port. Use -listen=0 if you want this."),
#    2570                 :          0 :                 "", CClientUIInterface::MSG_ERROR);
#    2571                 :          0 :         }
#    2572                 :          0 :         return false;
#    2573                 :          0 :     }
#    2574                 :            : 
#    2575                 :        719 :     Proxy i2p_sam;
#    2576         [ +  + ]:        719 :     if (GetProxy(NET_I2P, i2p_sam)) {
#    2577                 :          4 :         m_i2p_sam_session = std::make_unique<i2p::sam::Session>(gArgs.GetDataDirNet() / "i2p_private_key",
#    2578                 :          4 :                                                                 i2p_sam.proxy, &interruptNet);
#    2579                 :          4 :     }
#    2580                 :            : 
#    2581         [ -  + ]:        719 :     for (const auto& strDest : connOptions.vSeedNodes) {
#    2582                 :          0 :         AddAddrFetch(strDest);
#    2583                 :          0 :     }
#    2584                 :            : 
#    2585         [ +  + ]:        719 :     if (m_use_addrman_outgoing) {
#    2586                 :            :         // Load addresses from anchors.dat
#    2587                 :         19 :         m_anchors = ReadAnchors(gArgs.GetDataDirNet() / ANCHORS_DATABASE_FILENAME);
#    2588         [ -  + ]:         19 :         if (m_anchors.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) {
#    2589                 :          0 :             m_anchors.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS);
#    2590                 :          0 :         }
#    2591                 :         19 :         LogPrintf("%i block-relay-only anchors will be tried for connections.\n", m_anchors.size());
#    2592                 :         19 :     }
#    2593                 :            : 
#    2594         [ +  - ]:        719 :     if (m_client_interface) {
#    2595                 :        719 :         m_client_interface->InitMessage(_("Starting network threads…").translated);
#    2596                 :        719 :     }
#    2597                 :            : 
#    2598                 :        719 :     fAddressesInitialized = true;
#    2599                 :            : 
#    2600         [ +  - ]:        719 :     if (semOutbound == nullptr) {
#    2601                 :            :         // initialize semaphore
#    2602                 :        719 :         semOutbound = std::make_unique<CSemaphore>(std::min(m_max_outbound, nMaxConnections));
#    2603                 :        719 :     }
#    2604         [ +  - ]:        719 :     if (semAddnode == nullptr) {
#    2605                 :            :         // initialize semaphore
#    2606                 :        719 :         semAddnode = std::make_unique<CSemaphore>(nMaxAddnode);
#    2607                 :        719 :     }
#    2608                 :            : 
#    2609                 :            :     //
#    2610                 :            :     // Start threads
#    2611                 :            :     //
#    2612                 :        719 :     assert(m_msgproc);
#    2613                 :          0 :     InterruptSocks5(false);
#    2614                 :        719 :     interruptNet.reset();
#    2615                 :        719 :     flagInterruptMsgProc = false;
#    2616                 :            : 
#    2617                 :        719 :     {
#    2618                 :        719 :         LOCK(mutexMsgProc);
#    2619                 :        719 :         fMsgProcWake = false;
#    2620                 :        719 :     }
#    2621                 :            : 
#    2622                 :            :     // Send and receive from sockets, accept connections
#    2623                 :        719 :     threadSocketHandler = std::thread(&util::TraceThread, "net", [this] { ThreadSocketHandler(); });
#    2624                 :            : 
#    2625         [ +  + ]:        719 :     if (!gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED))
#    2626                 :        709 :         LogPrintf("DNS seeding disabled\n");
#    2627                 :         10 :     else
#    2628                 :         10 :         threadDNSAddressSeed = std::thread(&util::TraceThread, "dnsseed", [this] { ThreadDNSAddressSeed(); });
#    2629                 :            : 
#    2630                 :            :     // Initiate manual connections
#    2631                 :        719 :     threadOpenAddedConnections = std::thread(&util::TraceThread, "addcon", [this] { ThreadOpenAddedConnections(); });
#    2632                 :            : 
#    2633 [ +  + ][ -  + ]:        719 :     if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
#    2634         [ #  # ]:          0 :         if (m_client_interface) {
#    2635                 :          0 :             m_client_interface->ThreadSafeMessageBox(
#    2636                 :          0 :                 _("Cannot provide specific connections and have addrman find outgoing connections at the same time."),
#    2637                 :          0 :                 "", CClientUIInterface::MSG_ERROR);
#    2638                 :          0 :         }
#    2639                 :          0 :         return false;
#    2640                 :          0 :     }
#    2641 [ +  + ][ +  + ]:        719 :     if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty()) {
#    2642                 :         22 :         threadOpenConnections = std::thread(
#    2643                 :         22 :             &util::TraceThread, "opencon",
#    2644                 :         22 :             [this, connect = connOptions.m_specified_outgoing] { ThreadOpenConnections(connect); });
#    2645                 :         22 :     }
#    2646                 :            : 
#    2647                 :            :     // Process messages
#    2648                 :        719 :     threadMessageHandler = std::thread(&util::TraceThread, "msghand", [this] { ThreadMessageHandler(); });
#    2649                 :            : 
#    2650 [ +  + ][ +  + ]:        719 :     if (connOptions.m_i2p_accept_incoming && m_i2p_sam_session.get() != nullptr) {
#    2651                 :          3 :         threadI2PAcceptIncoming =
#    2652                 :          3 :             std::thread(&util::TraceThread, "i2paccept", [this] { ThreadI2PAcceptIncoming(); });
#    2653                 :          3 :     }
#    2654                 :            : 
#    2655                 :            :     // Dump network addresses
#    2656                 :        719 :     scheduler.scheduleEvery([this] { DumpAddresses(); }, DUMP_PEERS_INTERVAL);
#    2657                 :            : 
#    2658                 :        719 :     return true;
#    2659                 :        719 : }
#    2660                 :            : 
#    2661                 :            : class CNetCleanup
#    2662                 :            : {
#    2663                 :            : public:
#    2664                 :        828 :     CNetCleanup() {}
#    2665                 :            : 
#    2666                 :            :     ~CNetCleanup()
#    2667                 :          0 :     {
#    2668                 :            : #ifdef WIN32
#    2669                 :            :         // Shutdown Windows Sockets
#    2670                 :            :         WSACleanup();
#    2671                 :            : #endif
#    2672                 :          0 :     }
#    2673                 :            : };
#    2674                 :            : static CNetCleanup instance_of_cnetcleanup;
#    2675                 :            : 
#    2676                 :            : void CConnman::Interrupt()
#    2677                 :       1725 : {
#    2678                 :       1725 :     {
#    2679                 :       1725 :         LOCK(mutexMsgProc);
#    2680                 :       1725 :         flagInterruptMsgProc = true;
#    2681                 :       1725 :     }
#    2682                 :       1725 :     condMsgProc.notify_all();
#    2683                 :            : 
#    2684                 :       1725 :     interruptNet();
#    2685                 :       1725 :     InterruptSocks5(true);
#    2686                 :            : 
#    2687         [ +  + ]:       1725 :     if (semOutbound) {
#    2688         [ +  + ]:       8628 :         for (int i=0; i<m_max_outbound; i++) {
#    2689                 :       7909 :             semOutbound->post();
#    2690                 :       7909 :         }
#    2691                 :        719 :     }
#    2692                 :            : 
#    2693         [ +  + ]:       1725 :     if (semAddnode) {
#    2694         [ +  + ]:       6471 :         for (int i=0; i<nMaxAddnode; i++) {
#    2695                 :       5752 :             semAddnode->post();
#    2696                 :       5752 :         }
#    2697                 :        719 :     }
#    2698                 :       1725 : }
#    2699                 :            : 
#    2700                 :            : void CConnman::StopThreads()
#    2701                 :       1725 : {
#    2702         [ +  + ]:       1725 :     if (threadI2PAcceptIncoming.joinable()) {
#    2703                 :          3 :         threadI2PAcceptIncoming.join();
#    2704                 :          3 :     }
#    2705         [ +  + ]:       1725 :     if (threadMessageHandler.joinable())
#    2706                 :        719 :         threadMessageHandler.join();
#    2707         [ +  + ]:       1725 :     if (threadOpenConnections.joinable())
#    2708                 :         22 :         threadOpenConnections.join();
#    2709         [ +  + ]:       1725 :     if (threadOpenAddedConnections.joinable())
#    2710                 :        719 :         threadOpenAddedConnections.join();
#    2711         [ +  + ]:       1725 :     if (threadDNSAddressSeed.joinable())
#    2712                 :         10 :         threadDNSAddressSeed.join();
#    2713         [ +  + ]:       1725 :     if (threadSocketHandler.joinable())
#    2714                 :        719 :         threadSocketHandler.join();
#    2715                 :       1725 : }
#    2716                 :            : 
#    2717                 :            : void CConnman::StopNodes()
#    2718                 :       1725 : {
#    2719         [ +  + ]:       1725 :     if (fAddressesInitialized) {
#    2720                 :        719 :         DumpAddresses();
#    2721                 :        719 :         fAddressesInitialized = false;
#    2722                 :            : 
#    2723         [ +  + ]:        719 :         if (m_use_addrman_outgoing) {
#    2724                 :            :             // Anchor connections are only dumped during clean shutdown.
#    2725                 :         19 :             std::vector<CAddress> anchors_to_dump = GetCurrentBlockRelayOnlyConns();
#    2726         [ -  + ]:         19 :             if (anchors_to_dump.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) {
#    2727                 :          0 :                 anchors_to_dump.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS);
#    2728                 :          0 :             }
#    2729                 :         19 :             DumpAnchors(gArgs.GetDataDirNet() / ANCHORS_DATABASE_FILENAME, anchors_to_dump);
#    2730                 :         19 :         }
#    2731                 :        719 :     }
#    2732                 :            : 
#    2733                 :            :     // Delete peer connections.
#    2734                 :       1725 :     std::vector<CNode*> nodes;
#    2735                 :       1725 :     WITH_LOCK(m_nodes_mutex, nodes.swap(m_nodes));
#    2736         [ +  + ]:       1725 :     for (CNode* pnode : nodes) {
#    2737                 :        691 :         pnode->CloseSocketDisconnect();
#    2738                 :        691 :         DeleteNode(pnode);
#    2739                 :        691 :     }
#    2740                 :            : 
#    2741         [ -  + ]:       1725 :     for (CNode* pnode : m_nodes_disconnected) {
#    2742                 :          0 :         DeleteNode(pnode);
#    2743                 :          0 :     }
#    2744                 :       1725 :     m_nodes_disconnected.clear();
#    2745                 :       1725 :     vhListenSocket.clear();
#    2746                 :       1725 :     semOutbound.reset();
#    2747                 :       1725 :     semAddnode.reset();
#    2748                 :       1725 : }
#    2749                 :            : 
#    2750                 :            : void CConnman::DeleteNode(CNode* pnode)
#    2751                 :       1107 : {
#    2752                 :       1107 :     assert(pnode);
#    2753                 :          0 :     m_msgproc->FinalizeNode(*pnode);
#    2754                 :       1107 :     delete pnode;
#    2755                 :       1107 : }
#    2756                 :            : 
#    2757                 :            : CConnman::~CConnman()
#    2758                 :        968 : {
#    2759                 :        968 :     Interrupt();
#    2760                 :        968 :     Stop();
#    2761                 :        968 : }
#    2762                 :            : 
#    2763                 :            : std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
#    2764                 :        361 : {
#    2765                 :        361 :     std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct, network);
#    2766         [ +  - ]:        361 :     if (m_banman) {
#    2767                 :        361 :         addresses.erase(std::remove_if(addresses.begin(), addresses.end(),
#    2768 [ -  + ][ -  + ]:      21524 :                         [this](const CAddress& addr){return m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr);}),
#    2769                 :        361 :                         addresses.end());
#    2770                 :        361 :     }
#    2771                 :        361 :     return addresses;
#    2772                 :        361 : }
#    2773                 :            : 
#    2774                 :            : std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
#    2775                 :        636 : {
#    2776                 :        636 :     auto local_socket_bytes = requestor.addrBind.GetAddrBytes();
#    2777                 :        636 :     uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
#    2778                 :        636 :         .Write(requestor.addr.GetNetwork())
#    2779                 :        636 :         .Write(local_socket_bytes.data(), local_socket_bytes.size())
#    2780                 :        636 :         .Finalize();
#    2781                 :        636 :     const auto current_time = GetTime<std::chrono::microseconds>();
#    2782                 :        636 :     auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{});
#    2783                 :        636 :     CachedAddrResponse& cache_entry = r.first->second;
#    2784         [ +  + ]:        636 :     if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0.
#    2785                 :        311 :         cache_entry.m_addrs_response_cache = GetAddresses(max_addresses, max_pct, /*network=*/std::nullopt);
#    2786                 :            :         // Choosing a proper cache lifetime is a trade-off between the privacy leak minimization
#    2787                 :            :         // and the usefulness of ADDR responses to honest users.
#    2788                 :            :         //
#    2789                 :            :         // Longer cache lifetime makes it more difficult for an attacker to scrape
#    2790                 :            :         // enough AddrMan data to maliciously infer something useful.
#    2791                 :            :         // By the time an attacker scraped enough AddrMan records, most of
#    2792                 :            :         // the records should be old enough to not leak topology info by
#    2793                 :            :         // e.g. analyzing real-time changes in timestamps.
#    2794                 :            :         //
#    2795                 :            :         // It takes only several hundred requests to scrape everything from an AddrMan containing 100,000 nodes,
#    2796                 :            :         // so ~24 hours of cache lifetime indeed makes the data less inferable by the time
#    2797                 :            :         // most of it could be scraped (considering that timestamps are updated via
#    2798                 :            :         // ADDR self-announcements and when nodes communicate).
#    2799                 :            :         // We also should be robust to those attacks which may not require scraping *full* victim's AddrMan
#    2800                 :            :         // (because even several timestamps of the same handful of nodes may leak privacy).
#    2801                 :            :         //
#    2802                 :            :         // On the other hand, longer cache lifetime makes ADDR responses
#    2803                 :            :         // outdated and less useful for an honest requestor, e.g. if most nodes
#    2804                 :            :         // in the ADDR response are no longer active.
#    2805                 :            :         //
#    2806                 :            :         // However, the churn in the network is known to be rather low. Since we consider
#    2807                 :            :         // nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days,
#    2808                 :            :         // max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference
#    2809                 :            :         // in terms of the freshness of the response.
#    2810                 :        311 :         cache_entry.m_cache_entry_expiration = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6));
#    2811                 :        311 :     }
#    2812                 :        636 :     return cache_entry.m_addrs_response_cache;
#    2813                 :        636 : }
#    2814                 :            : 
#    2815                 :            : bool CConnman::AddNode(const std::string& strNode)
#    2816                 :          2 : {
#    2817                 :          2 :     LOCK(m_added_nodes_mutex);
#    2818         [ +  + ]:          2 :     for (const std::string& it : m_added_nodes) {
#    2819         [ +  - ]:          1 :         if (strNode == it) return false;
#    2820                 :          1 :     }
#    2821                 :            : 
#    2822                 :          1 :     m_added_nodes.push_back(strNode);
#    2823                 :          1 :     return true;
#    2824                 :          2 : }
#    2825                 :            : 
#    2826                 :            : bool CConnman::RemoveAddedNode(const std::string& strNode)
#    2827                 :          2 : {
#    2828                 :          2 :     LOCK(m_added_nodes_mutex);
#    2829         [ +  + ]:          2 :     for(std::vector<std::string>::iterator it = m_added_nodes.begin(); it != m_added_nodes.end(); ++it) {
#    2830         [ +  - ]:          1 :         if (strNode == *it) {
#    2831                 :          1 :             m_added_nodes.erase(it);
#    2832                 :          1 :             return true;
#    2833                 :          1 :         }
#    2834                 :          1 :     }
#    2835                 :          1 :     return false;
#    2836                 :          2 : }
#    2837                 :            : 
#    2838                 :            : size_t CConnman::GetNodeCount(ConnectionDirection flags) const
#    2839                 :        251 : {
#    2840                 :        251 :     LOCK(m_nodes_mutex);
#    2841         [ +  + ]:        251 :     if (flags == ConnectionDirection::Both) // Shortcut if we want total
#    2842                 :         89 :         return m_nodes.size();
#    2843                 :            : 
#    2844                 :        162 :     int nNum = 0;
#    2845         [ +  + ]:        234 :     for (const auto& pnode : m_nodes) {
#    2846 [ +  + ][ +  + ]:        234 :         if (flags & (pnode->IsInboundConn() ? ConnectionDirection::In : ConnectionDirection::Out)) {
#    2847                 :        117 :             nNum++;
#    2848                 :        117 :         }
#    2849                 :        234 :     }
#    2850                 :            : 
#    2851                 :        162 :     return nNum;
#    2852                 :        251 : }
#    2853                 :            : 
#    2854                 :            : void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
#    2855                 :       8690 : {
#    2856                 :       8690 :     vstats.clear();
#    2857                 :       8690 :     LOCK(m_nodes_mutex);
#    2858                 :       8690 :     vstats.reserve(m_nodes.size());
#    2859         [ +  + ]:      14875 :     for (CNode* pnode : m_nodes) {
#    2860                 :      14875 :         vstats.emplace_back();
#    2861                 :      14875 :         pnode->CopyStats(vstats.back());
#    2862                 :      14875 :         vstats.back().m_mapped_as = pnode->addr.GetMappedAS(addrman.GetAsmap());
#    2863                 :      14875 :     }
#    2864                 :       8690 : }
#    2865                 :            : 
#    2866                 :            : bool CConnman::DisconnectNode(const std::string& strNode)
#    2867                 :          2 : {
#    2868                 :          2 :     LOCK(m_nodes_mutex);
#    2869         [ +  + ]:          2 :     if (CNode* pnode = FindNode(strNode)) {
#    2870 [ +  - ][ -  + ]:          1 :         LogPrint(BCLog::NET, "disconnect by address%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->GetId());
#    2871                 :          1 :         pnode->fDisconnect = true;
#    2872                 :          1 :         return true;
#    2873                 :          1 :     }
#    2874                 :          1 :     return false;
#    2875                 :          2 : }
#    2876                 :            : 
#    2877                 :            : bool CConnman::DisconnectNode(const CSubNet& subnet)
#    2878                 :         30 : {
#    2879                 :         30 :     bool disconnected = false;
#    2880                 :         30 :     LOCK(m_nodes_mutex);
#    2881         [ +  + ]:         30 :     for (CNode* pnode : m_nodes) {
#    2882         [ +  + ]:         17 :         if (subnet.Match(pnode->addr)) {
#    2883 [ +  - ][ -  + ]:         10 :             LogPrint(BCLog::NET, "disconnect by subnet%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->GetId());
#    2884                 :         10 :             pnode->fDisconnect = true;
#    2885                 :         10 :             disconnected = true;
#    2886                 :         10 :         }
#    2887                 :         17 :     }
#    2888                 :         30 :     return disconnected;
#    2889                 :         30 : }
#    2890                 :            : 
#    2891                 :            : bool CConnman::DisconnectNode(const CNetAddr& addr)
#    2892                 :         16 : {
#    2893                 :         16 :     return DisconnectNode(CSubNet(addr));
#    2894                 :         16 : }
#    2895                 :            : 
#    2896                 :            : bool CConnman::DisconnectNode(NodeId id)
#    2897                 :         51 : {
#    2898                 :         51 :     LOCK(m_nodes_mutex);
#    2899         [ +  - ]:         85 :     for(CNode* pnode : m_nodes) {
#    2900         [ +  + ]:         85 :         if (id == pnode->GetId()) {
#    2901         [ +  - ]:         51 :             LogPrint(BCLog::NET, "disconnect by id peer=%d; disconnecting\n", pnode->GetId());
#    2902                 :         51 :             pnode->fDisconnect = true;
#    2903                 :         51 :             return true;
#    2904                 :         51 :         }
#    2905                 :         85 :     }
#    2906                 :          0 :     return false;
#    2907                 :         51 : }
#    2908                 :            : 
#    2909                 :            : void CConnman::RecordBytesRecv(uint64_t bytes)
#    2910                 :     130067 : {
#    2911                 :     130067 :     nTotalBytesRecv += bytes;
#    2912                 :     130067 : }
#    2913                 :            : 
#    2914                 :            : void CConnman::RecordBytesSent(uint64_t bytes)
#    2915                 :     113465 : {
#    2916                 :     113465 :     LOCK(cs_totalBytesSent);
#    2917                 :     113465 :     nTotalBytesSent += bytes;
#    2918                 :            : 
#    2919                 :     113465 :     const auto now = GetTime<std::chrono::seconds>();
#    2920         [ +  + ]:     113465 :     if (nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME < now)
#    2921                 :        452 :     {
#    2922                 :            :         // timeframe expired, reset cycle
#    2923                 :        452 :         nMaxOutboundCycleStartTime = now;
#    2924                 :        452 :         nMaxOutboundTotalBytesSentInCycle = 0;
#    2925                 :        452 :     }
#    2926                 :            : 
#    2927                 :     113465 :     nMaxOutboundTotalBytesSentInCycle += bytes;
#    2928                 :     113465 : }
#    2929                 :            : 
#    2930                 :            : uint64_t CConnman::GetMaxOutboundTarget() const
#    2931                 :          8 : {
#    2932                 :          8 :     LOCK(cs_totalBytesSent);
#    2933                 :          8 :     return nMaxOutboundLimit;
#    2934                 :          8 : }
#    2935                 :            : 
#    2936                 :            : std::chrono::seconds CConnman::GetMaxOutboundTimeframe() const
#    2937                 :          8 : {
#    2938                 :          8 :     return MAX_UPLOAD_TIMEFRAME;
#    2939                 :          8 : }
#    2940                 :            : 
#    2941                 :            : std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const
#    2942                 :       1110 : {
#    2943                 :       1110 :     LOCK(cs_totalBytesSent);
#    2944         [ +  + ]:       1110 :     if (nMaxOutboundLimit == 0)
#    2945                 :          8 :         return 0s;
#    2946                 :            : 
#    2947         [ -  + ]:       1102 :     if (nMaxOutboundCycleStartTime.count() == 0)
#    2948                 :          0 :         return MAX_UPLOAD_TIMEFRAME;
#    2949                 :            : 
#    2950                 :       1102 :     const std::chrono::seconds cycleEndTime = nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME;
#    2951                 :       1102 :     const auto now = GetTime<std::chrono::seconds>();
#    2952         [ -  + ]:       1102 :     return (cycleEndTime < now) ? 0s : cycleEndTime - now;
#    2953                 :       1102 : }
#    2954                 :            : 
#    2955                 :            : bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const
#    2956                 :      15866 : {
#    2957                 :      15866 :     LOCK(cs_totalBytesSent);
#    2958         [ +  + ]:      15866 :     if (nMaxOutboundLimit == 0)
#    2959                 :      14764 :         return false;
#    2960                 :            : 
#    2961         [ +  - ]:       1102 :     if (historicalBlockServingLimit)
#    2962                 :       1102 :     {
#    2963                 :            :         // keep a large enough buffer to at least relay each block once
#    2964                 :       1102 :         const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle();
#    2965                 :       1102 :         const uint64_t buffer = timeLeftInCycle / std::chrono::minutes{10} * MAX_BLOCK_SERIALIZED_SIZE;
#    2966 [ +  + ][ +  + ]:       1102 :         if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer)
#    2967                 :        823 :             return true;
#    2968                 :       1102 :     }
#    2969         [ #  # ]:          0 :     else if (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit)
#    2970                 :          0 :         return true;
#    2971                 :            : 
#    2972                 :        279 :     return false;
#    2973                 :       1102 : }
#    2974                 :            : 
#    2975                 :            : uint64_t CConnman::GetOutboundTargetBytesLeft() const
#    2976                 :          8 : {
#    2977                 :          8 :     LOCK(cs_totalBytesSent);
#    2978         [ +  - ]:          8 :     if (nMaxOutboundLimit == 0)
#    2979                 :          8 :         return 0;
#    2980                 :            : 
#    2981         [ #  # ]:          0 :     return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle;
#    2982                 :          8 : }
#    2983                 :            : 
#    2984                 :            : uint64_t CConnman::GetTotalBytesRecv() const
#    2985                 :         10 : {
#    2986                 :         10 :     return nTotalBytesRecv;
#    2987                 :         10 : }
#    2988                 :            : 
#    2989                 :            : uint64_t CConnman::GetTotalBytesSent() const
#    2990                 :         10 : {
#    2991                 :         10 :     LOCK(cs_totalBytesSent);
#    2992                 :         10 :     return nTotalBytesSent;
#    2993                 :         10 : }
#    2994                 :            : 
#    2995                 :            : ServiceFlags CConnman::GetLocalServices() const
#    2996                 :         79 : {
#    2997                 :         79 :     return nLocalServices;
#    2998                 :         79 : }
#    2999                 :            : 
#    3000                 :     107420 : unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
#    3001                 :            : 
#    3002                 :            : CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, 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)
#    3003                 :            :     : m_sock{sock},
#    3004                 :            :       m_connected{GetTime<std::chrono::seconds>()},
#    3005                 :            :       addr(addrIn),
#    3006                 :            :       addrBind(addrBindIn),
#    3007                 :            :       m_addr_name{addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn},
#    3008                 :            :       m_inbound_onion(inbound_onion),
#    3009                 :            :       nKeyedNetGroup(nKeyedNetGroupIn),
#    3010                 :            :       id(idIn),
#    3011                 :            :       nLocalHostNonce(nLocalHostNonceIn),
#    3012                 :            :       m_conn_type(conn_type_in),
#    3013                 :            :       nLocalServices(nLocalServicesIn)
#    3014                 :       1157 : {
#    3015         [ +  + ]:       1157 :     if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
#    3016                 :            : 
#    3017         [ +  + ]:          0 :     for (const std::string &msg : getAllNetMessageTypes())
#    3018                 :      39338 :         mapRecvBytesPerMsgCmd[msg] = 0;
#    3019                 :       1157 :     mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
#    3020                 :            : 
#    3021         [ +  + ]:       1157 :     if (fLogIPs) {
#    3022         [ +  - ]:          2 :         LogPrint(BCLog::NET, "Added connection to %s peer=%d\n", m_addr_name, id);
#    3023                 :       1155 :     } else {
#    3024         [ +  - ]:       1155 :         LogPrint(BCLog::NET, "Added connection peer=%d\n", id);
#    3025                 :       1155 :     }
#    3026                 :            : 
#    3027                 :       1157 :     m_deserializer = std::make_unique<V1TransportDeserializer>(V1TransportDeserializer(Params(), id, SER_NETWORK, INIT_PROTO_VERSION));
#    3028                 :       1157 :     m_serializer = std::make_unique<V1TransportSerializer>(V1TransportSerializer());
#    3029                 :       1157 : }
#    3030                 :            : 
#    3031                 :            : bool CConnman::NodeFullyConnected(const CNode* pnode)
#    3032                 :      60625 : {
#    3033 [ +  - ][ +  + ]:      60625 :     return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect;
#                 [ +  - ]
#    3034                 :      60625 : }
#    3035                 :            : 
#    3036                 :            : void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
#    3037                 :     113377 : {
#    3038                 :     113377 :     size_t nMessageSize = msg.data.size();
#    3039         [ +  - ]:     113377 :     LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId());
#    3040         [ +  + ]:     113377 :     if (gArgs.GetBoolArg("-capturemessages", false)) {
#    3041                 :         35 :         CaptureMessage(pnode->addr, msg.m_type, msg.data, /*is_incoming=*/false);
#    3042                 :         35 :     }
#    3043                 :            : 
#    3044                 :     113377 :     TRACE6(net, outbound_message,
#    3045                 :     113377 :         pnode->GetId(),
#    3046                 :     113377 :         pnode->m_addr_name.c_str(),
#    3047                 :     113377 :         pnode->ConnectionTypeAsString().c_str(),
#    3048                 :     113377 :         msg.m_type.c_str(),
#    3049                 :     113377 :         msg.data.size(),
#    3050                 :     113377 :         msg.data.data()
#    3051                 :     113377 :     );
#    3052                 :            : 
#    3053                 :            :     // make sure we use the appropriate network transport format
#    3054                 :     113377 :     std::vector<unsigned char> serializedHeader;
#    3055                 :     113377 :     pnode->m_serializer->prepareForTransport(msg, serializedHeader);
#    3056                 :     113377 :     size_t nTotalSize = nMessageSize + serializedHeader.size();
#    3057                 :            : 
#    3058                 :     113377 :     size_t nBytesSent = 0;
#    3059                 :     113377 :     {
#    3060                 :     113377 :         LOCK(pnode->cs_vSend);
#    3061                 :     113377 :         bool optimisticSend(pnode->vSendMsg.empty());
#    3062                 :            : 
#    3063                 :            :         //log total amount of bytes per message type
#    3064                 :     113377 :         pnode->mapSendBytesPerMsgCmd[msg.m_type] += nTotalSize;
#    3065                 :     113377 :         pnode->nSendSize += nTotalSize;
#    3066                 :            : 
#    3067         [ +  + ]:     113377 :         if (pnode->nSendSize > nSendBufferMaxSize) pnode->fPauseSend = true;
#    3068                 :     113377 :         pnode->vSendMsg.push_back(std::move(serializedHeader));
#    3069         [ +  + ]:     113377 :         if (nMessageSize) pnode->vSendMsg.push_back(std::move(msg.data));
#    3070                 :            : 
#    3071                 :            :         // If write queue empty, attempt "optimistic write"
#    3072         [ +  + ]:     113377 :         if (optimisticSend) nBytesSent = SocketSendData(*pnode);
#    3073                 :     113377 :     }
#    3074         [ +  + ]:     113377 :     if (nBytesSent) RecordBytesSent(nBytesSent);
#    3075                 :     113377 : }
#    3076                 :            : 
#    3077                 :            : bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
#    3078                 :        329 : {
#    3079                 :        329 :     CNode* found = nullptr;
#    3080                 :        329 :     LOCK(m_nodes_mutex);
#    3081         [ +  + ]:        537 :     for (auto&& pnode : m_nodes) {
#    3082         [ +  + ]:        537 :         if(pnode->GetId() == id) {
#    3083                 :        314 :             found = pnode;
#    3084                 :        314 :             break;
#    3085                 :        314 :         }
#    3086                 :        537 :     }
#    3087 [ +  + ][ +  - ]:        329 :     return found != nullptr && NodeFullyConnected(found) && func(found);
#                 [ +  + ]
#    3088                 :        329 : }
#    3089                 :            : 
#    3090                 :            : CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const
#    3091                 :       2883 : {
#    3092                 :       2883 :     return CSipHasher(nSeed0, nSeed1).Write(id);
#    3093                 :       2883 : }
#    3094                 :            : 
#    3095                 :            : uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
#    3096                 :       1107 : {
#    3097                 :       1107 :     std::vector<unsigned char> vchNetGroup(ad.GetGroup(addrman.GetAsmap()));
#    3098                 :            : 
#    3099                 :       1107 :     return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
#    3100                 :       1107 : }
#    3101                 :            : 
#    3102                 :            : void CaptureMessageToFile(const CAddress& addr,
#    3103                 :            :                           const std::string& msg_type,
#    3104                 :            :                           Span<const unsigned char> data,
#    3105                 :            :                           bool is_incoming)
#    3106                 :         33 : {
#    3107                 :            :     // Note: This function captures the message at the time of processing,
#    3108                 :            :     // not at socket receive/send time.
#    3109                 :            :     // This ensures that the messages are always in order from an application
#    3110                 :            :     // layer (processing) perspective.
#    3111                 :         33 :     auto now = GetTime<std::chrono::microseconds>();
#    3112                 :            : 
#    3113                 :            :     // Windows folder names cannot include a colon
#    3114                 :         33 :     std::string clean_addr = addr.ToString();
#    3115                 :         33 :     std::replace(clean_addr.begin(), clean_addr.end(), ':', '_');
#    3116                 :            : 
#    3117                 :         33 :     fs::path base_path = gArgs.GetDataDirNet() / "message_capture" / clean_addr;
#    3118                 :         33 :     fs::create_directories(base_path);
#    3119                 :            : 
#    3120         [ +  + ]:         33 :     fs::path path = base_path / (is_incoming ? "msgs_recv.dat" : "msgs_sent.dat");
#    3121                 :         33 :     CAutoFile f(fsbridge::fopen(path, "ab"), SER_DISK, CLIENT_VERSION);
#    3122                 :            : 
#    3123                 :         33 :     ser_writedata64(f, now.count());
#    3124                 :         33 :     f.write(MakeByteSpan(msg_type));
#    3125         [ +  + ]:        164 :     for (auto i = msg_type.length(); i < CMessageHeader::COMMAND_SIZE; ++i) {
#    3126                 :        131 :         f << uint8_t{'\0'};
#    3127                 :        131 :     }
#    3128                 :         33 :     uint32_t size = data.size();
#    3129                 :         33 :     ser_writedata32(f, size);
#    3130                 :         33 :     f.write(AsBytes(data));
#    3131                 :         33 : }
#    3132                 :            : 
#    3133                 :            : std::function<void(const CAddress& addr,
#    3134                 :            :                    const std::string& msg_type,
#    3135                 :            :                    Span<const unsigned char> data,
#    3136                 :            :                    bool is_incoming)>
#    3137                 :            :     CaptureMessage = CaptureMessageToFile;

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a