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