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