/Users/eugenesiegel/btc/bitcoin/src/net.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2009-2010 Satoshi Nakamoto | 
| 2 |  | // Copyright (c) 2009-present 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 |  | #include <bitcoin-build-config.h> // IWYU pragma: keep | 
| 7 |  |  | 
| 8 |  | #include <net.h> | 
| 9 |  |  | 
| 10 |  | #include <addrdb.h> | 
| 11 |  | #include <addrman.h> | 
| 12 |  | #include <banman.h> | 
| 13 |  | #include <clientversion.h> | 
| 14 |  | #include <common/args.h> | 
| 15 |  | #include <common/netif.h> | 
| 16 |  | #include <compat/compat.h> | 
| 17 |  | #include <consensus/consensus.h> | 
| 18 |  | #include <crypto/sha256.h> | 
| 19 |  | #include <i2p.h> | 
| 20 |  | #include <key.h> | 
| 21 |  | #include <logging.h> | 
| 22 |  | #include <memusage.h> | 
| 23 |  | #include <net_permissions.h> | 
| 24 |  | #include <netaddress.h> | 
| 25 |  | #include <netbase.h> | 
| 26 |  | #include <node/eviction.h> | 
| 27 |  | #include <node/interface_ui.h> | 
| 28 |  | #include <protocol.h> | 
| 29 |  | #include <random.h> | 
| 30 |  | #include <scheduler.h> | 
| 31 |  | #include <util/fs.h> | 
| 32 |  | #include <util/sock.h> | 
| 33 |  | #include <util/strencodings.h> | 
| 34 |  | #include <util/thread.h> | 
| 35 |  | #include <util/threadinterrupt.h> | 
| 36 |  | #include <util/trace.h> | 
| 37 |  | #include <util/translation.h> | 
| 38 |  | #include <util/vector.h> | 
| 39 |  |  | 
| 40 |  | #include <algorithm> | 
| 41 |  | #include <array> | 
| 42 |  | #include <cstring> | 
| 43 |  | #include <cmath> | 
| 44 |  | #include <cstdint> | 
| 45 |  | #include <functional> | 
| 46 |  | #include <optional> | 
| 47 |  | #include <unordered_map> | 
| 48 |  |  | 
| 49 |  | TRACEPOINT_SEMAPHORE(net, closed_connection); | 
| 50 |  | TRACEPOINT_SEMAPHORE(net, evicted_inbound_connection); | 
| 51 |  | TRACEPOINT_SEMAPHORE(net, inbound_connection); | 
| 52 |  | TRACEPOINT_SEMAPHORE(net, outbound_connection); | 
| 53 |  | TRACEPOINT_SEMAPHORE(net, outbound_message); | 
| 54 |  |  | 
| 55 |  | /** Maximum number of block-relay-only anchor connections */ | 
| 56 |  | static constexpr size_t MAX_BLOCK_RELAY_ONLY_ANCHORS = 2; | 
| 57 |  | 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."); | 
| 58 |  | /** Anchor IP address database file name */ | 
| 59 |  | const char* const ANCHORS_DATABASE_FILENAME = "anchors.dat"; | 
| 60 |  |  | 
| 61 |  | // How often to dump addresses to peers.dat | 
| 62 |  | static constexpr std::chrono::minutes DUMP_PEERS_INTERVAL{15}; | 
| 63 |  |  | 
| 64 |  | /** Number of DNS seeds to query when the number of connections is low. */ | 
| 65 |  | static constexpr int DNSSEEDS_TO_QUERY_AT_ONCE = 3; | 
| 66 |  |  | 
| 67 |  | /** Minimum number of outbound connections under which we will keep fetching our address seeds. */ | 
| 68 |  | static constexpr int SEED_OUTBOUND_CONNECTION_THRESHOLD = 2; | 
| 69 |  |  | 
| 70 |  | /** How long to delay before querying DNS seeds | 
| 71 |  |  * | 
| 72 |  |  * If we have more than THRESHOLD entries in addrman, then it's likely | 
| 73 |  |  * that we got those addresses from having previously connected to the P2P | 
| 74 |  |  * network, and that we'll be able to successfully reconnect to the P2P | 
| 75 |  |  * network via contacting one of them. So if that's the case, spend a | 
| 76 |  |  * little longer trying to connect to known peers before querying the | 
| 77 |  |  * DNS seeds. | 
| 78 |  |  */ | 
| 79 |  | static constexpr std::chrono::seconds DNSSEEDS_DELAY_FEW_PEERS{11}; | 
| 80 |  | static constexpr std::chrono::minutes DNSSEEDS_DELAY_MANY_PEERS{5}; | 
| 81 |  | static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" peers | 
| 82 |  |  | 
| 83 |  | /** The default timeframe for -maxuploadtarget. 1 day. */ | 
| 84 |  | static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24}; | 
| 85 |  |  | 
| 86 |  | // A random time period (0 to 1 seconds) is added to feeler connections to prevent synchronization. | 
| 87 |  | static constexpr auto FEELER_SLEEP_WINDOW{1s}; | 
| 88 |  |  | 
| 89 |  | /** Frequency to attempt extra connections to reachable networks we're not connected to yet **/ | 
| 90 |  | static constexpr auto EXTRA_NETWORK_PEER_INTERVAL{5min}; | 
| 91 |  |  | 
| 92 |  | /** Used to pass flags to the Bind() function */ | 
| 93 |  | enum BindFlags { | 
| 94 |  |     BF_NONE         = 0, | 
| 95 |  |     BF_REPORT_ERROR = (1U << 0), | 
| 96 |  |     /** | 
| 97 |  |      * Do not call AddLocal() for our special addresses, e.g., for incoming | 
| 98 |  |      * Tor connections, to prevent gossiping them over the network. | 
| 99 |  |      */ | 
| 100 |  |     BF_DONT_ADVERTISE = (1U << 1), | 
| 101 |  | }; | 
| 102 |  |  | 
| 103 |  | // The set of sockets cannot be modified while waiting | 
| 104 |  | // The sleep time needs to be small to avoid new sockets stalling | 
| 105 |  | static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50; | 
| 106 |  |  | 
| 107 |  | const std::string NET_MESSAGE_TYPE_OTHER = "*other*"; | 
| 108 |  |  | 
| 109 |  | static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8] | 
| 110 |  | static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8] | 
| 111 |  | static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8] | 
| 112 |  | // | 
| 113 |  | // Global state variables | 
| 114 |  | // | 
| 115 |  | bool fDiscover = true; | 
| 116 |  | bool fListen = true; | 
| 117 |  | GlobalMutex g_maplocalhost_mutex; | 
| 118 |  | std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex); | 
| 119 |  | std::string strSubVersion; | 
| 120 |  |  | 
| 121 |  | size_t CSerializedNetMsg::GetMemoryUsage() const noexcept | 
| 122 | 5.85M | { | 
| 123 | 5.85M |     return sizeof(*this) + memusage::DynamicUsage(m_type) + memusage::DynamicUsage(data); | 
| 124 | 5.85M | } | 
| 125 |  |  | 
| 126 |  | size_t CNetMessage::GetMemoryUsage() const noexcept | 
| 127 | 13.1M | { | 
| 128 | 13.1M |     return sizeof(*this) + memusage::DynamicUsage(m_type) + m_recv.GetMemoryUsage(); | 
| 129 | 13.1M | } | 
| 130 |  |  | 
| 131 |  | void CConnman::AddAddrFetch(const std::string& strDest) | 
| 132 | 0 | { | 
| 133 | 0 |     LOCK(m_addr_fetches_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 134 | 0 |     m_addr_fetches.push_back(strDest); | 
| 135 | 0 | } | 
| 136 |  |  | 
| 137 |  | uint16_t GetListenPort() | 
| 138 | 2.02k | { | 
| 139 |  |     // If -bind= is provided with ":port" part, use that (first one if multiple are provided). | 
| 140 | 2.02k |     for (const std::string& bind_arg : gArgs.GetArgs("-bind")) { | 
| 141 | 0 |         constexpr uint16_t dummy_port = 0; | 
| 142 |  | 
 | 
| 143 | 0 |         const std::optional<CService> bind_addr{Lookup(bind_arg, dummy_port, /*fAllowLookup=*/false)}; | 
| 144 | 0 |         if (bind_addr.has_value() && bind_addr->GetPort() != dummy_port) return bind_addr->GetPort(); | 
| 145 | 0 |     } | 
| 146 |  |  | 
| 147 |  |     // Otherwise, if -whitebind= without NetPermissionFlags::NoBan is provided, use that | 
| 148 |  |     // (-whitebind= is required to have ":port"). | 
| 149 | 2.02k |     for (const std::string& whitebind_arg : gArgs.GetArgs("-whitebind")) { | 
| 150 | 0 |         NetWhitebindPermissions whitebind; | 
| 151 | 0 |         bilingual_str error; | 
| 152 | 0 |         if (NetWhitebindPermissions::TryParse(whitebind_arg, whitebind, error)) { | 
| 153 | 0 |             if (!NetPermissions::HasFlag(whitebind.m_flags, NetPermissionFlags::NoBan)) { | 
| 154 | 0 |                 return whitebind.m_service.GetPort(); | 
| 155 | 0 |             } | 
| 156 | 0 |         } | 
| 157 | 0 |     } | 
| 158 |  |  | 
| 159 |  |     // Otherwise, if -port= is provided, use that. Otherwise use the default port. | 
| 160 | 2.02k |     return static_cast<uint16_t>(gArgs.GetIntArg("-port", Params().GetDefaultPort())); | 
| 161 | 2.02k | } | 
| 162 |  |  | 
| 163 |  | // Determine the "best" local address for a particular peer. | 
| 164 |  | [[nodiscard]] static std::optional<CService> GetLocal(const CNode& peer) | 
| 165 | 2.02k | { | 
| 166 | 2.02k |     if (!fListen) return std::nullopt0; | 
| 167 |  |  | 
| 168 | 2.02k |     std::optional<CService> addr; | 
| 169 | 2.02k |     int nBestScore = -1; | 
| 170 | 2.02k |     int nBestReachability = -1; | 
| 171 | 2.02k |     { | 
| 172 | 2.02k |         LOCK(g_maplocalhost_mutex); | Line | Count | Source |  | 259 | 2.02k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 2.02k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 2.02k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 2.02k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 173 | 2.02k |         for (const auto& [local_addr, local_service_info] : mapLocalHost) { | 
| 174 |  |             // For privacy reasons, don't advertise our privacy-network address | 
| 175 |  |             // to other networks and don't advertise our other-network address | 
| 176 |  |             // to privacy networks. | 
| 177 | 0 |             if (local_addr.GetNetwork() != peer.ConnectedThroughNetwork() | 
| 178 | 0 |                 && (local_addr.IsPrivacyNet() || peer.IsConnectedThroughPrivacyNet())) { | 
| 179 | 0 |                 continue; | 
| 180 | 0 |             } | 
| 181 | 0 |             const int nScore{local_service_info.nScore}; | 
| 182 | 0 |             const int nReachability{local_addr.GetReachabilityFrom(peer.addr)}; | 
| 183 | 0 |             if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) { | 
| 184 | 0 |                 addr.emplace(CService{local_addr, local_service_info.nPort}); | 
| 185 | 0 |                 nBestReachability = nReachability; | 
| 186 | 0 |                 nBestScore = nScore; | 
| 187 | 0 |             } | 
| 188 | 0 |         } | 
| 189 | 2.02k |     } | 
| 190 | 2.02k |     return addr; | 
| 191 | 2.02k | } | 
| 192 |  |  | 
| 193 |  | //! Convert the serialized seeds into usable address objects. | 
| 194 |  | static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn) | 
| 195 | 0 | { | 
| 196 |  |     // It'll only connect to one or two seed nodes because once it connects, | 
| 197 |  |     // it'll get a pile of addresses with newer timestamps. | 
| 198 |  |     // Seed nodes are given a random 'last seen time' of between one and two | 
| 199 |  |     // weeks ago. | 
| 200 | 0 |     const auto one_week{7 * 24h}; | 
| 201 | 0 |     std::vector<CAddress> vSeedsOut; | 
| 202 | 0 |     FastRandomContext rng; | 
| 203 | 0 |     ParamsStream s{DataStream{vSeedsIn}, CAddress::V2_NETWORK}; | 
| 204 | 0 |     while (!s.eof()) { | 
| 205 | 0 |         CService endpoint; | 
| 206 | 0 |         s >> endpoint; | 
| 207 | 0 |         CAddress addr{endpoint, SeedsServiceFlags()}; | 
| 208 | 0 |         addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week); | 
| 209 | 0 |         LogDebug(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 210 | 0 |         vSeedsOut.push_back(addr); | 
| 211 | 0 |     } | 
| 212 | 0 |     return vSeedsOut; | 
| 213 | 0 | } | 
| 214 |  |  | 
| 215 |  | // Determine the "best" local address for a particular peer. | 
| 216 |  | // If none, return the unroutable 0.0.0.0 but filled in with | 
| 217 |  | // the normal parameters, since the IP may be changed to a useful | 
| 218 |  | // one by discovery. | 
| 219 |  | CService GetLocalAddress(const CNode& peer) | 
| 220 | 2.02k | { | 
| 221 | 2.02k |     return GetLocal(peer).value_or(CService{CNetAddr(), GetListenPort()}); | 
| 222 | 2.02k | } | 
| 223 |  |  | 
| 224 |  | static int GetnScore(const CService& addr) | 
| 225 | 0 | { | 
| 226 | 0 |     LOCK(g_maplocalhost_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 227 | 0 |     const auto it = mapLocalHost.find(addr); | 
| 228 | 0 |     return (it != mapLocalHost.end()) ? it->second.nScore : 0; | 
| 229 | 0 | } | 
| 230 |  |  | 
| 231 |  | // Is our peer's addrLocal potentially useful as an external IP source? | 
| 232 |  | [[nodiscard]] static bool IsPeerAddrLocalGood(CNode *pnode) | 
| 233 | 2.02k | { | 
| 234 | 2.02k |     CService addrLocal = pnode->GetAddrLocal(); | 
| 235 | 2.02k |     return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable()1.30k&& | 
| 236 | 2.02k |            g_reachable_nets.Contains(addrLocal)0; | 
| 237 | 2.02k | } | 
| 238 |  |  | 
| 239 |  | std::optional<CService> GetLocalAddrForPeer(CNode& node) | 
| 240 | 2.02k | { | 
| 241 | 2.02k |     CService addrLocal{GetLocalAddress(node)}; | 
| 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 | 2.02k |     FastRandomContext rng; | 
| 246 | 2.02k |     if (IsPeerAddrLocalGood(&node) && (0 !addrLocal.IsRoutable()0|| | 
| 247 | 0 |          rng.randbits((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3 : 1) == 0)) | 
| 248 | 0 |     { | 
| 249 | 0 |         if (node.IsInboundConn()) { | 
| 250 |  |             // For inbound connections, assume both the address and the port | 
| 251 |  |             // as seen from the peer. | 
| 252 | 0 |             addrLocal = CService{node.GetAddrLocal()}; | 
| 253 | 0 |         } 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 | 0 |             addrLocal.SetIP(node.GetAddrLocal()); | 
| 259 | 0 |         } | 
| 260 | 0 |     } | 
| 261 | 2.02k |     if (addrLocal.IsRoutable()) { | 
| 262 | 0 |         LogDebug(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToStringAddrPort(), node.GetId()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 263 | 0 |         return addrLocal; | 
| 264 | 0 |     } | 
| 265 |  |     // Address is unroutable. Don't advertise. | 
| 266 | 2.02k |     return std::nullopt; | 
| 267 | 2.02k | } | 
| 268 |  |  | 
| 269 |  | void ClearLocal() | 
| 270 | 51.2k | { | 
| 271 | 51.2k |     LOCK(g_maplocalhost_mutex); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 272 | 51.2k |     return mapLocalHost.clear(); | 
| 273 | 51.2k | } | 
| 274 |  |  | 
| 275 |  | // learn a new local address | 
| 276 |  | bool AddLocal(const CService& addr_, int nScore) | 
| 277 | 0 | { | 
| 278 | 0 |     CService addr{MaybeFlipIPv6toCJDNS(addr_)}; | 
| 279 |  | 
 | 
| 280 | 0 |     if (!addr.IsRoutable()) | 
| 281 | 0 |         return false; | 
| 282 |  |  | 
| 283 | 0 |     if (!fDiscover && nScore < LOCAL_MANUAL) | 
| 284 | 0 |         return false; | 
| 285 |  |  | 
| 286 | 0 |     if (!g_reachable_nets.Contains(addr)) | 
| 287 | 0 |         return false; | 
| 288 |  |  | 
| 289 | 0 |     LogPrintf("AddLocal(%s,%i)\n", addr.ToStringAddrPort(), nScore);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 290 |  | 
 | 
| 291 | 0 |     { | 
| 292 | 0 |         LOCK(g_maplocalhost_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 293 | 0 |         const auto [it, is_newly_added] = mapLocalHost.emplace(addr, LocalServiceInfo()); | 
| 294 | 0 |         LocalServiceInfo &info = it->second; | 
| 295 | 0 |         if (is_newly_added || nScore >= info.nScore) { | 
| 296 | 0 |             info.nScore = nScore + (is_newly_added ? 0 : 1); | 
| 297 | 0 |             info.nPort = addr.GetPort(); | 
| 298 | 0 |         } | 
| 299 | 0 |     } | 
| 300 |  | 
 | 
| 301 | 0 |     return true; | 
| 302 | 0 | } | 
| 303 |  |  | 
| 304 |  | bool AddLocal(const CNetAddr &addr, int nScore) | 
| 305 | 0 | { | 
| 306 | 0 |     return AddLocal(CService(addr, GetListenPort()), nScore); | 
| 307 | 0 | } | 
| 308 |  |  | 
| 309 |  | void RemoveLocal(const CService& addr) | 
| 310 | 0 | { | 
| 311 | 0 |     LOCK(g_maplocalhost_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 312 | 0 |     LogPrintf("RemoveLocal(%s)\n", addr.ToStringAddrPort());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 313 | 0 |     mapLocalHost.erase(addr); | 
| 314 | 0 | } | 
| 315 |  |  | 
| 316 |  | /** vote for a local address */ | 
| 317 |  | bool SeenLocal(const CService& addr) | 
| 318 | 0 | { | 
| 319 | 0 |     LOCK(g_maplocalhost_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 320 | 0 |     const auto it = mapLocalHost.find(addr); | 
| 321 | 0 |     if (it == mapLocalHost.end()) return false; | 
| 322 | 0 |     ++it->second.nScore; | 
| 323 | 0 |     return true; | 
| 324 | 0 | } | 
| 325 |  |  | 
| 326 |  |  | 
| 327 |  | /** check whether a given address is potentially local */ | 
| 328 |  | bool IsLocal(const CService& addr) | 
| 329 | 0 | { | 
| 330 | 0 |     LOCK(g_maplocalhost_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 331 | 0 |     return mapLocalHost.count(addr) > 0; | 
| 332 | 0 | } | 
| 333 |  |  | 
| 334 |  | bool CConnman::AlreadyConnectedToHost(const std::string& host) const | 
| 335 | 0 | { | 
| 336 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 337 | 0 |     return std::ranges::any_of(m_nodes, [&host](CNode* node) { return node->m_addr_name == host; }); | 
| 338 | 0 | } | 
| 339 |  |  | 
| 340 |  | bool CConnman::AlreadyConnectedToAddressPort(const CService& addr_port) const | 
| 341 | 0 | { | 
| 342 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 343 | 0 |     return std::ranges::any_of(m_nodes, [&addr_port](CNode* node) { return node->addr == addr_port; }); | 
| 344 | 0 | } | 
| 345 |  |  | 
| 346 |  | bool CConnman::AlreadyConnectedToAddress(const CNetAddr& addr) const | 
| 347 | 0 | { | 
| 348 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 349 | 0 |     return std::ranges::any_of(m_nodes, [&addr](CNode* node) { return node->addr == addr; }); | 
| 350 | 0 | } | 
| 351 |  |  | 
| 352 |  | bool CConnman::CheckIncomingNonce(uint64_t nonce) | 
| 353 | 182k | { | 
| 354 | 182k |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 182k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 182k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 182k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 182k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 355 | 263k |     for (const CNode* pnode : m_nodes) { | 
| 356 | 263k |         if (!pnode->fSuccessfullyConnected && !pnode->IsInboundConn()148k&& pnode->GetLocalNonce() == nonce1.44k) | 
| 357 | 0 |             return false; | 
| 358 | 263k |     } | 
| 359 | 182k |     return true; | 
| 360 | 182k | } | 
| 361 |  |  | 
| 362 |  | /** Get the bind address for a socket as CService. */ | 
| 363 |  | static CService GetBindAddress(const Sock& sock) | 
| 364 | 0 | { | 
| 365 | 0 |     CService addr_bind; | 
| 366 | 0 |     struct sockaddr_storage sockaddr_bind; | 
| 367 | 0 |     socklen_t sockaddr_bind_len = sizeof(sockaddr_bind); | 
| 368 | 0 |     if (!sock.GetSockName((struct sockaddr*)&sockaddr_bind, &sockaddr_bind_len)) { | 
| 369 | 0 |         addr_bind.SetSockAddr((const struct sockaddr*)&sockaddr_bind, sockaddr_bind_len); | 
| 370 | 0 |     } else { | 
| 371 | 0 |         LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "getsockname failed\n"); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 372 | 0 |     } | 
| 373 | 0 |     return addr_bind; | 
| 374 | 0 | } | 
| 375 |  |  | 
| 376 |  | CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type, bool use_v2transport) | 
| 377 | 0 | { | 
| 378 | 0 |     AssertLockNotHeld(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 379 | 0 |     assert(conn_type != ConnectionType::INBOUND); | 
| 380 |  |  | 
| 381 | 0 |     if (pszDest == nullptr) { | 
| 382 | 0 |         if (IsLocal(addrConnect)) | 
| 383 | 0 |             return nullptr; | 
| 384 |  |  | 
| 385 |  |         // Look for an existing connection | 
| 386 | 0 |         if (AlreadyConnectedToAddressPort(addrConnect)) { | 
| 387 | 0 |             LogInfo("Failed to open new connection to %s, already connected", addrConnect.ToStringAddrPort());| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 388 | 0 |             return nullptr; | 
| 389 | 0 |         } | 
| 390 | 0 |     } | 
| 391 |  |  | 
| 392 | 0 |     LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying %s connection %s lastseen=%.1fhrs\n", | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 393 | 0 |         use_v2transport ? "v2" : "v1", | 
| 394 | 0 |         pszDest ? pszDest : addrConnect.ToStringAddrPort(), | 
| 395 | 0 |         Ticks<HoursDouble>(pszDest ? 0h : Now<NodeSeconds>() - addrConnect.nTime)); | 
| 396 |  |  | 
| 397 |  |     // Resolve | 
| 398 | 0 |     const uint16_t default_port{pszDest != nullptr ? GetDefaultPort(pszDest) : | 
| 399 | 0 |                                                      m_params.GetDefaultPort()}; | 
| 400 |  |  | 
| 401 |  |     // Collection of addresses to try to connect to: either all dns resolved addresses if a domain name (pszDest) is provided, or addrConnect otherwise. | 
| 402 | 0 |     std::vector<CAddress> connect_to{}; | 
| 403 | 0 |     if (pszDest) { | 
| 404 | 0 |         std::vector<CService> resolved{Lookup(pszDest, default_port, fNameLookup && !HaveNameProxy(), 256)}; | 
| 405 | 0 |         if (!resolved.empty()) { | 
| 406 | 0 |             std::shuffle(resolved.begin(), resolved.end(), FastRandomContext()); | 
| 407 |  |             // If the connection is made by name, it can be the case that the name resolves to more than one address. | 
| 408 |  |             // We don't want to connect any more of them if we are already connected to one | 
| 409 | 0 |             for (const auto& r : resolved) { | 
| 410 | 0 |                 addrConnect = CAddress{MaybeFlipIPv6toCJDNS(r), NODE_NONE}; | 
| 411 | 0 |                 if (!addrConnect.IsValid()) { | 
| 412 | 0 |                     LogDebug(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToStringAddrPort(), pszDest); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 413 | 0 |                     return nullptr; | 
| 414 | 0 |                 } | 
| 415 |  |                 // It is possible that we already have a connection to the IP/port pszDest resolved to. | 
| 416 |  |                 // In that case, drop the connection that was just created. | 
| 417 | 0 |                 if (AlreadyConnectedToAddressPort(addrConnect)) { | 
| 418 | 0 |                     LogPrintf("Not opening a connection to %s, already connected to %s\n", pszDest, addrConnect.ToStringAddrPort());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 419 | 0 |                     return nullptr; | 
| 420 | 0 |                 } | 
| 421 |  |                 // Add the address to the resolved addresses vector so we can try to connect to it later on | 
| 422 | 0 |                 connect_to.push_back(addrConnect); | 
| 423 | 0 |             } | 
| 424 | 0 |         } else { | 
| 425 |  |             // For resolution via proxy | 
| 426 | 0 |             connect_to.push_back(addrConnect); | 
| 427 | 0 |         } | 
| 428 | 0 |     } else { | 
| 429 |  |         // Connect via addrConnect directly | 
| 430 | 0 |         connect_to.push_back(addrConnect); | 
| 431 | 0 |     } | 
| 432 |  |  | 
| 433 |  |     // Connect | 
| 434 | 0 |     std::unique_ptr<Sock> sock; | 
| 435 | 0 |     Proxy proxy; | 
| 436 | 0 |     CService addr_bind; | 
| 437 | 0 |     assert(!addr_bind.IsValid()); | 
| 438 | 0 |     std::unique_ptr<i2p::sam::Session> i2p_transient_session; | 
| 439 |  | 
 | 
| 440 | 0 |     for (auto& target_addr: connect_to) { | 
| 441 | 0 |         if (target_addr.IsValid()) { | 
| 442 | 0 |             const bool use_proxy{GetProxy(target_addr.GetNetwork(), proxy)}; | 
| 443 | 0 |             bool proxyConnectionFailed = false; | 
| 444 |  | 
 | 
| 445 | 0 |             if (target_addr.IsI2P() && use_proxy) { | 
| 446 | 0 |                 i2p::Connection conn; | 
| 447 | 0 |                 bool connected{false}; | 
| 448 |  | 
 | 
| 449 | 0 |                 if (m_i2p_sam_session) { | 
| 450 | 0 |                     connected = m_i2p_sam_session->Connect(target_addr, conn, proxyConnectionFailed); | 
| 451 | 0 |                 } else { | 
| 452 | 0 |                     { | 
| 453 | 0 |                         LOCK(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 454 | 0 |                         if (m_unused_i2p_sessions.empty()) { | 
| 455 | 0 |                             i2p_transient_session = | 
| 456 | 0 |                                 std::make_unique<i2p::sam::Session>(proxy, m_interrupt_net); | 
| 457 | 0 |                         } else { | 
| 458 | 0 |                             i2p_transient_session.swap(m_unused_i2p_sessions.front()); | 
| 459 | 0 |                             m_unused_i2p_sessions.pop(); | 
| 460 | 0 |                         } | 
| 461 | 0 |                     } | 
| 462 | 0 |                     connected = i2p_transient_session->Connect(target_addr, conn, proxyConnectionFailed); | 
| 463 | 0 |                     if (!connected) { | 
| 464 | 0 |                         LOCK(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 465 | 0 |                         if (m_unused_i2p_sessions.size() < MAX_UNUSED_I2P_SESSIONS_SIZE) { | 
| 466 | 0 |                             m_unused_i2p_sessions.emplace(i2p_transient_session.release()); | 
| 467 | 0 |                         } | 
| 468 | 0 |                     } | 
| 469 | 0 |                 } | 
| 470 |  | 
 | 
| 471 | 0 |                 if (connected) { | 
| 472 | 0 |                     sock = std::move(conn.sock); | 
| 473 | 0 |                     addr_bind = conn.me; | 
| 474 | 0 |                 } | 
| 475 | 0 |             } else if (use_proxy) { | 
| 476 | 0 |                 LogPrintLevel(BCLog::PROXY, BCLog::Level::Debug, "Using proxy: %s to connect to %s\n", proxy.ToString(), target_addr.ToStringAddrPort()); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 477 | 0 |                 sock = ConnectThroughProxy(proxy, target_addr.ToStringAddr(), target_addr.GetPort(), proxyConnectionFailed); | 
| 478 | 0 |             } else { | 
| 479 |  |                 // no proxy needed (none set for target network) | 
| 480 | 0 |                 sock = ConnectDirectly(target_addr, conn_type == ConnectionType::MANUAL); | 
| 481 | 0 |             } | 
| 482 | 0 |             if (!proxyConnectionFailed) { | 
| 483 |  |                 // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to | 
| 484 |  |                 // the proxy, mark this as an attempt. | 
| 485 | 0 |                 addrman.Attempt(target_addr, fCountFailure); | 
| 486 | 0 |             } | 
| 487 | 0 |         } else if (pszDest && GetNameProxy(proxy)) { | 
| 488 | 0 |             std::string host; | 
| 489 | 0 |             uint16_t port{default_port}; | 
| 490 | 0 |             SplitHostPort(std::string(pszDest), port, host); | 
| 491 | 0 |             bool proxyConnectionFailed; | 
| 492 | 0 |             sock = ConnectThroughProxy(proxy, host, port, proxyConnectionFailed); | 
| 493 | 0 |         } | 
| 494 |  |         // Check any other resolved address (if any) if we fail to connect | 
| 495 | 0 |         if (!sock) { | 
| 496 | 0 |             continue; | 
| 497 | 0 |         } | 
| 498 |  |  | 
| 499 | 0 |         NetPermissionFlags permission_flags = NetPermissionFlags::None; | 
| 500 | 0 |         std::vector<NetWhitelistPermissions> whitelist_permissions = conn_type == ConnectionType::MANUAL ? vWhitelistedRangeOutgoing : std::vector<NetWhitelistPermissions>{}; | 
| 501 | 0 |         AddWhitelistPermissionFlags(permission_flags, target_addr, whitelist_permissions); | 
| 502 |  |  | 
| 503 |  |         // Add node | 
| 504 | 0 |         NodeId id = GetNewNodeId(); | 
| 505 | 0 |         uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); | 
| 506 | 0 |         if (!addr_bind.IsValid()) { | 
| 507 | 0 |             addr_bind = GetBindAddress(*sock); | 
| 508 | 0 |         } | 
| 509 | 0 |         CNode* pnode = new CNode(id, | 
| 510 | 0 |                                 std::move(sock), | 
| 511 | 0 |                                 target_addr, | 
| 512 | 0 |                                 CalculateKeyedNetGroup(target_addr), | 
| 513 | 0 |                                 nonce, | 
| 514 | 0 |                                 addr_bind, | 
| 515 | 0 |                                 pszDest ? pszDest : "", | 
| 516 | 0 |                                 conn_type, | 
| 517 | 0 |                                 /*inbound_onion=*/false, | 
| 518 | 0 |                                 CNodeOptions{ | 
| 519 | 0 |                                     .permission_flags = permission_flags, | 
| 520 | 0 |                                     .i2p_sam_session = std::move(i2p_transient_session), | 
| 521 | 0 |                                     .recv_flood_size = nReceiveFloodSize, | 
| 522 | 0 |                                     .use_v2transport = use_v2transport, | 
| 523 | 0 |                                 }); | 
| 524 | 0 |         pnode->AddRef(); | 
| 525 |  |  | 
| 526 |  |         // We're making a new connection, harvest entropy from the time (and our peer count) | 
| 527 | 0 |         RandAddEvent((uint32_t)id); | 
| 528 |  | 
 | 
| 529 | 0 |         return pnode; | 
| 530 | 0 |     } | 
| 531 |  |  | 
| 532 | 0 |     return nullptr; | 
| 533 | 0 | } | 
| 534 |  |  | 
| 535 |  | void CNode::CloseSocketDisconnect() | 
| 536 | 202k | { | 
| 537 | 202k |     fDisconnect = true; | 
| 538 | 202k |     LOCK(m_sock_mutex); | Line | Count | Source |  | 259 | 202k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 202k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 202k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 202k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 539 | 202k |     if (m_sock) { | 
| 540 | 192k |         LogDebug(BCLog::NET, "Resetting socket for peer=%d%s", GetId(), LogIP(fLogIPs)); | Line | Count | Source |  | 381 | 192k | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 192k |     do {                                                              \ |  | 374 | 192k |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 192k |     } while (0) | 
 | 
 | 
| 541 | 192k |         m_sock.reset(); | 
| 542 |  |  | 
| 543 | 192k |         TRACEPOINT(net, closed_connection, | 
| 544 | 192k |             GetId(), | 
| 545 | 192k |             m_addr_name.c_str(), | 
| 546 | 192k |             ConnectionTypeAsString().c_str(), | 
| 547 | 192k |             ConnectedThroughNetwork(), | 
| 548 | 192k |             Ticks<std::chrono::seconds>(m_connected)); | 
| 549 | 192k |     } | 
| 550 | 202k |     m_i2p_sam_session.reset(); | 
| 551 | 202k | } | 
| 552 |  |  | 
| 553 | 0 | void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr, const std::vector<NetWhitelistPermissions>& ranges) const { | 
| 554 | 0 |     for (const auto& subnet : ranges) { | 
| 555 | 0 |         if (addr.has_value() && subnet.m_subnet.Match(addr.value())) { | 
| 556 | 0 |             NetPermissions::AddFlag(flags, subnet.m_flags); | 
| 557 | 0 |         } | 
| 558 | 0 |     } | 
| 559 | 0 |     if (NetPermissions::HasFlag(flags, NetPermissionFlags::Implicit)) { | 
| 560 | 0 |         NetPermissions::ClearFlag(flags, NetPermissionFlags::Implicit); | 
| 561 | 0 |         if (whitelist_forcerelay) NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay); | 
| 562 | 0 |         if (whitelist_relay) NetPermissions::AddFlag(flags, NetPermissionFlags::Relay); | 
| 563 | 0 |         NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool); | 
| 564 | 0 |         NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan); | 
| 565 | 0 |     } | 
| 566 | 0 | } | 
| 567 |  |  | 
| 568 |  | CService CNode::GetAddrLocal() const | 
| 569 | 2.02k | { | 
| 570 | 2.02k |     AssertLockNotHeld(m_addr_local_mutex); | Line | Count | Source |  | 142 | 2.02k | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 571 | 2.02k |     LOCK(m_addr_local_mutex); | Line | Count | Source |  | 259 | 2.02k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 2.02k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 2.02k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 2.02k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 572 | 2.02k |     return m_addr_local; | 
| 573 | 2.02k | } | 
| 574 |  |  | 
| 575 | 190k | void CNode::SetAddrLocal(const CService& addrLocalIn) { | 
| 576 | 190k |     AssertLockNotHeld(m_addr_local_mutex); | Line | Count | Source |  | 142 | 190k | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 577 | 190k |     LOCK(m_addr_local_mutex); | Line | Count | Source |  | 259 | 190k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 190k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 190k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 190k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 578 | 190k |     if (Assume(!m_addr_local.IsValid())) { // Addr local can only be set once during version msg processing| Line | Count | Source |  | 118 | 190k | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 579 | 190k |         m_addr_local = addrLocalIn; | 
| 580 | 190k |     } | 
| 581 | 190k | } | 
| 582 |  |  | 
| 583 |  | Network CNode::ConnectedThroughNetwork() const | 
| 584 | 0 | { | 
| 585 | 0 |     return m_inbound_onion ? NET_ONION : addr.GetNetClass(); | 
| 586 | 0 | } | 
| 587 |  |  | 
| 588 |  | bool CNode::IsConnectedThroughPrivacyNet() const | 
| 589 | 0 | { | 
| 590 | 0 |     return m_inbound_onion || addr.IsPrivacyNet(); | 
| 591 | 0 | } | 
| 592 |  |  | 
| 593 |  | #undef X | 
| 594 | 0 | #define X(name) stats.name = name | 
| 595 |  | void CNode::CopyStats(CNodeStats& stats) | 
| 596 | 0 | { | 
| 597 | 0 |     stats.nodeid = this->GetId(); | 
| 598 | 0 |     X(addr); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 599 | 0 |     X(addrBind); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 600 | 0 |     stats.m_network = ConnectedThroughNetwork(); | 
| 601 | 0 |     X(m_last_send); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 602 | 0 |     X(m_last_recv); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 603 | 0 |     X(m_last_tx_time); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 604 | 0 |     X(m_last_block_time); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 605 | 0 |     X(m_connected); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 606 | 0 |     X(m_addr_name); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 607 | 0 |     X(nVersion); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 608 | 0 |     { | 
| 609 | 0 |         LOCK(m_subver_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 610 | 0 |         X(cleanSubVer); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 611 | 0 |     } | 
| 612 | 0 |     stats.fInbound = IsInboundConn(); | 
| 613 | 0 |     X(m_bip152_highbandwidth_to); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 614 | 0 |     X(m_bip152_highbandwidth_from); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 615 | 0 |     { | 
| 616 | 0 |         LOCK(cs_vSend); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 617 | 0 |         X(mapSendBytesPerMsgType); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 618 | 0 |         X(nSendBytes); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 619 | 0 |     } | 
| 620 | 0 |     { | 
| 621 | 0 |         LOCK(cs_vRecv); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 622 | 0 |         X(mapRecvBytesPerMsgType); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 623 | 0 |         X(nRecvBytes); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 624 | 0 |         Transport::Info info = m_transport->GetInfo(); | 
| 625 | 0 |         stats.m_transport_type = info.transport_type; | 
| 626 | 0 |         if (info.session_id) stats.m_session_id = HexStr(*info.session_id); | 
| 627 | 0 |     } | 
| 628 | 0 |     X(m_permission_flags); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 629 |  | 
 | 
| 630 | 0 |     X(m_last_ping_time); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 631 | 0 |     X(m_min_ping_time); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 632 |  |  | 
| 633 |  |     // Leave string empty if addrLocal invalid (not filled in yet) | 
| 634 | 0 |     CService addrLocalUnlocked = GetAddrLocal(); | 
| 635 | 0 |     stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToStringAddrPort() : ""; | 
| 636 |  | 
 | 
| 637 | 0 |     X(m_conn_type); | Line | Count | Source |  | 594 | 0 | #define X(name) stats.name = name | 
 | 
| 638 | 0 | } | 
| 639 |  | #undef X | 
| 640 |  |  | 
| 641 |  | bool CNode::ReceiveMsgBytes(std::span<const uint8_t> msg_bytes, bool& complete) | 
| 642 | 13.5M | { | 
| 643 | 13.5M |     complete = false; | 
| 644 | 13.5M |     const auto time = GetTime<std::chrono::microseconds>(); | 
| 645 | 13.5M |     LOCK(cs_vRecv); | Line | Count | Source |  | 259 | 13.5M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 13.5M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 13.5M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 13.5M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 646 | 13.5M |     m_last_recv = std::chrono::duration_cast<std::chrono::seconds>(time); | 
| 647 | 13.5M |     nRecvBytes += msg_bytes.size(); | 
| 648 | 27.1M |     while (msg_bytes.size() > 0) { | 
| 649 |  |         // absorb network data | 
| 650 | 13.5M |         if (!m_transport->ReceivedBytes(msg_bytes)) { | 
| 651 |  |             // Serious transport problem, disconnect from the peer. | 
| 652 | 0 |             return false; | 
| 653 | 0 |         } | 
| 654 |  |  | 
| 655 | 13.5M |         if (m_transport->ReceivedMessageComplete()) { | 
| 656 |  |             // decompose a transport agnostic CNetMessage from the deserializer | 
| 657 | 6.84M |             bool reject_message{false}; | 
| 658 | 6.84M |             CNetMessage msg = m_transport->GetReceivedMessage(time, reject_message); | 
| 659 | 6.84M |             if (reject_message) { | 
| 660 |  |                 // Message deserialization failed. Drop the message but don't disconnect the peer. | 
| 661 |  |                 // store the size of the corrupt message | 
| 662 | 0 |                 mapRecvBytesPerMsgType.at(NET_MESSAGE_TYPE_OTHER) += msg.m_raw_message_size; | 
| 663 | 0 |                 continue; | 
| 664 | 0 |             } | 
| 665 |  |  | 
| 666 |  |             // Store received bytes per message type. | 
| 667 |  |             // To prevent a memory DOS, only allow known message types. | 
| 668 | 6.84M |             auto i = mapRecvBytesPerMsgType.find(msg.m_type); | 
| 669 | 6.84M |             if (i == mapRecvBytesPerMsgType.end()) { | 
| 670 | 0 |                 i = mapRecvBytesPerMsgType.find(NET_MESSAGE_TYPE_OTHER); | 
| 671 | 0 |             } | 
| 672 | 6.84M |             assert(i != mapRecvBytesPerMsgType.end()); | 
| 673 | 6.84M |             i->second += msg.m_raw_message_size; | 
| 674 |  |  | 
| 675 |  |             // push the message to the process queue, | 
| 676 | 6.84M |             vRecvMsg.push_back(std::move(msg)); | 
| 677 |  |  | 
| 678 | 6.84M |             complete = true; | 
| 679 | 6.84M |         } | 
| 680 | 13.5M |     } | 
| 681 |  |  | 
| 682 | 13.5M |     return true; | 
| 683 | 13.5M | } | 
| 684 |  |  | 
| 685 |  | std::string CNode::LogIP(bool log_ip) const | 
| 686 | 115k | { | 
| 687 | 115k |     return log_ip ? strprintf0 (" peeraddr=%s", addr.ToStringAddrPort())0: ""; | Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 688 | 115k | } | 
| 689 |  |  | 
| 690 |  | std::string CNode::DisconnectMsg(bool log_ip) const | 
| 691 | 1.59k | { | 
| 692 | 1.59k |     return strprintf("disconnecting peer=%d%s",| Line | Count | Source |  | 1172 | 1.59k | #define strprintf tfm::format | 
 | 
| 693 | 1.59k |                      GetId(), | 
| 694 | 1.59k |                      LogIP(log_ip)); | 
| 695 | 1.59k | } | 
| 696 |  |  | 
| 697 |  | V1Transport::V1Transport(const NodeId node_id) noexcept | 
| 698 | 192k |     : m_magic_bytes{Params().MessageStart()}, m_node_id{node_id} | 
| 699 | 192k | { | 
| 700 | 192k |     LOCK(m_recv_mutex); | Line | Count | Source |  | 259 | 192k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 192k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 192k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 192k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 701 | 192k |     Reset(); | 
| 702 | 192k | } | 
| 703 |  |  | 
| 704 |  | Transport::Info V1Transport::GetInfo() const noexcept | 
| 705 | 5.59k | { | 
| 706 | 5.59k |     return {.transport_type = TransportProtocolType::V1, .session_id = {}}; | 
| 707 | 5.59k | } | 
| 708 |  |  | 
| 709 |  | int V1Transport::readHeader(std::span<const uint8_t> msg_bytes) | 
| 710 | 6.84M | { | 
| 711 | 6.84M |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 6.84M | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 712 |  |     // copy data to temporary parsing buffer | 
| 713 | 6.84M |     unsigned int nRemaining = CMessageHeader::HEADER_SIZE - nHdrPos; | 
| 714 | 6.84M |     unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size()); | 
| 715 |  |  | 
| 716 | 6.84M |     memcpy(&hdrbuf[nHdrPos], msg_bytes.data(), nCopy); | 
| 717 | 6.84M |     nHdrPos += nCopy; | 
| 718 |  |  | 
| 719 |  |     // if header incomplete, exit | 
| 720 | 6.84M |     if (nHdrPos < CMessageHeader::HEADER_SIZE) | 
| 721 | 0 |         return nCopy; | 
| 722 |  |  | 
| 723 |  |     // deserialize to CMessageHeader | 
| 724 | 6.84M |     try { | 
| 725 | 6.84M |         hdrbuf >> hdr; | 
| 726 | 6.84M |     } | 
| 727 | 6.84M |     catch (const std::exception&) { | 
| 728 | 0 |         LogDebug(BCLog::NET, "Header error: Unable to deserialize, peer=%d\n", m_node_id); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 729 | 0 |         return -1; | 
| 730 | 0 |     } | 
| 731 |  |  | 
| 732 |  |     // Check start string, network magic | 
| 733 | 6.84M |     if (hdr.pchMessageStart != m_magic_bytes) { | 
| 734 | 0 |         LogDebug(BCLog::NET, "Header error: Wrong MessageStart %s received, peer=%d\n", HexStr(hdr.pchMessageStart), m_node_id); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 735 | 0 |         return -1; | 
| 736 | 0 |     } | 
| 737 |  |  | 
| 738 |  |     // reject messages larger than MAX_SIZE or MAX_PROTOCOL_MESSAGE_LENGTH | 
| 739 |  |     // NOTE: failing to perform this check previously allowed a malicious peer to make us allocate 32MiB of memory per | 
| 740 |  |     // connection. See https://bitcoincore.org/en/2024/07/03/disclose_receive_buffer_oom. | 
| 741 | 6.84M |     if (hdr.nMessageSize > MAX_SIZE || hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) { | 
| 742 | 0 |         LogDebug(BCLog::NET, "Header error: Size too large (%s, %u bytes), peer=%d\n", SanitizeString(hdr.GetMessageType()), hdr.nMessageSize, m_node_id); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 743 | 0 |         return -1; | 
| 744 | 0 |     } | 
| 745 |  |  | 
| 746 |  |     // switch state to reading message data | 
| 747 | 6.84M |     in_data = true; | 
| 748 |  |  | 
| 749 | 6.84M |     return nCopy; | 
| 750 | 6.84M | } | 
| 751 |  |  | 
| 752 |  | int V1Transport::readData(std::span<const uint8_t> msg_bytes) | 
| 753 | 6.73M | { | 
| 754 | 6.73M |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 6.73M | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 755 | 6.73M |     unsigned int nRemaining = hdr.nMessageSize - nDataPos; | 
| 756 | 6.73M |     unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size()); | 
| 757 |  |  | 
| 758 | 6.73M |     if (vRecv.size() < nDataPos + nCopy) { | 
| 759 |  |         // Allocate up to 256 KiB ahead, but never more than the total message size. | 
| 760 | 6.73M |         vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024)); | 
| 761 | 6.73M |     } | 
| 762 |  |  | 
| 763 | 6.73M |     hasher.Write(msg_bytes.first(nCopy)); | 
| 764 | 6.73M |     memcpy(&vRecv[nDataPos], msg_bytes.data(), nCopy); | 
| 765 | 6.73M |     nDataPos += nCopy; | 
| 766 |  |  | 
| 767 | 6.73M |     return nCopy; | 
| 768 | 6.73M | } | 
| 769 |  |  | 
| 770 |  | const uint256& V1Transport::GetMessageHash() const | 
| 771 | 6.84M | { | 
| 772 | 6.84M |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 6.84M | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 773 | 6.84M |     assert(CompleteInternal()); | 
| 774 | 6.84M |     if (data_hash.IsNull()) | 
| 775 | 6.84M |         hasher.Finalize(data_hash); | 
| 776 | 6.84M |     return data_hash; | 
| 777 | 6.84M | } | 
| 778 |  |  | 
| 779 |  | CNetMessage V1Transport::GetReceivedMessage(const std::chrono::microseconds time, bool& reject_message) | 
| 780 | 6.84M | { | 
| 781 | 6.84M |     AssertLockNotHeld(m_recv_mutex); | Line | Count | Source |  | 142 | 6.84M | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 782 |  |     // Initialize out parameter | 
| 783 | 6.84M |     reject_message = false; | 
| 784 |  |     // decompose a single CNetMessage from the TransportDeserializer | 
| 785 | 6.84M |     LOCK(m_recv_mutex); | Line | Count | Source |  | 259 | 6.84M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 6.84M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 6.84M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 6.84M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 786 | 6.84M |     CNetMessage msg(std::move(vRecv)); | 
| 787 |  |  | 
| 788 |  |     // store message type string, time, and sizes | 
| 789 | 6.84M |     msg.m_type = hdr.GetMessageType(); | 
| 790 | 6.84M |     msg.m_time = time; | 
| 791 | 6.84M |     msg.m_message_size = hdr.nMessageSize; | 
| 792 | 6.84M |     msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE; | 
| 793 |  |  | 
| 794 | 6.84M |     uint256 hash = GetMessageHash(); | 
| 795 |  |  | 
| 796 |  |     // We just received a message off the wire, harvest entropy from the time (and the message checksum) | 
| 797 | 6.84M |     RandAddEvent(ReadLE32(hash.begin())); | 
| 798 |  |  | 
| 799 |  |     // Check checksum and header message type string | 
| 800 | 6.84M |     if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) { | 
| 801 | 0 |         LogDebug(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n", | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 802 | 0 |                  SanitizeString(msg.m_type), msg.m_message_size, | 
| 803 | 0 |                  HexStr(std::span{hash}.first(CMessageHeader::CHECKSUM_SIZE)), | 
| 804 | 0 |                  HexStr(hdr.pchChecksum), | 
| 805 | 0 |                  m_node_id); | 
| 806 | 0 |         reject_message = true; | 
| 807 | 6.84M |     } else if (!hdr.IsMessageTypeValid()) { | 
| 808 | 0 |         LogDebug(BCLog::NET, "Header error: Invalid message type (%s, %u bytes), peer=%d\n", | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 809 | 0 |                  SanitizeString(hdr.GetMessageType()), msg.m_message_size, m_node_id); | 
| 810 | 0 |         reject_message = true; | 
| 811 | 0 |     } | 
| 812 |  |  | 
| 813 |  |     // Always reset the network deserializer (prepare for the next message) | 
| 814 | 6.84M |     Reset(); | 
| 815 | 6.84M |     return msg; | 
| 816 | 6.84M | } | 
| 817 |  |  | 
| 818 |  | bool V1Transport::SetMessageToSend(CSerializedNetMsg& msg) noexcept | 
| 819 | 8.05M | { | 
| 820 | 8.05M |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 8.05M | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 821 |  |     // Determine whether a new message can be set. | 
| 822 | 8.05M |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 8.05M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 8.05M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 8.05M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 8.05M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 823 | 8.05M |     if (m_sending_header || m_bytes_sent < m_message_to_send.data.size()) return false0; | 
| 824 |  |  | 
| 825 |  |     // create dbl-sha256 checksum | 
| 826 | 8.05M |     uint256 hash = Hash(msg.data); | 
| 827 |  |  | 
| 828 |  |     // create header | 
| 829 | 8.05M |     CMessageHeader hdr(m_magic_bytes, msg.m_type.c_str(), msg.data.size()); | 
| 830 | 8.05M |     memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE); | 
| 831 |  |  | 
| 832 |  |     // serialize header | 
| 833 | 8.05M |     m_header_to_send.clear(); | 
| 834 | 8.05M |     VectorWriter{m_header_to_send, 0, hdr}; | 
| 835 |  |  | 
| 836 |  |     // update state | 
| 837 | 8.05M |     m_message_to_send = std::move(msg); | 
| 838 | 8.05M |     m_sending_header = true; | 
| 839 | 8.05M |     m_bytes_sent = 0; | 
| 840 | 8.05M |     return true; | 
| 841 | 8.05M | } | 
| 842 |  |  | 
| 843 |  | Transport::BytesToSend V1Transport::GetBytesToSend(bool have_next_message) const noexcept | 
| 844 | 32.3M | { | 
| 845 | 32.3M |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 32.3M | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 846 | 32.3M |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 32.3M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 32.3M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 32.3M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 32.3M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 847 | 32.3M |     if (m_sending_header) { | 
| 848 | 8.77M |         return {std::span{m_header_to_send}.subspan(m_bytes_sent), | 
| 849 |  |                 // We have more to send after the header if the message has payload, or if there | 
| 850 |  |                 // is a next message after that. | 
| 851 | 8.77M |                 have_next_message || !m_message_to_send.data.empty()8.29M, | 
| 852 | 8.77M |                 m_message_to_send.m_type | 
| 853 | 8.77M |                }; | 
| 854 | 23.5M |     } else { | 
| 855 | 23.5M |         return {std::span{m_message_to_send.data}.subspan(m_bytes_sent), | 
| 856 |  |                 // We only have more to send after this message's payload if there is another | 
| 857 |  |                 // message. | 
| 858 | 23.5M |                 have_next_message, | 
| 859 | 23.5M |                 m_message_to_send.m_type | 
| 860 | 23.5M |                }; | 
| 861 | 23.5M |     } | 
| 862 | 32.3M | } | 
| 863 |  |  | 
| 864 |  | void V1Transport::MarkBytesSent(size_t bytes_sent) noexcept | 
| 865 | 15.9M | { | 
| 866 | 15.9M |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 15.9M | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 867 | 15.9M |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 15.9M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 15.9M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 15.9M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 15.9M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 868 | 15.9M |     m_bytes_sent += bytes_sent; | 
| 869 | 15.9M |     if (m_sending_header && m_bytes_sent == m_header_to_send.size()8.28M) { | 
| 870 |  |         // We're done sending a message's header. Switch to sending its data bytes. | 
| 871 | 8.02M |         m_sending_header = false; | 
| 872 | 8.02M |         m_bytes_sent = 0; | 
| 873 | 8.02M |     } else if (7.93M !m_sending_header7.93M&& m_bytes_sent == m_message_to_send.data.size()7.67M) { | 
| 874 |  |         // We're done sending a message's data. Wipe the data vector to reduce memory consumption. | 
| 875 | 7.65M |         ClearShrink(m_message_to_send.data); | 
| 876 | 7.65M |         m_bytes_sent = 0; | 
| 877 | 7.65M |     } | 
| 878 | 15.9M | } | 
| 879 |  |  | 
| 880 |  | size_t V1Transport::GetSendMemoryUsage() const noexcept | 
| 881 | 2.92M | { | 
| 882 | 2.92M |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 2.92M | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 883 | 2.92M |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 2.92M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 2.92M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 2.92M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 2.92M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 884 |  |     // Don't count sending-side fields besides m_message_to_send, as they're all small and bounded. | 
| 885 | 2.92M |     return m_message_to_send.GetMemoryUsage(); | 
| 886 | 2.92M | } | 
| 887 |  |  | 
| 888 |  | namespace { | 
| 889 |  |  | 
| 890 |  | /** List of short messages as defined in BIP324, in order. | 
| 891 |  |  * | 
| 892 |  |  * Only message types that are actually implemented in this codebase need to be listed, as other | 
| 893 |  |  * messages get ignored anyway - whether we know how to decode them or not. | 
| 894 |  |  */ | 
| 895 |  | const std::array<std::string, 33> V2_MESSAGE_IDS = { | 
| 896 |  |     "", // 12 bytes follow encoding the message type like in V1 | 
| 897 |  |     NetMsgType::ADDR, | 
| 898 |  |     NetMsgType::BLOCK, | 
| 899 |  |     NetMsgType::BLOCKTXN, | 
| 900 |  |     NetMsgType::CMPCTBLOCK, | 
| 901 |  |     NetMsgType::FEEFILTER, | 
| 902 |  |     NetMsgType::FILTERADD, | 
| 903 |  |     NetMsgType::FILTERCLEAR, | 
| 904 |  |     NetMsgType::FILTERLOAD, | 
| 905 |  |     NetMsgType::GETBLOCKS, | 
| 906 |  |     NetMsgType::GETBLOCKTXN, | 
| 907 |  |     NetMsgType::GETDATA, | 
| 908 |  |     NetMsgType::GETHEADERS, | 
| 909 |  |     NetMsgType::HEADERS, | 
| 910 |  |     NetMsgType::INV, | 
| 911 |  |     NetMsgType::MEMPOOL, | 
| 912 |  |     NetMsgType::MERKLEBLOCK, | 
| 913 |  |     NetMsgType::NOTFOUND, | 
| 914 |  |     NetMsgType::PING, | 
| 915 |  |     NetMsgType::PONG, | 
| 916 |  |     NetMsgType::SENDCMPCT, | 
| 917 |  |     NetMsgType::TX, | 
| 918 |  |     NetMsgType::GETCFILTERS, | 
| 919 |  |     NetMsgType::CFILTER, | 
| 920 |  |     NetMsgType::GETCFHEADERS, | 
| 921 |  |     NetMsgType::CFHEADERS, | 
| 922 |  |     NetMsgType::GETCFCHECKPT, | 
| 923 |  |     NetMsgType::CFCHECKPT, | 
| 924 |  |     NetMsgType::ADDRV2, | 
| 925 |  |     // Unimplemented message types that are assigned in BIP324: | 
| 926 |  |     "", | 
| 927 |  |     "", | 
| 928 |  |     "", | 
| 929 |  |     "" | 
| 930 |  | }; | 
| 931 |  |  | 
| 932 |  | class V2MessageMap | 
| 933 |  | { | 
| 934 |  |     std::unordered_map<std::string, uint8_t> m_map; | 
| 935 |  |  | 
| 936 |  | public: | 
| 937 |  |     V2MessageMap() noexcept | 
| 938 | 0 |     { | 
| 939 | 0 |         for (size_t i = 1; i < std::size(V2_MESSAGE_IDS); ++i) { | 
| 940 | 0 |             m_map.emplace(V2_MESSAGE_IDS[i], i); | 
| 941 | 0 |         } | 
| 942 | 0 |     } | 
| 943 |  |  | 
| 944 |  |     std::optional<uint8_t> operator()(const std::string& message_name) const noexcept | 
| 945 | 0 |     { | 
| 946 | 0 |         auto it = m_map.find(message_name); | 
| 947 | 0 |         if (it == m_map.end()) return std::nullopt; | 
| 948 | 0 |         return it->second; | 
| 949 | 0 |     } | 
| 950 |  | }; | 
| 951 |  |  | 
| 952 |  | const V2MessageMap V2_MESSAGE_MAP; | 
| 953 |  |  | 
| 954 |  | std::vector<uint8_t> GenerateRandomGarbage() noexcept | 
| 955 | 0 | { | 
| 956 | 0 |     std::vector<uint8_t> ret; | 
| 957 | 0 |     FastRandomContext rng; | 
| 958 | 0 |     ret.resize(rng.randrange(V2Transport::MAX_GARBAGE_LEN + 1)); | 
| 959 | 0 |     rng.fillrand(MakeWritableByteSpan(ret)); | 
| 960 | 0 |     return ret; | 
| 961 | 0 | } | 
| 962 |  |  | 
| 963 |  | } // namespace | 
| 964 |  |  | 
| 965 |  | void V2Transport::StartSendingHandshake() noexcept | 
| 966 | 0 | { | 
| 967 | 0 |     AssertLockHeld(m_send_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 968 | 0 |     Assume(m_send_state == SendState::AWAITING_KEY); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 969 | 0 |     Assume(m_send_buffer.empty()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 970 |  |     // Initialize the send buffer with ellswift pubkey + provided garbage. | 
| 971 | 0 |     m_send_buffer.resize(EllSwiftPubKey::size() + m_send_garbage.size()); | 
| 972 | 0 |     std::copy(std::begin(m_cipher.GetOurPubKey()), std::end(m_cipher.GetOurPubKey()), MakeWritableByteSpan(m_send_buffer).begin()); | 
| 973 | 0 |     std::copy(m_send_garbage.begin(), m_send_garbage.end(), m_send_buffer.begin() + EllSwiftPubKey::size()); | 
| 974 |  |     // We cannot wipe m_send_garbage as it will still be used as AAD later in the handshake. | 
| 975 | 0 | } | 
| 976 |  |  | 
| 977 |  | V2Transport::V2Transport(NodeId nodeid, bool initiating, const CKey& key, std::span<const std::byte> ent32, std::vector<uint8_t> garbage) noexcept | 
| 978 | 0 |     : m_cipher{key, ent32}, m_initiating{initiating}, m_nodeid{nodeid}, | 
| 979 | 0 |       m_v1_fallback{nodeid}, | 
| 980 | 0 |       m_recv_state{initiating ? RecvState::KEY : RecvState::KEY_MAYBE_V1}, | 
| 981 | 0 |       m_send_garbage{std::move(garbage)}, | 
| 982 | 0 |       m_send_state{initiating ? SendState::AWAITING_KEY : SendState::MAYBE_V1} | 
| 983 | 0 | { | 
| 984 | 0 |     Assume(m_send_garbage.size() <= MAX_GARBAGE_LEN); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 985 |  |     // Start sending immediately if we're the initiator of the connection. | 
| 986 | 0 |     if (initiating) { | 
| 987 | 0 |         LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 988 | 0 |         StartSendingHandshake(); | 
| 989 | 0 |     } | 
| 990 | 0 | } | 
| 991 |  |  | 
| 992 |  | V2Transport::V2Transport(NodeId nodeid, bool initiating) noexcept | 
| 993 | 0 |     : V2Transport{nodeid, initiating, GenerateRandomKey(), | 
| 994 | 0 |                   MakeByteSpan(GetRandHash()), GenerateRandomGarbage()} {}Unexecuted instantiation: _ZN11V2TransportC2ExbUnexecuted instantiation: _ZN11V2TransportC1Exb | 
| 995 |  |  | 
| 996 |  | void V2Transport::SetReceiveState(RecvState recv_state) noexcept | 
| 997 | 0 | { | 
| 998 | 0 |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 999 |  |     // Enforce allowed state transitions. | 
| 1000 | 0 |     switch (m_recv_state) { | 
| 1001 | 0 |     case RecvState::KEY_MAYBE_V1: | 
| 1002 | 0 |         Assume(recv_state == RecvState::KEY || recv_state == RecvState::V1); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1003 | 0 |         break; | 
| 1004 | 0 |     case RecvState::KEY: | 
| 1005 | 0 |         Assume(recv_state == RecvState::GARB_GARBTERM); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1006 | 0 |         break; | 
| 1007 | 0 |     case RecvState::GARB_GARBTERM: | 
| 1008 | 0 |         Assume(recv_state == RecvState::VERSION); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1009 | 0 |         break; | 
| 1010 | 0 |     case RecvState::VERSION: | 
| 1011 | 0 |         Assume(recv_state == RecvState::APP); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1012 | 0 |         break; | 
| 1013 | 0 |     case RecvState::APP: | 
| 1014 | 0 |         Assume(recv_state == RecvState::APP_READY); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1015 | 0 |         break; | 
| 1016 | 0 |     case RecvState::APP_READY: | 
| 1017 | 0 |         Assume(recv_state == RecvState::APP); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1018 | 0 |         break; | 
| 1019 | 0 |     case RecvState::V1: | 
| 1020 | 0 |         Assume(false); // V1 state cannot be left | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1021 | 0 |         break; | 
| 1022 | 0 |     } | 
| 1023 |  |     // Change state. | 
| 1024 | 0 |     m_recv_state = recv_state; | 
| 1025 | 0 | } | 
| 1026 |  |  | 
| 1027 |  | void V2Transport::SetSendState(SendState send_state) noexcept | 
| 1028 | 0 | { | 
| 1029 | 0 |     AssertLockHeld(m_send_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1030 |  |     // Enforce allowed state transitions. | 
| 1031 | 0 |     switch (m_send_state) { | 
| 1032 | 0 |     case SendState::MAYBE_V1: | 
| 1033 | 0 |         Assume(send_state == SendState::V1 || send_state == SendState::AWAITING_KEY); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1034 | 0 |         break; | 
| 1035 | 0 |     case SendState::AWAITING_KEY: | 
| 1036 | 0 |         Assume(send_state == SendState::READY); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1037 | 0 |         break; | 
| 1038 | 0 |     case SendState::READY: | 
| 1039 | 0 |     case SendState::V1: | 
| 1040 | 0 |         Assume(false); // Final states | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1041 | 0 |         break; | 
| 1042 | 0 |     } | 
| 1043 |  |     // Change state. | 
| 1044 | 0 |     m_send_state = send_state; | 
| 1045 | 0 | } | 
| 1046 |  |  | 
| 1047 |  | bool V2Transport::ReceivedMessageComplete() const noexcept | 
| 1048 | 0 | { | 
| 1049 | 0 |     AssertLockNotHeld(m_recv_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1050 | 0 |     LOCK(m_recv_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1051 | 0 |     if (m_recv_state == RecvState::V1) return m_v1_fallback.ReceivedMessageComplete(); | 
| 1052 |  |  | 
| 1053 | 0 |     return m_recv_state == RecvState::APP_READY; | 
| 1054 | 0 | } | 
| 1055 |  |  | 
| 1056 |  | void V2Transport::ProcessReceivedMaybeV1Bytes() noexcept | 
| 1057 | 0 | { | 
| 1058 | 0 |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1059 | 0 |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1060 | 0 |     Assume(m_recv_state == RecvState::KEY_MAYBE_V1); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1061 |  |     // We still have to determine if this is a v1 or v2 connection. The bytes being received could | 
| 1062 |  |     // be the beginning of either a v1 packet (network magic + "version\x00\x00\x00\x00\x00"), or | 
| 1063 |  |     // of a v2 public key. BIP324 specifies that a mismatch with this 16-byte string should trigger | 
| 1064 |  |     // sending of the key. | 
| 1065 | 0 |     std::array<uint8_t, V1_PREFIX_LEN> v1_prefix = {0, 0, 0, 0, 'v', 'e', 'r', 's', 'i', 'o', 'n', 0, 0, 0, 0, 0}; | 
| 1066 | 0 |     std::copy(std::begin(Params().MessageStart()), std::end(Params().MessageStart()), v1_prefix.begin()); | 
| 1067 | 0 |     Assume(m_recv_buffer.size() <= v1_prefix.size()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1068 | 0 |     if (!std::equal(m_recv_buffer.begin(), m_recv_buffer.end(), v1_prefix.begin())) { | 
| 1069 |  |         // Mismatch with v1 prefix, so we can assume a v2 connection. | 
| 1070 | 0 |         SetReceiveState(RecvState::KEY); // Convert to KEY state, leaving received bytes around. | 
| 1071 |  |         // Transition the sender to AWAITING_KEY state and start sending. | 
| 1072 | 0 |         LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1073 | 0 |         SetSendState(SendState::AWAITING_KEY); | 
| 1074 | 0 |         StartSendingHandshake(); | 
| 1075 | 0 |     } else if (m_recv_buffer.size() == v1_prefix.size()) { | 
| 1076 |  |         // Full match with the v1 prefix, so fall back to v1 behavior. | 
| 1077 | 0 |         LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1078 | 0 |         std::span<const uint8_t> feedback{m_recv_buffer}; | 
| 1079 |  |         // Feed already received bytes to v1 transport. It should always accept these, because it's | 
| 1080 |  |         // less than the size of a v1 header, and these are the first bytes fed to m_v1_fallback. | 
| 1081 | 0 |         bool ret = m_v1_fallback.ReceivedBytes(feedback); | 
| 1082 | 0 |         Assume(feedback.empty()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1083 | 0 |         Assume(ret); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1084 | 0 |         SetReceiveState(RecvState::V1); | 
| 1085 | 0 |         SetSendState(SendState::V1); | 
| 1086 |  |         // Reset v2 transport buffers to save memory. | 
| 1087 | 0 |         ClearShrink(m_recv_buffer); | 
| 1088 | 0 |         ClearShrink(m_send_buffer); | 
| 1089 | 0 |     } else { | 
| 1090 |  |         // We have not received enough to distinguish v1 from v2 yet. Wait until more bytes come. | 
| 1091 | 0 |     } | 
| 1092 | 0 | } | 
| 1093 |  |  | 
| 1094 |  | bool V2Transport::ProcessReceivedKeyBytes() noexcept | 
| 1095 | 0 | { | 
| 1096 | 0 |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1097 | 0 |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1098 | 0 |     Assume(m_recv_state == RecvState::KEY); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1099 | 0 |     Assume(m_recv_buffer.size() <= EllSwiftPubKey::size()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1100 |  |  | 
| 1101 |  |     // As a special exception, if bytes 4-16 of the key on a responder connection match the | 
| 1102 |  |     // corresponding bytes of a V1 version message, but bytes 0-4 don't match the network magic | 
| 1103 |  |     // (if they did, we'd have switched to V1 state already), assume this is a peer from | 
| 1104 |  |     // another network, and disconnect them. They will almost certainly disconnect us too when | 
| 1105 |  |     // they receive our uniformly random key and garbage, but detecting this case specially | 
| 1106 |  |     // means we can log it. | 
| 1107 | 0 |     static constexpr std::array<uint8_t, 12> MATCH = {'v', 'e', 'r', 's', 'i', 'o', 'n', 0, 0, 0, 0, 0}; | 
| 1108 | 0 |     static constexpr size_t OFFSET = std::tuple_size_v<MessageStartChars>; | 
| 1109 | 0 |     if (!m_initiating && m_recv_buffer.size() >= OFFSET + MATCH.size()) { | 
| 1110 | 0 |         if (std::equal(MATCH.begin(), MATCH.end(), m_recv_buffer.begin() + OFFSET)) { | 
| 1111 | 0 |             LogDebug(BCLog::NET, "V2 transport error: V1 peer with wrong MessageStart %s\n", | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1112 | 0 |                      HexStr(std::span(m_recv_buffer).first(OFFSET))); | 
| 1113 | 0 |             return false; | 
| 1114 | 0 |         } | 
| 1115 | 0 |     } | 
| 1116 |  |  | 
| 1117 | 0 |     if (m_recv_buffer.size() == EllSwiftPubKey::size()) { | 
| 1118 |  |         // Other side's key has been fully received, and can now be Diffie-Hellman combined with | 
| 1119 |  |         // our key to initialize the encryption ciphers. | 
| 1120 |  |  | 
| 1121 |  |         // Initialize the ciphers. | 
| 1122 | 0 |         EllSwiftPubKey ellswift(MakeByteSpan(m_recv_buffer)); | 
| 1123 | 0 |         LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1124 | 0 |         m_cipher.Initialize(ellswift, m_initiating); | 
| 1125 |  |  | 
| 1126 |  |         // Switch receiver state to GARB_GARBTERM. | 
| 1127 | 0 |         SetReceiveState(RecvState::GARB_GARBTERM); | 
| 1128 | 0 |         m_recv_buffer.clear(); | 
| 1129 |  |  | 
| 1130 |  |         // Switch sender state to READY. | 
| 1131 | 0 |         SetSendState(SendState::READY); | 
| 1132 |  |  | 
| 1133 |  |         // Append the garbage terminator to the send buffer. | 
| 1134 | 0 |         m_send_buffer.resize(m_send_buffer.size() + BIP324Cipher::GARBAGE_TERMINATOR_LEN); | 
| 1135 | 0 |         std::copy(m_cipher.GetSendGarbageTerminator().begin(), | 
| 1136 | 0 |                   m_cipher.GetSendGarbageTerminator().end(), | 
| 1137 | 0 |                   MakeWritableByteSpan(m_send_buffer).last(BIP324Cipher::GARBAGE_TERMINATOR_LEN).begin()); | 
| 1138 |  |  | 
| 1139 |  |         // Construct version packet in the send buffer, with the sent garbage data as AAD. | 
| 1140 | 0 |         m_send_buffer.resize(m_send_buffer.size() + BIP324Cipher::EXPANSION + VERSION_CONTENTS.size()); | 
| 1141 | 0 |         m_cipher.Encrypt( | 
| 1142 | 0 |             /*contents=*/VERSION_CONTENTS, | 
| 1143 | 0 |             /*aad=*/MakeByteSpan(m_send_garbage), | 
| 1144 | 0 |             /*ignore=*/false, | 
| 1145 | 0 |             /*output=*/MakeWritableByteSpan(m_send_buffer).last(BIP324Cipher::EXPANSION + VERSION_CONTENTS.size())); | 
| 1146 |  |         // We no longer need the garbage. | 
| 1147 | 0 |         ClearShrink(m_send_garbage); | 
| 1148 | 0 |     } else { | 
| 1149 |  |         // We still have to receive more key bytes. | 
| 1150 | 0 |     } | 
| 1151 | 0 |     return true; | 
| 1152 | 0 | } | 
| 1153 |  |  | 
| 1154 |  | bool V2Transport::ProcessReceivedGarbageBytes() noexcept | 
| 1155 | 0 | { | 
| 1156 | 0 |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1157 | 0 |     Assume(m_recv_state == RecvState::GARB_GARBTERM); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1158 | 0 |     Assume(m_recv_buffer.size() <= MAX_GARBAGE_LEN + BIP324Cipher::GARBAGE_TERMINATOR_LEN); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1159 | 0 |     if (m_recv_buffer.size() >= BIP324Cipher::GARBAGE_TERMINATOR_LEN) { | 
| 1160 | 0 |         if (std::ranges::equal(MakeByteSpan(m_recv_buffer).last(BIP324Cipher::GARBAGE_TERMINATOR_LEN), m_cipher.GetReceiveGarbageTerminator())) { | 
| 1161 |  |             // Garbage terminator received. Store garbage to authenticate it as AAD later. | 
| 1162 | 0 |             m_recv_aad = std::move(m_recv_buffer); | 
| 1163 | 0 |             m_recv_aad.resize(m_recv_aad.size() - BIP324Cipher::GARBAGE_TERMINATOR_LEN); | 
| 1164 | 0 |             m_recv_buffer.clear(); | 
| 1165 | 0 |             SetReceiveState(RecvState::VERSION); | 
| 1166 | 0 |         } else if (m_recv_buffer.size() == MAX_GARBAGE_LEN + BIP324Cipher::GARBAGE_TERMINATOR_LEN) { | 
| 1167 |  |             // We've reached the maximum length for garbage + garbage terminator, and the | 
| 1168 |  |             // terminator still does not match. Abort. | 
| 1169 | 0 |             LogDebug(BCLog::NET, "V2 transport error: missing garbage terminator, peer=%d\n", m_nodeid); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1170 | 0 |             return false; | 
| 1171 | 0 |         } else { | 
| 1172 |  |             // We still need to receive more garbage and/or garbage terminator bytes. | 
| 1173 | 0 |         } | 
| 1174 | 0 |     } else { | 
| 1175 |  |         // We have less than GARBAGE_TERMINATOR_LEN (16) bytes, so we certainly need to receive | 
| 1176 |  |         // more first. | 
| 1177 | 0 |     } | 
| 1178 | 0 |     return true; | 
| 1179 | 0 | } | 
| 1180 |  |  | 
| 1181 |  | bool V2Transport::ProcessReceivedPacketBytes() noexcept | 
| 1182 | 0 | { | 
| 1183 | 0 |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1184 | 0 |     Assume(m_recv_state == RecvState::VERSION || m_recv_state == RecvState::APP); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1185 |  |  | 
| 1186 |  |     // The maximum permitted contents length for a packet, consisting of: | 
| 1187 |  |     // - 0x00 byte: indicating long message type encoding | 
| 1188 |  |     // - 12 bytes of message type | 
| 1189 |  |     // - payload | 
| 1190 | 0 |     static constexpr size_t MAX_CONTENTS_LEN = | 
| 1191 | 0 |         1 + CMessageHeader::MESSAGE_TYPE_SIZE + | 
| 1192 | 0 |         std::min<size_t>(MAX_SIZE, MAX_PROTOCOL_MESSAGE_LENGTH); | 
| 1193 |  | 
 | 
| 1194 | 0 |     if (m_recv_buffer.size() == BIP324Cipher::LENGTH_LEN) { | 
| 1195 |  |         // Length descriptor received. | 
| 1196 | 0 |         m_recv_len = m_cipher.DecryptLength(MakeByteSpan(m_recv_buffer)); | 
| 1197 | 0 |         if (m_recv_len > MAX_CONTENTS_LEN) { | 
| 1198 | 0 |             LogDebug(BCLog::NET, "V2 transport error: packet too large (%u bytes), peer=%d\n", m_recv_len, m_nodeid); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1199 | 0 |             return false; | 
| 1200 | 0 |         } | 
| 1201 | 0 |     } else if (m_recv_buffer.size() > BIP324Cipher::LENGTH_LEN && m_recv_buffer.size() == m_recv_len + BIP324Cipher::EXPANSION) { | 
| 1202 |  |         // Ciphertext received, decrypt it into m_recv_decode_buffer. | 
| 1203 |  |         // Note that it is impossible to reach this branch without hitting the branch above first, | 
| 1204 |  |         // as GetMaxBytesToProcess only allows up to LENGTH_LEN into the buffer before that point. | 
| 1205 | 0 |         m_recv_decode_buffer.resize(m_recv_len); | 
| 1206 | 0 |         bool ignore{false}; | 
| 1207 | 0 |         bool ret = m_cipher.Decrypt( | 
| 1208 | 0 |             /*input=*/MakeByteSpan(m_recv_buffer).subspan(BIP324Cipher::LENGTH_LEN), | 
| 1209 | 0 |             /*aad=*/MakeByteSpan(m_recv_aad), | 
| 1210 | 0 |             /*ignore=*/ignore, | 
| 1211 | 0 |             /*contents=*/MakeWritableByteSpan(m_recv_decode_buffer)); | 
| 1212 | 0 |         if (!ret) { | 
| 1213 | 0 |             LogDebug(BCLog::NET, "V2 transport error: packet decryption failure (%u bytes), peer=%d\n", m_recv_len, m_nodeid); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1214 | 0 |             return false; | 
| 1215 | 0 |         } | 
| 1216 |  |         // We have decrypted a valid packet with the AAD we expected, so clear the expected AAD. | 
| 1217 | 0 |         ClearShrink(m_recv_aad); | 
| 1218 |  |         // Feed the last 4 bytes of the Poly1305 authentication tag (and its timing) into our RNG. | 
| 1219 | 0 |         RandAddEvent(ReadLE32(m_recv_buffer.data() + m_recv_buffer.size() - 4)); | 
| 1220 |  |  | 
| 1221 |  |         // At this point we have a valid packet decrypted into m_recv_decode_buffer. If it's not a | 
| 1222 |  |         // decoy, which we simply ignore, use the current state to decide what to do with it. | 
| 1223 | 0 |         if (!ignore) { | 
| 1224 | 0 |             switch (m_recv_state) { | 
| 1225 | 0 |             case RecvState::VERSION: | 
| 1226 |  |                 // Version message received; transition to application phase. The contents is | 
| 1227 |  |                 // ignored, but can be used for future extensions. | 
| 1228 | 0 |                 SetReceiveState(RecvState::APP); | 
| 1229 | 0 |                 break; | 
| 1230 | 0 |             case RecvState::APP: | 
| 1231 |  |                 // Application message decrypted correctly. It can be extracted using GetMessage(). | 
| 1232 | 0 |                 SetReceiveState(RecvState::APP_READY); | 
| 1233 | 0 |                 break; | 
| 1234 | 0 |             default: | 
| 1235 |  |                 // Any other state is invalid (this function should not have been called). | 
| 1236 | 0 |                 Assume(false); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1237 | 0 |             } | 
| 1238 | 0 |         } | 
| 1239 |  |         // Wipe the receive buffer where the next packet will be received into. | 
| 1240 | 0 |         ClearShrink(m_recv_buffer); | 
| 1241 |  |         // In all but APP_READY state, we can wipe the decoded contents. | 
| 1242 | 0 |         if (m_recv_state != RecvState::APP_READY) ClearShrink(m_recv_decode_buffer); | 
| 1243 | 0 |     } else { | 
| 1244 |  |         // We either have less than 3 bytes, so we don't know the packet's length yet, or more | 
| 1245 |  |         // than 3 bytes but less than the packet's full ciphertext. Wait until those arrive. | 
| 1246 | 0 |     } | 
| 1247 | 0 |     return true; | 
| 1248 | 0 | } | 
| 1249 |  |  | 
| 1250 |  | size_t V2Transport::GetMaxBytesToProcess() noexcept | 
| 1251 | 0 | { | 
| 1252 | 0 |     AssertLockHeld(m_recv_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1253 | 0 |     switch (m_recv_state) { | 
| 1254 | 0 |     case RecvState::KEY_MAYBE_V1: | 
| 1255 |  |         // During the KEY_MAYBE_V1 state we do not allow more than the length of v1 prefix into the | 
| 1256 |  |         // receive buffer. | 
| 1257 | 0 |         Assume(m_recv_buffer.size() <= V1_PREFIX_LEN); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1258 |  |         // As long as we're not sure if this is a v1 or v2 connection, don't receive more than what | 
| 1259 |  |         // is strictly necessary to distinguish the two (16 bytes). If we permitted more than | 
| 1260 |  |         // the v1 header size (24 bytes), we may not be able to feed the already-received bytes | 
| 1261 |  |         // back into the m_v1_fallback V1 transport. | 
| 1262 | 0 |         return V1_PREFIX_LEN - m_recv_buffer.size(); | 
| 1263 | 0 |     case RecvState::KEY: | 
| 1264 |  |         // During the KEY state, we only allow the 64-byte key into the receive buffer. | 
| 1265 | 0 |         Assume(m_recv_buffer.size() <= EllSwiftPubKey::size()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1266 |  |         // As long as we have not received the other side's public key, don't receive more than | 
| 1267 |  |         // that (64 bytes), as garbage follows, and locating the garbage terminator requires the | 
| 1268 |  |         // key exchange first. | 
| 1269 | 0 |         return EllSwiftPubKey::size() - m_recv_buffer.size(); | 
| 1270 | 0 |     case RecvState::GARB_GARBTERM: | 
| 1271 |  |         // Process garbage bytes one by one (because terminator may appear anywhere). | 
| 1272 | 0 |         return 1; | 
| 1273 | 0 |     case RecvState::VERSION: | 
| 1274 | 0 |     case RecvState::APP: | 
| 1275 |  |         // These three states all involve decoding a packet. Process the length descriptor first, | 
| 1276 |  |         // so that we know where the current packet ends (and we don't process bytes from the next | 
| 1277 |  |         // packet or decoy yet). Then, process the ciphertext bytes of the current packet. | 
| 1278 | 0 |         if (m_recv_buffer.size() < BIP324Cipher::LENGTH_LEN) { | 
| 1279 | 0 |             return BIP324Cipher::LENGTH_LEN - m_recv_buffer.size(); | 
| 1280 | 0 |         } else { | 
| 1281 |  |             // Note that BIP324Cipher::EXPANSION is the total difference between contents size | 
| 1282 |  |             // and encoded packet size, which includes the 3 bytes due to the packet length. | 
| 1283 |  |             // When transitioning from receiving the packet length to receiving its ciphertext, | 
| 1284 |  |             // the encrypted packet length is left in the receive buffer. | 
| 1285 | 0 |             return BIP324Cipher::EXPANSION + m_recv_len - m_recv_buffer.size(); | 
| 1286 | 0 |         } | 
| 1287 | 0 |     case RecvState::APP_READY: | 
| 1288 |  |         // No bytes can be processed until GetMessage() is called. | 
| 1289 | 0 |         return 0; | 
| 1290 | 0 |     case RecvState::V1: | 
| 1291 |  |         // Not allowed (must be dealt with by the caller). | 
| 1292 | 0 |         Assume(false); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1293 | 0 |         return 0; | 
| 1294 | 0 |     } | 
| 1295 | 0 |     Assume(false); // unreachable | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1296 | 0 |     return 0; | 
| 1297 | 0 | } | 
| 1298 |  |  | 
| 1299 |  | bool V2Transport::ReceivedBytes(std::span<const uint8_t>& msg_bytes) noexcept | 
| 1300 | 0 | { | 
| 1301 | 0 |     AssertLockNotHeld(m_recv_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1302 |  |     /** How many bytes to allocate in the receive buffer at most above what is received so far. */ | 
| 1303 | 0 |     static constexpr size_t MAX_RESERVE_AHEAD = 256 * 1024; | 
| 1304 |  | 
 | 
| 1305 | 0 |     LOCK(m_recv_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1306 | 0 |     if (m_recv_state == RecvState::V1) return m_v1_fallback.ReceivedBytes(msg_bytes); | 
| 1307 |  |  | 
| 1308 |  |     // Process the provided bytes in msg_bytes in a loop. In each iteration a nonzero number of | 
| 1309 |  |     // bytes (decided by GetMaxBytesToProcess) are taken from the beginning om msg_bytes, and | 
| 1310 |  |     // appended to m_recv_buffer. Then, depending on the receiver state, one of the | 
| 1311 |  |     // ProcessReceived*Bytes functions is called to process the bytes in that buffer. | 
| 1312 | 0 |     while (!msg_bytes.empty()) { | 
| 1313 |  |         // Decide how many bytes to copy from msg_bytes to m_recv_buffer. | 
| 1314 | 0 |         size_t max_read = GetMaxBytesToProcess(); | 
| 1315 |  |  | 
| 1316 |  |         // Reserve space in the buffer if there is not enough. | 
| 1317 | 0 |         if (m_recv_buffer.size() + std::min(msg_bytes.size(), max_read) > m_recv_buffer.capacity()) { | 
| 1318 | 0 |             switch (m_recv_state) { | 
| 1319 | 0 |             case RecvState::KEY_MAYBE_V1: | 
| 1320 | 0 |             case RecvState::KEY: | 
| 1321 | 0 |             case RecvState::GARB_GARBTERM: | 
| 1322 |  |                 // During the initial states (key/garbage), allocate once to fit the maximum (4111 | 
| 1323 |  |                 // bytes). | 
| 1324 | 0 |                 m_recv_buffer.reserve(MAX_GARBAGE_LEN + BIP324Cipher::GARBAGE_TERMINATOR_LEN); | 
| 1325 | 0 |                 break; | 
| 1326 | 0 |             case RecvState::VERSION: | 
| 1327 | 0 |             case RecvState::APP: { | 
| 1328 |  |                 // During states where a packet is being received, as much as is expected but never | 
| 1329 |  |                 // more than MAX_RESERVE_AHEAD bytes in addition to what is received so far. | 
| 1330 |  |                 // This means attackers that want to cause us to waste allocated memory are limited | 
| 1331 |  |                 // to MAX_RESERVE_AHEAD above the largest allowed message contents size, and to | 
| 1332 |  |                 // MAX_RESERVE_AHEAD more than they've actually sent us. | 
| 1333 | 0 |                 size_t alloc_add = std::min(max_read, msg_bytes.size() + MAX_RESERVE_AHEAD); | 
| 1334 | 0 |                 m_recv_buffer.reserve(m_recv_buffer.size() + alloc_add); | 
| 1335 | 0 |                 break; | 
| 1336 | 0 |             } | 
| 1337 | 0 |             case RecvState::APP_READY: | 
| 1338 |  |                 // The buffer is empty in this state. | 
| 1339 | 0 |                 Assume(m_recv_buffer.empty()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1340 | 0 |                 break; | 
| 1341 | 0 |             case RecvState::V1: | 
| 1342 |  |                 // Should have bailed out above. | 
| 1343 | 0 |                 Assume(false); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1344 | 0 |                 break; | 
| 1345 | 0 |             } | 
| 1346 | 0 |         } | 
| 1347 |  |  | 
| 1348 |  |         // Can't read more than provided input. | 
| 1349 | 0 |         max_read = std::min(msg_bytes.size(), max_read); | 
| 1350 |  |         // Copy data to buffer. | 
| 1351 | 0 |         m_recv_buffer.insert(m_recv_buffer.end(), UCharCast(msg_bytes.data()), UCharCast(msg_bytes.data() + max_read)); | 
| 1352 | 0 |         msg_bytes = msg_bytes.subspan(max_read); | 
| 1353 |  |  | 
| 1354 |  |         // Process data in the buffer. | 
| 1355 | 0 |         switch (m_recv_state) { | 
| 1356 | 0 |         case RecvState::KEY_MAYBE_V1: | 
| 1357 | 0 |             ProcessReceivedMaybeV1Bytes(); | 
| 1358 | 0 |             if (m_recv_state == RecvState::V1) return true; | 
| 1359 | 0 |             break; | 
| 1360 |  |  | 
| 1361 | 0 |         case RecvState::KEY: | 
| 1362 | 0 |             if (!ProcessReceivedKeyBytes()) return false; | 
| 1363 | 0 |             break; | 
| 1364 |  |  | 
| 1365 | 0 |         case RecvState::GARB_GARBTERM: | 
| 1366 | 0 |             if (!ProcessReceivedGarbageBytes()) return false; | 
| 1367 | 0 |             break; | 
| 1368 |  |  | 
| 1369 | 0 |         case RecvState::VERSION: | 
| 1370 | 0 |         case RecvState::APP: | 
| 1371 | 0 |             if (!ProcessReceivedPacketBytes()) return false; | 
| 1372 | 0 |             break; | 
| 1373 |  |  | 
| 1374 | 0 |         case RecvState::APP_READY: | 
| 1375 | 0 |             return true; | 
| 1376 |  |  | 
| 1377 | 0 |         case RecvState::V1: | 
| 1378 |  |             // We should have bailed out before. | 
| 1379 | 0 |             Assume(false); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1380 | 0 |             break; | 
| 1381 | 0 |         } | 
| 1382 |  |         // Make sure we have made progress before continuing. | 
| 1383 | 0 |         Assume(max_read > 0); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1384 | 0 |     } | 
| 1385 |  |  | 
| 1386 | 0 |     return true; | 
| 1387 | 0 | } | 
| 1388 |  |  | 
| 1389 |  | std::optional<std::string> V2Transport::GetMessageType(std::span<const uint8_t>& contents) noexcept | 
| 1390 | 0 | { | 
| 1391 | 0 |     if (contents.size() == 0) return std::nullopt; // Empty contents | 
| 1392 | 0 |     uint8_t first_byte = contents[0]; | 
| 1393 | 0 |     contents = contents.subspan(1); // Strip first byte. | 
| 1394 |  | 
 | 
| 1395 | 0 |     if (first_byte != 0) { | 
| 1396 |  |         // Short (1 byte) encoding. | 
| 1397 | 0 |         if (first_byte < std::size(V2_MESSAGE_IDS)) { | 
| 1398 |  |             // Valid short message id. | 
| 1399 | 0 |             return V2_MESSAGE_IDS[first_byte]; | 
| 1400 | 0 |         } else { | 
| 1401 |  |             // Unknown short message id. | 
| 1402 | 0 |             return std::nullopt; | 
| 1403 | 0 |         } | 
| 1404 | 0 |     } | 
| 1405 |  |  | 
| 1406 | 0 |     if (contents.size() < CMessageHeader::MESSAGE_TYPE_SIZE) { | 
| 1407 | 0 |         return std::nullopt; // Long encoding needs 12 message type bytes. | 
| 1408 | 0 |     } | 
| 1409 |  |  | 
| 1410 | 0 |     size_t msg_type_len{0}; | 
| 1411 | 0 |     while (msg_type_len < CMessageHeader::MESSAGE_TYPE_SIZE && contents[msg_type_len] != 0) { | 
| 1412 |  |         // Verify that message type bytes before the first 0x00 are in range. | 
| 1413 | 0 |         if (contents[msg_type_len] < ' ' || contents[msg_type_len] > 0x7F) { | 
| 1414 | 0 |             return {}; | 
| 1415 | 0 |         } | 
| 1416 | 0 |         ++msg_type_len; | 
| 1417 | 0 |     } | 
| 1418 | 0 |     std::string ret{reinterpret_cast<const char*>(contents.data()), msg_type_len}; | 
| 1419 | 0 |     while (msg_type_len < CMessageHeader::MESSAGE_TYPE_SIZE) { | 
| 1420 |  |         // Verify that message type bytes after the first 0x00 are also 0x00. | 
| 1421 | 0 |         if (contents[msg_type_len] != 0) return {}; | 
| 1422 | 0 |         ++msg_type_len; | 
| 1423 | 0 |     } | 
| 1424 |  |     // Strip message type bytes of contents. | 
| 1425 | 0 |     contents = contents.subspan(CMessageHeader::MESSAGE_TYPE_SIZE); | 
| 1426 | 0 |     return ret; | 
| 1427 | 0 | } | 
| 1428 |  |  | 
| 1429 |  | CNetMessage V2Transport::GetReceivedMessage(std::chrono::microseconds time, bool& reject_message) noexcept | 
| 1430 | 0 | { | 
| 1431 | 0 |     AssertLockNotHeld(m_recv_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1432 | 0 |     LOCK(m_recv_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1433 | 0 |     if (m_recv_state == RecvState::V1) return m_v1_fallback.GetReceivedMessage(time, reject_message); | 
| 1434 |  |  | 
| 1435 | 0 |     Assume(m_recv_state == RecvState::APP_READY); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1436 | 0 |     std::span<const uint8_t> contents{m_recv_decode_buffer}; | 
| 1437 | 0 |     auto msg_type = GetMessageType(contents); | 
| 1438 | 0 |     CNetMessage msg{DataStream{}}; | 
| 1439 |  |     // Note that BIP324Cipher::EXPANSION also includes the length descriptor size. | 
| 1440 | 0 |     msg.m_raw_message_size = m_recv_decode_buffer.size() + BIP324Cipher::EXPANSION; | 
| 1441 | 0 |     if (msg_type) { | 
| 1442 | 0 |         reject_message = false; | 
| 1443 | 0 |         msg.m_type = std::move(*msg_type); | 
| 1444 | 0 |         msg.m_time = time; | 
| 1445 | 0 |         msg.m_message_size = contents.size(); | 
| 1446 | 0 |         msg.m_recv.resize(contents.size()); | 
| 1447 | 0 |         std::copy(contents.begin(), contents.end(), UCharCast(msg.m_recv.data())); | 
| 1448 | 0 |     } else { | 
| 1449 | 0 |         LogDebug(BCLog::NET, "V2 transport error: invalid message type (%u bytes contents), peer=%d\n", m_recv_decode_buffer.size(), m_nodeid); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1450 | 0 |         reject_message = true; | 
| 1451 | 0 |     } | 
| 1452 | 0 |     ClearShrink(m_recv_decode_buffer); | 
| 1453 | 0 |     SetReceiveState(RecvState::APP); | 
| 1454 |  | 
 | 
| 1455 | 0 |     return msg; | 
| 1456 | 0 | } | 
| 1457 |  |  | 
| 1458 |  | bool V2Transport::SetMessageToSend(CSerializedNetMsg& msg) noexcept | 
| 1459 | 0 | { | 
| 1460 | 0 |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1461 | 0 |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1462 | 0 |     if (m_send_state == SendState::V1) return m_v1_fallback.SetMessageToSend(msg); | 
| 1463 |  |     // We only allow adding a new message to be sent when in the READY state (so the packet cipher | 
| 1464 |  |     // is available) and the send buffer is empty. This limits the number of messages in the send | 
| 1465 |  |     // buffer to just one, and leaves the responsibility for queueing them up to the caller. | 
| 1466 | 0 |     if (!(m_send_state == SendState::READY && m_send_buffer.empty())) return false; | 
| 1467 |  |     // Construct contents (encoding message type + payload). | 
| 1468 | 0 |     std::vector<uint8_t> contents; | 
| 1469 | 0 |     auto short_message_id = V2_MESSAGE_MAP(msg.m_type); | 
| 1470 | 0 |     if (short_message_id) { | 
| 1471 | 0 |         contents.resize(1 + msg.data.size()); | 
| 1472 | 0 |         contents[0] = *short_message_id; | 
| 1473 | 0 |         std::copy(msg.data.begin(), msg.data.end(), contents.begin() + 1); | 
| 1474 | 0 |     } else { | 
| 1475 |  |         // Initialize with zeroes, and then write the message type string starting at offset 1. | 
| 1476 |  |         // This means contents[0] and the unused positions in contents[1..13] remain 0x00. | 
| 1477 | 0 |         contents.resize(1 + CMessageHeader::MESSAGE_TYPE_SIZE + msg.data.size(), 0); | 
| 1478 | 0 |         std::copy(msg.m_type.begin(), msg.m_type.end(), contents.data() + 1); | 
| 1479 | 0 |         std::copy(msg.data.begin(), msg.data.end(), contents.begin() + 1 + CMessageHeader::MESSAGE_TYPE_SIZE); | 
| 1480 | 0 |     } | 
| 1481 |  |     // Construct ciphertext in send buffer. | 
| 1482 | 0 |     m_send_buffer.resize(contents.size() + BIP324Cipher::EXPANSION); | 
| 1483 | 0 |     m_cipher.Encrypt(MakeByteSpan(contents), {}, false, MakeWritableByteSpan(m_send_buffer)); | 
| 1484 | 0 |     m_send_type = msg.m_type; | 
| 1485 |  |     // Release memory | 
| 1486 | 0 |     ClearShrink(msg.data); | 
| 1487 | 0 |     return true; | 
| 1488 | 0 | } | 
| 1489 |  |  | 
| 1490 |  | Transport::BytesToSend V2Transport::GetBytesToSend(bool have_next_message) const noexcept | 
| 1491 | 0 | { | 
| 1492 | 0 |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1493 | 0 |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1494 | 0 |     if (m_send_state == SendState::V1) return m_v1_fallback.GetBytesToSend(have_next_message); | 
| 1495 |  |  | 
| 1496 | 0 |     if (m_send_state == SendState::MAYBE_V1) Assume(m_send_buffer.empty()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1497 | 0 |     Assume(m_send_pos <= m_send_buffer.size()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1498 | 0 |     return { | 
| 1499 | 0 |         std::span{m_send_buffer}.subspan(m_send_pos), | 
| 1500 |  |         // We only have more to send after the current m_send_buffer if there is a (next) | 
| 1501 |  |         // message to be sent, and we're capable of sending packets. */ | 
| 1502 | 0 |         have_next_message && m_send_state == SendState::READY, | 
| 1503 | 0 |         m_send_type | 
| 1504 | 0 |     }; | 
| 1505 | 0 | } | 
| 1506 |  |  | 
| 1507 |  | void V2Transport::MarkBytesSent(size_t bytes_sent) noexcept | 
| 1508 | 0 | { | 
| 1509 | 0 |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1510 | 0 |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1511 | 0 |     if (m_send_state == SendState::V1) return m_v1_fallback.MarkBytesSent(bytes_sent); | 
| 1512 |  |  | 
| 1513 | 0 |     if (m_send_state == SendState::AWAITING_KEY && m_send_pos == 0 && bytes_sent > 0) { | 
| 1514 | 0 |         LogDebug(BCLog::NET, "start sending v2 handshake to peer=%d\n", m_nodeid); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1515 | 0 |     } | 
| 1516 |  | 
 | 
| 1517 | 0 |     m_send_pos += bytes_sent; | 
| 1518 | 0 |     Assume(m_send_pos <= m_send_buffer.size()); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1519 | 0 |     if (m_send_pos >= CMessageHeader::HEADER_SIZE) { | 
| 1520 | 0 |         m_sent_v1_header_worth = true; | 
| 1521 | 0 |     } | 
| 1522 |  |     // Wipe the buffer when everything is sent. | 
| 1523 | 0 |     if (m_send_pos == m_send_buffer.size()) { | 
| 1524 | 0 |         m_send_pos = 0; | 
| 1525 | 0 |         ClearShrink(m_send_buffer); | 
| 1526 | 0 |     } | 
| 1527 | 0 | } | 
| 1528 |  |  | 
| 1529 |  | bool V2Transport::ShouldReconnectV1() const noexcept | 
| 1530 | 0 | { | 
| 1531 | 0 |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1532 | 0 |     AssertLockNotHeld(m_recv_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1533 |  |     // Only outgoing connections need reconnection. | 
| 1534 | 0 |     if (!m_initiating) return false; | 
| 1535 |  |  | 
| 1536 | 0 |     LOCK(m_recv_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1537 |  |     // We only reconnect in the very first state and when the receive buffer is empty. Together | 
| 1538 |  |     // these conditions imply nothing has been received so far. | 
| 1539 | 0 |     if (m_recv_state != RecvState::KEY) return false; | 
| 1540 | 0 |     if (!m_recv_buffer.empty()) return false; | 
| 1541 |  |     // Check if we've sent enough for the other side to disconnect us (if it was V1). | 
| 1542 | 0 |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1543 | 0 |     return m_sent_v1_header_worth; | 
| 1544 | 0 | } | 
| 1545 |  |  | 
| 1546 |  | size_t V2Transport::GetSendMemoryUsage() const noexcept | 
| 1547 | 0 | { | 
| 1548 | 0 |     AssertLockNotHeld(m_send_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1549 | 0 |     LOCK(m_send_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1550 | 0 |     if (m_send_state == SendState::V1) return m_v1_fallback.GetSendMemoryUsage(); | 
| 1551 |  |  | 
| 1552 | 0 |     return sizeof(m_send_buffer) + memusage::DynamicUsage(m_send_buffer); | 
| 1553 | 0 | } | 
| 1554 |  |  | 
| 1555 |  | Transport::Info V2Transport::GetInfo() const noexcept | 
| 1556 | 0 | { | 
| 1557 | 0 |     AssertLockNotHeld(m_recv_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1558 | 0 |     LOCK(m_recv_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1559 | 0 |     if (m_recv_state == RecvState::V1) return m_v1_fallback.GetInfo(); | 
| 1560 |  |  | 
| 1561 | 0 |     Transport::Info info; | 
| 1562 |  |  | 
| 1563 |  |     // Do not report v2 and session ID until the version packet has been received | 
| 1564 |  |     // and verified (confirming that the other side very likely has the same keys as us). | 
| 1565 | 0 |     if (m_recv_state != RecvState::KEY_MAYBE_V1 && m_recv_state != RecvState::KEY && | 
| 1566 | 0 |         m_recv_state != RecvState::GARB_GARBTERM && m_recv_state != RecvState::VERSION) { | 
| 1567 | 0 |         info.transport_type = TransportProtocolType::V2; | 
| 1568 | 0 |         info.session_id = uint256(MakeUCharSpan(m_cipher.GetSessionID())); | 
| 1569 | 0 |     } else { | 
| 1570 | 0 |         info.transport_type = TransportProtocolType::DETECTING; | 
| 1571 | 0 |     } | 
| 1572 |  | 
 | 
| 1573 | 0 |     return info; | 
| 1574 | 0 | } | 
| 1575 |  |  | 
| 1576 |  | std::pair<size_t, bool> CConnman::SocketSendData(CNode& node) const | 
| 1577 | 1.21M | { | 
| 1578 | 1.21M |     auto it = node.vSendMsg.begin(); | 
| 1579 | 1.21M |     size_t nSentSize = 0; | 
| 1580 | 1.21M |     bool data_left{false}; //!< second return value (whether unsent data remains) | 
| 1581 | 1.21M |     std::optional<bool> expected_more; | 
| 1582 |  |  | 
| 1583 | 2.87M |     while (true) { | 
| 1584 | 2.87M |         if (it != node.vSendMsg.end()) { | 
| 1585 |  |             // If possible, move one message from the send queue to the transport. This fails when | 
| 1586 |  |             // there is an existing message still being sent, or (for v2 transports) when the | 
| 1587 |  |             // handshake has not yet completed. | 
| 1588 | 1.21M |             size_t memusage = it->GetMemoryUsage(); | 
| 1589 | 1.21M |             if (node.m_transport->SetMessageToSend(*it)) { | 
| 1590 |  |                 // Update memory usage of send buffer (as *it will be deleted). | 
| 1591 | 1.21M |                 node.m_send_memusage -= memusage; | 
| 1592 | 1.21M |                 ++it; | 
| 1593 | 1.21M |             } | 
| 1594 | 1.21M |         } | 
| 1595 | 2.87M |         const auto& [data, more, msg_type] = node.m_transport->GetBytesToSend(it != node.vSendMsg.end()); | 
| 1596 |  |         // We rely on the 'more' value returned by GetBytesToSend to correctly predict whether more | 
| 1597 |  |         // bytes are still to be sent, to correctly set the MSG_MORE flag. As a sanity check, | 
| 1598 |  |         // verify that the previously returned 'more' was correct. | 
| 1599 | 2.87M |         if (expected_more.has_value()) Assume1.66M(!data.empty() == *expected_more); | Line | Count | Source |  | 118 | 1.66M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 1600 | 2.87M |         expected_more = more; | 
| 1601 | 2.87M |         data_left = !data.empty(); // will be overwritten on next loop if all of data gets sent | 
| 1602 | 2.87M |         int nBytes = 0; | 
| 1603 | 2.87M |         if (!data.empty()) { | 
| 1604 | 1.95M |             LOCK(node.m_sock_mutex); | Line | Count | Source |  | 259 | 1.95M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 1.95M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 1.95M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 1.95M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1605 |  |             // There is no socket in case we've already disconnected, or in test cases without | 
| 1606 |  |             // real connections. In these cases, we bail out immediately and just leave things | 
| 1607 |  |             // in the send queue and transport. | 
| 1608 | 1.95M |             if (!node.m_sock) { | 
| 1609 | 0 |                 break; | 
| 1610 | 0 |             } | 
| 1611 | 1.95M |             int flags = MSG_NOSIGNAL | MSG_DONTWAIT; | 
| 1612 |  | #ifdef MSG_MORE | 
| 1613 |  |             if (more) { | 
| 1614 |  |                 flags |= MSG_MORE; | 
| 1615 |  |             } | 
| 1616 |  | #endif | 
| 1617 | 1.95M |             nBytes = node.m_sock->Send(data.data(), data.size(), flags); | 
| 1618 | 1.95M |         } | 
| 1619 | 2.87M |         if (nBytes > 0) { | 
| 1620 | 1.94M |             node.m_last_send = GetTime<std::chrono::seconds>(); | 
| 1621 | 1.94M |             node.nSendBytes += nBytes; | 
| 1622 |  |             // Notify transport that bytes have been processed. | 
| 1623 | 1.94M |             node.m_transport->MarkBytesSent(nBytes); | 
| 1624 |  |             // Update statistics per message type. | 
| 1625 | 1.94M |             if (!msg_type.empty()) { // don't report v2 handshake bytes for now | 
| 1626 | 1.94M |                 node.AccountForSentBytes(msg_type, nBytes); | 
| 1627 | 1.94M |             } | 
| 1628 | 1.94M |             nSentSize += nBytes; | 
| 1629 | 1.94M |             if ((size_t)nBytes != data.size()) { | 
| 1630 |  |                 // could not send full message; stop sending more | 
| 1631 | 276k |                 break; | 
| 1632 | 276k |             } | 
| 1633 | 1.94M |         } else { | 
| 1634 | 937k |             if (nBytes < 0) { | 
| 1635 |  |                 // error | 
| 1636 | 11.0k |                 int nErr = WSAGetLastError(); | Line | Count | Source |  | 47 | 11.0k | #define WSAGetLastError()   errno | 
 | 
| 1637 | 11.0k |                 if (nErr != WSAEWOULDBLOCK && nErr != 10.2k WSAEMSGSIZE10.2k&& nErr != 10.0k WSAEINTR10.0k&& nErr != 10.0k WSAEINPROGRESS10.0k) { | Line | Count | Source |  | 49 | 22.0k | #define WSAEWOULDBLOCK      EWOULDBLOCK | 
 |                 if (nErr != WSAEWOULDBLOCK && nErr != 10.2k WSAEMSGSIZE10.2k&& nErr != 10.0k WSAEINTR10.0k&& nErr != 10.0k WSAEINPROGRESS10.0k) { | Line | Count | Source |  | 51 | 21.2k | #define WSAEMSGSIZE         EMSGSIZE | 
 |                 if (nErr != WSAEWOULDBLOCK && nErr != 10.2k WSAEMSGSIZE10.2k&& nErr != 10.0k WSAEINTR10.0k&& nErr != 10.0k WSAEINPROGRESS10.0k) { | Line | Count | Source |  | 52 | 21.1k | #define WSAEINTR            EINTR | 
 |                 if (nErr != WSAEWOULDBLOCK && nErr != 10.2k WSAEMSGSIZE10.2k&& nErr != 10.0k WSAEINTR10.0k&& nErr != 10.0k WSAEINPROGRESS10.0k) { | Line | Count | Source |  | 53 | 10.0k | #define WSAEINPROGRESS      EINPROGRESS | 
 | 
| 1638 | 10.0k |                     LogDebug(BCLog::NET, "socket send error, %s: %s\n", node.DisconnectMsg(fLogIPs), NetworkErrorString(nErr)); | Line | Count | Source |  | 381 | 10.0k | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 10.0k |     do {                                                              \ |  | 374 | 10.0k |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 10.0k |     } while (0) | 
 | 
 | 
| 1639 | 10.0k |                     node.CloseSocketDisconnect(); | 
| 1640 | 10.0k |                 } | 
| 1641 | 11.0k |             } | 
| 1642 | 937k |             break; | 
| 1643 | 937k |         } | 
| 1644 | 2.87M |     } | 
| 1645 |  |  | 
| 1646 | 1.21M |     node.fPauseSend = node.m_send_memusage + node.m_transport->GetSendMemoryUsage() > nSendBufferMaxSize; | 
| 1647 |  |  | 
| 1648 | 1.21M |     if (it == node.vSendMsg.end()) { | 
| 1649 | 1.21M |         assert(node.m_send_memusage == 0); | 
| 1650 | 1.21M |     } | 
| 1651 | 1.21M |     node.vSendMsg.erase(node.vSendMsg.begin(), it); | 
| 1652 | 1.21M |     return {nSentSize, data_left}; | 
| 1653 | 1.21M | } | 
| 1654 |  |  | 
| 1655 |  | /** Try to find a connection to evict when the node is full. | 
| 1656 |  |  *  Extreme care must be taken to avoid opening the node to attacker | 
| 1657 |  |  *   triggered network partitioning. | 
| 1658 |  |  *  The strategy used here is to protect a small number of peers | 
| 1659 |  |  *   for each of several distinct characteristics which are difficult | 
| 1660 |  |  *   to forge.  In order to partition a node the attacker must be | 
| 1661 |  |  *   simultaneously better at all of them than honest peers. | 
| 1662 |  |  */ | 
| 1663 |  | bool CConnman::AttemptToEvictConnection() | 
| 1664 | 0 | { | 
| 1665 | 0 |     std::vector<NodeEvictionCandidate> vEvictionCandidates; | 
| 1666 | 0 |     { | 
| 1667 |  | 
 | 
| 1668 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1669 | 0 |         for (const CNode* node : m_nodes) { | 
| 1670 | 0 |             if (node->fDisconnect) | 
| 1671 | 0 |                 continue; | 
| 1672 | 0 |             NodeEvictionCandidate candidate{ | 
| 1673 | 0 |                 .id = node->GetId(), | 
| 1674 | 0 |                 .m_connected = node->m_connected, | 
| 1675 | 0 |                 .m_min_ping_time = node->m_min_ping_time, | 
| 1676 | 0 |                 .m_last_block_time = node->m_last_block_time, | 
| 1677 | 0 |                 .m_last_tx_time = node->m_last_tx_time, | 
| 1678 | 0 |                 .fRelevantServices = node->m_has_all_wanted_services, | 
| 1679 | 0 |                 .m_relay_txs = node->m_relays_txs.load(), | 
| 1680 | 0 |                 .fBloomFilter = node->m_bloom_filter_loaded.load(), | 
| 1681 | 0 |                 .nKeyedNetGroup = node->nKeyedNetGroup, | 
| 1682 | 0 |                 .prefer_evict = node->m_prefer_evict, | 
| 1683 | 0 |                 .m_is_local = node->addr.IsLocal(), | 
| 1684 | 0 |                 .m_network = node->ConnectedThroughNetwork(), | 
| 1685 | 0 |                 .m_noban = node->HasPermission(NetPermissionFlags::NoBan), | 
| 1686 | 0 |                 .m_conn_type = node->m_conn_type, | 
| 1687 | 0 |             }; | 
| 1688 | 0 |             vEvictionCandidates.push_back(candidate); | 
| 1689 | 0 |         } | 
| 1690 | 0 |     } | 
| 1691 | 0 |     const std::optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates)); | 
| 1692 | 0 |     if (!node_id_to_evict) { | 
| 1693 | 0 |         return false; | 
| 1694 | 0 |     } | 
| 1695 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1696 | 0 |     for (CNode* pnode : m_nodes) { | 
| 1697 | 0 |         if (pnode->GetId() == *node_id_to_evict) { | 
| 1698 | 0 |             LogDebug(BCLog::NET, "selected %s connection for eviction, %s", pnode->ConnectionTypeAsString(), pnode->DisconnectMsg(fLogIPs)); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1699 | 0 |             TRACEPOINT(net, evicted_inbound_connection, | 
| 1700 | 0 |                 pnode->GetId(), | 
| 1701 | 0 |                 pnode->m_addr_name.c_str(), | 
| 1702 | 0 |                 pnode->ConnectionTypeAsString().c_str(), | 
| 1703 | 0 |                 pnode->ConnectedThroughNetwork(), | 
| 1704 | 0 |                 Ticks<std::chrono::seconds>(pnode->m_connected)); | 
| 1705 | 0 |             pnode->fDisconnect = true; | 
| 1706 | 0 |             return true; | 
| 1707 | 0 |         } | 
| 1708 | 0 |     } | 
| 1709 | 0 |     return false; | 
| 1710 | 0 | } | 
| 1711 |  |  | 
| 1712 | 0 | void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { | 
| 1713 | 0 |     struct sockaddr_storage sockaddr; | 
| 1714 | 0 |     socklen_t len = sizeof(sockaddr); | 
| 1715 | 0 |     auto sock = hListenSocket.sock->Accept((struct sockaddr*)&sockaddr, &len); | 
| 1716 |  | 
 | 
| 1717 | 0 |     if (!sock) { | 
| 1718 | 0 |         const int nErr = WSAGetLastError(); | Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 1719 | 0 |         if (nErr != WSAEWOULDBLOCK) {| Line | Count | Source |  | 49 | 0 | #define WSAEWOULDBLOCK      EWOULDBLOCK | 
 | 
| 1720 | 0 |             LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 1721 | 0 |         } | 
| 1722 | 0 |         return; | 
| 1723 | 0 |     } | 
| 1724 |  |  | 
| 1725 | 0 |     CService addr; | 
| 1726 | 0 |     if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr, len)) { | 
| 1727 | 0 |         LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "Unknown socket family\n"); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 1728 | 0 |     } else { | 
| 1729 | 0 |         addr = MaybeFlipIPv6toCJDNS(addr); | 
| 1730 | 0 |     } | 
| 1731 |  | 
 | 
| 1732 | 0 |     const CService addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(*sock))}; | 
| 1733 |  | 
 | 
| 1734 | 0 |     NetPermissionFlags permission_flags = NetPermissionFlags::None; | 
| 1735 | 0 |     hListenSocket.AddSocketPermissionFlags(permission_flags); | 
| 1736 |  | 
 | 
| 1737 | 0 |     CreateNodeFromAcceptedSocket(std::move(sock), permission_flags, addr_bind, addr); | 
| 1738 | 0 | } | 
| 1739 |  |  | 
| 1740 |  | void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, | 
| 1741 |  |                                             NetPermissionFlags permission_flags, | 
| 1742 |  |                                             const CService& addr_bind, | 
| 1743 |  |                                             const CService& addr) | 
| 1744 | 0 | { | 
| 1745 | 0 |     int nInbound = 0; | 
| 1746 |  | 
 | 
| 1747 | 0 |     const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end(); | 
| 1748 |  |  | 
| 1749 |  |     // Tor inbound connections do not reveal the peer's actual network address. | 
| 1750 |  |     // Therefore do not apply address-based whitelist permissions to them. | 
| 1751 | 0 |     AddWhitelistPermissionFlags(permission_flags, inbound_onion ? std::optional<CNetAddr>{} : addr, vWhitelistedRangeIncoming); | 
| 1752 |  | 
 | 
| 1753 | 0 |     { | 
| 1754 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1755 | 0 |         for (const CNode* pnode : m_nodes) { | 
| 1756 | 0 |             if (pnode->IsInboundConn()) nInbound++; | 
| 1757 | 0 |         } | 
| 1758 | 0 |     } | 
| 1759 |  | 
 | 
| 1760 | 0 |     if (!fNetworkActive) { | 
| 1761 | 0 |         LogDebug(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToStringAddrPort()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1762 | 0 |         return; | 
| 1763 | 0 |     } | 
| 1764 |  |  | 
| 1765 | 0 |     if (!sock->IsSelectable()) { | 
| 1766 | 0 |         LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToStringAddrPort());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 1767 | 0 |         return; | 
| 1768 | 0 |     } | 
| 1769 |  |  | 
| 1770 |  |     // According to the internet TCP_NODELAY is not carried into accepted sockets | 
| 1771 |  |     // on all platforms.  Set it again here just to be sure. | 
| 1772 | 0 |     const int on{1}; | 
| 1773 | 0 |     if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) {| Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 1774 | 0 |         LogDebug(BCLog::NET, "connection from %s: unable to set TCP_NODELAY, continuing anyway\n", | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1775 | 0 |                  addr.ToStringAddrPort()); | 
| 1776 | 0 |     } | 
| 1777 |  |  | 
| 1778 |  |     // Don't accept connections from banned peers. | 
| 1779 | 0 |     bool banned = m_banman && m_banman->IsBanned(addr); | 
| 1780 | 0 |     if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && banned) | 
| 1781 | 0 |     { | 
| 1782 | 0 |         LogDebug(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToStringAddrPort()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1783 | 0 |         return; | 
| 1784 | 0 |     } | 
| 1785 |  |  | 
| 1786 |  |     // Only accept connections from discouraged peers if our inbound slots aren't (almost) full. | 
| 1787 | 0 |     bool discouraged = m_banman && m_banman->IsDiscouraged(addr); | 
| 1788 | 0 |     if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && nInbound + 1 >= m_max_inbound && discouraged) | 
| 1789 | 0 |     { | 
| 1790 | 0 |         LogDebug(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToStringAddrPort()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1791 | 0 |         return; | 
| 1792 | 0 |     } | 
| 1793 |  |  | 
| 1794 | 0 |     if (nInbound >= m_max_inbound) | 
| 1795 | 0 |     { | 
| 1796 | 0 |         if (!AttemptToEvictConnection()) { | 
| 1797 |  |             // No connection to evict, disconnect the new connection | 
| 1798 | 0 |             LogDebug(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n"); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1799 | 0 |             return; | 
| 1800 | 0 |         } | 
| 1801 | 0 |     } | 
| 1802 |  |  | 
| 1803 | 0 |     NodeId id = GetNewNodeId(); | 
| 1804 | 0 |     uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); | 
| 1805 |  |  | 
| 1806 |  |     // The V2Transport transparently falls back to V1 behavior when an incoming V1 connection is | 
| 1807 |  |     // detected, so use it whenever we signal NODE_P2P_V2. | 
| 1808 | 0 |     ServiceFlags local_services = GetLocalServices(); | 
| 1809 | 0 |     const bool use_v2transport(local_services & NODE_P2P_V2); | 
| 1810 |  | 
 | 
| 1811 | 0 |     CNode* pnode = new CNode(id, | 
| 1812 | 0 |                              std::move(sock), | 
| 1813 | 0 |                              CAddress{addr, NODE_NONE}, | 
| 1814 | 0 |                              CalculateKeyedNetGroup(addr), | 
| 1815 | 0 |                              nonce, | 
| 1816 | 0 |                              addr_bind, | 
| 1817 | 0 |                              /*addrNameIn=*/"", | 
| 1818 | 0 |                              ConnectionType::INBOUND, | 
| 1819 | 0 |                              inbound_onion, | 
| 1820 | 0 |                              CNodeOptions{ | 
| 1821 | 0 |                                  .permission_flags = permission_flags, | 
| 1822 | 0 |                                  .prefer_evict = discouraged, | 
| 1823 | 0 |                                  .recv_flood_size = nReceiveFloodSize, | 
| 1824 | 0 |                                  .use_v2transport = use_v2transport, | 
| 1825 | 0 |                              }); | 
| 1826 | 0 |     pnode->AddRef(); | 
| 1827 | 0 |     m_msgproc->InitializeNode(*pnode, local_services); | 
| 1828 | 0 |     { | 
| 1829 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1830 | 0 |         m_nodes.push_back(pnode); | 
| 1831 | 0 |     } | 
| 1832 | 0 |     LogDebug(BCLog::NET, "connection from %s accepted\n", addr.ToStringAddrPort()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1833 | 0 |     TRACEPOINT(net, inbound_connection, | 
| 1834 | 0 |         pnode->GetId(), | 
| 1835 | 0 |         pnode->m_addr_name.c_str(), | 
| 1836 | 0 |         pnode->ConnectionTypeAsString().c_str(), | 
| 1837 | 0 |         pnode->ConnectedThroughNetwork(), | 
| 1838 | 0 |         GetNodeCount(ConnectionDirection::In)); | 
| 1839 |  |  | 
| 1840 |  |     // We received a new connection, harvest entropy from the time (and our peer count) | 
| 1841 | 0 |     RandAddEvent((uint32_t)id); | 
| 1842 | 0 | } | 
| 1843 |  |  | 
| 1844 |  | bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type, bool use_v2transport = false) | 
| 1845 | 0 | { | 
| 1846 | 0 |     AssertLockNotHeld(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1847 | 0 |     std::optional<int> max_connections; | 
| 1848 | 0 |     switch (conn_type) { | 
| 1849 | 0 |     case ConnectionType::INBOUND: | 
| 1850 | 0 |     case ConnectionType::MANUAL: | 
| 1851 | 0 |         return false; | 
| 1852 | 0 |     case ConnectionType::OUTBOUND_FULL_RELAY: | 
| 1853 | 0 |         max_connections = m_max_outbound_full_relay; | 
| 1854 | 0 |         break; | 
| 1855 | 0 |     case ConnectionType::BLOCK_RELAY: | 
| 1856 | 0 |         max_connections = m_max_outbound_block_relay; | 
| 1857 | 0 |         break; | 
| 1858 |  |     // no limit for ADDR_FETCH because -seednode has no limit either | 
| 1859 | 0 |     case ConnectionType::ADDR_FETCH: | 
| 1860 | 0 |         break; | 
| 1861 |  |     // no limit for FEELER connections since they're short-lived | 
| 1862 | 0 |     case ConnectionType::FEELER: | 
| 1863 | 0 |         break; | 
| 1864 | 0 |     } // no default case, so the compiler can warn about missing cases | 
| 1865 |  |  | 
| 1866 |  |     // Count existing connections | 
| 1867 | 0 |     int existing_connections = WITH_LOCK(m_nodes_mutex, | Line | Count | Source |  | 290 | 0 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) | 
 | 
| 1868 | 0 |                                          return std::count_if(m_nodes.begin(), m_nodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; });); | 
| 1869 |  |  | 
| 1870 |  |     // Max connections of specified type already exist | 
| 1871 | 0 |     if (max_connections != std::nullopt && existing_connections >= max_connections) return false; | 
| 1872 |  |  | 
| 1873 |  |     // Max total outbound connections already exist | 
| 1874 | 0 |     CountingSemaphoreGrant<> grant(*semOutbound, true); | 
| 1875 | 0 |     if (!grant) return false; | 
| 1876 |  |  | 
| 1877 | 0 |     OpenNetworkConnection(CAddress(), false, std::move(grant), address.c_str(), conn_type, /*use_v2transport=*/use_v2transport); | 
| 1878 | 0 |     return true; | 
| 1879 | 0 | } | 
| 1880 |  |  | 
| 1881 |  | void CConnman::DisconnectNodes() | 
| 1882 | 0 | { | 
| 1883 | 0 |     AssertLockNotHeld(m_nodes_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1884 | 0 |     AssertLockNotHeld(m_reconnections_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 1885 |  |  | 
| 1886 |  |     // Use a temporary variable to accumulate desired reconnections, so we don't need | 
| 1887 |  |     // m_reconnections_mutex while holding m_nodes_mutex. | 
| 1888 | 0 |     decltype(m_reconnections) reconnections_to_add; | 
| 1889 |  | 
 | 
| 1890 | 0 |     { | 
| 1891 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1892 |  | 
 | 
| 1893 | 0 |         const bool network_active{fNetworkActive}; | 
| 1894 | 0 |         if (!network_active) { | 
| 1895 |  |             // Disconnect any connected nodes | 
| 1896 | 0 |             for (CNode* pnode : m_nodes) { | 
| 1897 | 0 |                 if (!pnode->fDisconnect) { | 
| 1898 | 0 |                     LogDebug(BCLog::NET, "Network not active, %s\n", pnode->DisconnectMsg(fLogIPs)); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1899 | 0 |                     pnode->fDisconnect = true; | 
| 1900 | 0 |                 } | 
| 1901 | 0 |             } | 
| 1902 | 0 |         } | 
| 1903 |  |  | 
| 1904 |  |         // Disconnect unused nodes | 
| 1905 | 0 |         std::vector<CNode*> nodes_copy = m_nodes; | 
| 1906 | 0 |         for (CNode* pnode : nodes_copy) | 
| 1907 | 0 |         { | 
| 1908 | 0 |             if (pnode->fDisconnect) | 
| 1909 | 0 |             { | 
| 1910 |  |                 // remove from m_nodes | 
| 1911 | 0 |                 m_nodes.erase(remove(m_nodes.begin(), m_nodes.end(), pnode), m_nodes.end()); | 
| 1912 |  |  | 
| 1913 |  |                 // Add to reconnection list if appropriate. We don't reconnect right here, because | 
| 1914 |  |                 // the creation of a connection is a blocking operation (up to several seconds), | 
| 1915 |  |                 // and we don't want to hold up the socket handler thread for that long. | 
| 1916 | 0 |                 if (network_active && pnode->m_transport->ShouldReconnectV1()) { | 
| 1917 | 0 |                     reconnections_to_add.push_back({ | 
| 1918 | 0 |                         .addr_connect = pnode->addr, | 
| 1919 | 0 |                         .grant = std::move(pnode->grantOutbound), | 
| 1920 | 0 |                         .destination = pnode->m_dest, | 
| 1921 | 0 |                         .conn_type = pnode->m_conn_type, | 
| 1922 | 0 |                         .use_v2transport = false}); | 
| 1923 | 0 |                     LogDebug(BCLog::NET, "retrying with v1 transport protocol for peer=%d\n", pnode->GetId()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1924 | 0 |                 } | 
| 1925 |  |  | 
| 1926 |  |                 // release outbound grant (if any) | 
| 1927 | 0 |                 pnode->grantOutbound.Release(); | 
| 1928 |  |  | 
| 1929 |  |                 // close socket and cleanup | 
| 1930 | 0 |                 pnode->CloseSocketDisconnect(); | 
| 1931 |  |  | 
| 1932 |  |                 // update connection count by network | 
| 1933 | 0 |                 if (pnode->IsManualOrFullOutboundConn()) --m_network_conn_counts[pnode->addr.GetNetwork()]; | 
| 1934 |  |  | 
| 1935 |  |                 // hold in disconnected pool until all refs are released | 
| 1936 | 0 |                 pnode->Release(); | 
| 1937 | 0 |                 m_nodes_disconnected.push_back(pnode); | 
| 1938 | 0 |             } | 
| 1939 | 0 |         } | 
| 1940 | 0 |     } | 
| 1941 | 0 |     { | 
| 1942 |  |         // Delete disconnected nodes | 
| 1943 | 0 |         std::list<CNode*> nodes_disconnected_copy = m_nodes_disconnected; | 
| 1944 | 0 |         for (CNode* pnode : nodes_disconnected_copy) | 
| 1945 | 0 |         { | 
| 1946 |  |             // Destroy the object only after other threads have stopped using it. | 
| 1947 | 0 |             if (pnode->GetRefCount() <= 0) { | 
| 1948 | 0 |                 m_nodes_disconnected.remove(pnode); | 
| 1949 | 0 |                 DeleteNode(pnode); | 
| 1950 | 0 |             } | 
| 1951 | 0 |         } | 
| 1952 | 0 |     } | 
| 1953 | 0 |     { | 
| 1954 |  |         // Move entries from reconnections_to_add to m_reconnections. | 
| 1955 | 0 |         LOCK(m_reconnections_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1956 | 0 |         m_reconnections.splice(m_reconnections.end(), std::move(reconnections_to_add)); | 
| 1957 | 0 |     } | 
| 1958 | 0 | } | 
| 1959 |  |  | 
| 1960 |  | void CConnman::NotifyNumConnectionsChanged() | 
| 1961 | 0 | { | 
| 1962 | 0 |     size_t nodes_size; | 
| 1963 | 0 |     { | 
| 1964 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 1965 | 0 |         nodes_size = m_nodes.size(); | 
| 1966 | 0 |     } | 
| 1967 | 0 |     if(nodes_size != nPrevNodeCount) { | 
| 1968 | 0 |         nPrevNodeCount = nodes_size; | 
| 1969 | 0 |         if (m_client_interface) { | 
| 1970 | 0 |             m_client_interface->NotifyNumConnectionsChanged(nodes_size); | 
| 1971 | 0 |         } | 
| 1972 | 0 |     } | 
| 1973 | 0 | } | 
| 1974 |  |  | 
| 1975 |  | bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const | 
| 1976 | 5.74M | { | 
| 1977 | 5.74M |     return node.m_connected + m_peer_connect_timeout < now; | 
| 1978 | 5.74M | } | 
| 1979 |  |  | 
| 1980 |  | bool CConnman::InactivityCheck(const CNode& node) const | 
| 1981 | 0 | { | 
| 1982 |  |     // Tests that see disconnects after using mocktime can start nodes with a | 
| 1983 |  |     // large timeout. For example, -peertimeout=999999999. | 
| 1984 | 0 |     const auto now{GetTime<std::chrono::seconds>()}; | 
| 1985 | 0 |     const auto last_send{node.m_last_send.load()}; | 
| 1986 | 0 |     const auto last_recv{node.m_last_recv.load()}; | 
| 1987 |  | 
 | 
| 1988 | 0 |     if (!ShouldRunInactivityChecks(node, now)) return false; | 
| 1989 |  |  | 
| 1990 | 0 |     bool has_received{last_recv.count() != 0}; | 
| 1991 | 0 |     bool has_sent{last_send.count() != 0}; | 
| 1992 |  | 
 | 
| 1993 | 0 |     if (!has_received || !has_sent) { | 
| 1994 | 0 |         std::string has_never; | 
| 1995 | 0 |         if (!has_received) has_never += ", never received from peer"; | 
| 1996 | 0 |         if (!has_sent) has_never += ", never sent to peer"; | 
| 1997 | 0 |         LogDebug(BCLog::NET, | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 1998 | 0 |             "socket no message in first %i seconds%s, %s\n", | 
| 1999 | 0 |             count_seconds(m_peer_connect_timeout), | 
| 2000 | 0 |             has_never, | 
| 2001 | 0 |             node.DisconnectMsg(fLogIPs) | 
| 2002 | 0 |         ); | 
| 2003 | 0 |         return true; | 
| 2004 | 0 |     } | 
| 2005 |  |  | 
| 2006 | 0 |     if (now > last_send + TIMEOUT_INTERVAL) { | 
| 2007 | 0 |         LogDebug(BCLog::NET, | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2008 | 0 |             "socket sending timeout: %is, %s\n", count_seconds(now - last_send), | 
| 2009 | 0 |             node.DisconnectMsg(fLogIPs) | 
| 2010 | 0 |         ); | 
| 2011 | 0 |         return true; | 
| 2012 | 0 |     } | 
| 2013 |  |  | 
| 2014 | 0 |     if (now > last_recv + TIMEOUT_INTERVAL) { | 
| 2015 | 0 |         LogDebug(BCLog::NET, | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2016 | 0 |             "socket receive timeout: %is, %s\n", count_seconds(now - last_recv), | 
| 2017 | 0 |             node.DisconnectMsg(fLogIPs) | 
| 2018 | 0 |         ); | 
| 2019 | 0 |         return true; | 
| 2020 | 0 |     } | 
| 2021 |  |  | 
| 2022 | 0 |     if (!node.fSuccessfullyConnected) { | 
| 2023 | 0 |         if (node.m_transport->GetInfo().transport_type == TransportProtocolType::DETECTING) { | 
| 2024 | 0 |             LogDebug(BCLog::NET, "V2 handshake timeout, %s\n", node.DisconnectMsg(fLogIPs)); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2025 | 0 |         } else { | 
| 2026 | 0 |             LogDebug(BCLog::NET, "version handshake timeout, %s\n", node.DisconnectMsg(fLogIPs)); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2027 | 0 |         } | 
| 2028 | 0 |         return true; | 
| 2029 | 0 |     } | 
| 2030 |  |  | 
| 2031 | 0 |     return false; | 
| 2032 | 0 | } | 
| 2033 |  |  | 
| 2034 |  | Sock::EventsPerSock CConnman::GenerateWaitSockets(std::span<CNode* const> nodes) | 
| 2035 | 0 | { | 
| 2036 | 0 |     Sock::EventsPerSock events_per_sock; | 
| 2037 |  | 
 | 
| 2038 | 0 |     for (const ListenSocket& hListenSocket : vhListenSocket) { | 
| 2039 | 0 |         events_per_sock.emplace(hListenSocket.sock, Sock::Events{Sock::RECV}); | 
| 2040 | 0 |     } | 
| 2041 |  | 
 | 
| 2042 | 0 |     for (CNode* pnode : nodes) { | 
| 2043 | 0 |         bool select_recv = !pnode->fPauseRecv; | 
| 2044 | 0 |         bool select_send; | 
| 2045 | 0 |         { | 
| 2046 | 0 |             LOCK(pnode->cs_vSend); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2047 |  |             // Sending is possible if either there are bytes to send right now, or if there will be | 
| 2048 |  |             // once a potential message from vSendMsg is handed to the transport. GetBytesToSend | 
| 2049 |  |             // determines both of these in a single call. | 
| 2050 | 0 |             const auto& [to_send, more, _msg_type] = pnode->m_transport->GetBytesToSend(!pnode->vSendMsg.empty()); | 
| 2051 | 0 |             select_send = !to_send.empty() || more; | 
| 2052 | 0 |         } | 
| 2053 | 0 |         if (!select_recv && !select_send) continue; | 
| 2054 |  |  | 
| 2055 | 0 |         LOCK(pnode->m_sock_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2056 | 0 |         if (pnode->m_sock) { | 
| 2057 | 0 |             Sock::Event event = (select_send ? Sock::SEND : 0) | (select_recv ? Sock::RECV : 0); | 
| 2058 | 0 |             events_per_sock.emplace(pnode->m_sock, Sock::Events{event}); | 
| 2059 | 0 |         } | 
| 2060 | 0 |     } | 
| 2061 |  | 
 | 
| 2062 | 0 |     return events_per_sock; | 
| 2063 | 0 | } | 
| 2064 |  |  | 
| 2065 |  | void CConnman::SocketHandler() | 
| 2066 | 0 | { | 
| 2067 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2068 |  | 
 | 
| 2069 | 0 |     Sock::EventsPerSock events_per_sock; | 
| 2070 |  | 
 | 
| 2071 | 0 |     { | 
| 2072 | 0 |         const NodesSnapshot snap{*this, /*shuffle=*/false}; | 
| 2073 |  | 
 | 
| 2074 | 0 |         const auto timeout = std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS); | 
| 2075 |  |  | 
| 2076 |  |         // Check for the readiness of the already connected sockets and the | 
| 2077 |  |         // listening sockets in one call ("readiness" as in poll(2) or | 
| 2078 |  |         // select(2)). If none are ready, wait for a short while and return | 
| 2079 |  |         // empty sets. | 
| 2080 | 0 |         events_per_sock = GenerateWaitSockets(snap.Nodes()); | 
| 2081 | 0 |         if (events_per_sock.empty() || !events_per_sock.begin()->first->WaitMany(timeout, events_per_sock)) { | 
| 2082 | 0 |             m_interrupt_net->sleep_for(timeout); | 
| 2083 | 0 |         } | 
| 2084 |  |  | 
| 2085 |  |         // Service (send/receive) each of the already connected nodes. | 
| 2086 | 0 |         SocketHandlerConnected(snap.Nodes(), events_per_sock); | 
| 2087 | 0 |     } | 
| 2088 |  |  | 
| 2089 |  |     // Accept new connections from listening sockets. | 
| 2090 | 0 |     SocketHandlerListening(events_per_sock); | 
| 2091 | 0 | } | 
| 2092 |  |  | 
| 2093 |  | void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes, | 
| 2094 |  |                                       const Sock::EventsPerSock& events_per_sock) | 
| 2095 | 0 | { | 
| 2096 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2097 |  | 
 | 
| 2098 | 0 |     for (CNode* pnode : nodes) { | 
| 2099 | 0 |         if (m_interrupt_net->interrupted()) { | 
| 2100 | 0 |             return; | 
| 2101 | 0 |         } | 
| 2102 |  |  | 
| 2103 |  |         // | 
| 2104 |  |         // Receive | 
| 2105 |  |         // | 
| 2106 | 0 |         bool recvSet = false; | 
| 2107 | 0 |         bool sendSet = false; | 
| 2108 | 0 |         bool errorSet = false; | 
| 2109 | 0 |         { | 
| 2110 | 0 |             LOCK(pnode->m_sock_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2111 | 0 |             if (!pnode->m_sock) { | 
| 2112 | 0 |                 continue; | 
| 2113 | 0 |             } | 
| 2114 | 0 |             const auto it = events_per_sock.find(pnode->m_sock); | 
| 2115 | 0 |             if (it != events_per_sock.end()) { | 
| 2116 | 0 |                 recvSet = it->second.occurred & Sock::RECV; | 
| 2117 | 0 |                 sendSet = it->second.occurred & Sock::SEND; | 
| 2118 | 0 |                 errorSet = it->second.occurred & Sock::ERR; | 
| 2119 | 0 |             } | 
| 2120 | 0 |         } | 
| 2121 |  |  | 
| 2122 | 0 |         if (sendSet) { | 
| 2123 |  |             // Send data | 
| 2124 | 0 |             auto [bytes_sent, data_left] = WITH_LOCK(pnode->cs_vSend, return SocketSendData(*pnode)); | Line | Count | Source |  | 290 | 0 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) | 
 | 
| 2125 | 0 |             if (bytes_sent) { | 
| 2126 | 0 |                 RecordBytesSent(bytes_sent); | 
| 2127 |  |  | 
| 2128 |  |                 // If both receiving and (non-optimistic) sending were possible, we first attempt | 
| 2129 |  |                 // sending. If that succeeds, but does not fully drain the send queue, do not | 
| 2130 |  |                 // attempt to receive. This avoids needlessly queueing data if the remote peer | 
| 2131 |  |                 // is slow at receiving data, by means of TCP flow control. We only do this when | 
| 2132 |  |                 // sending actually succeeded to make sure progress is always made; otherwise a | 
| 2133 |  |                 // deadlock would be possible when both sides have data to send, but neither is | 
| 2134 |  |                 // receiving. | 
| 2135 | 0 |                 if (data_left) recvSet = false; | 
| 2136 | 0 |             } | 
| 2137 | 0 |         } | 
| 2138 |  | 
 | 
| 2139 | 0 |         if (recvSet || errorSet) | 
| 2140 | 0 |         { | 
| 2141 |  |             // typical socket buffer is 8K-64K | 
| 2142 | 0 |             uint8_t pchBuf[0x10000]; | 
| 2143 | 0 |             int nBytes = 0; | 
| 2144 | 0 |             { | 
| 2145 | 0 |                 LOCK(pnode->m_sock_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2146 | 0 |                 if (!pnode->m_sock) { | 
| 2147 | 0 |                     continue; | 
| 2148 | 0 |                 } | 
| 2149 | 0 |                 nBytes = pnode->m_sock->Recv(pchBuf, sizeof(pchBuf), MSG_DONTWAIT); | 
| 2150 | 0 |             } | 
| 2151 | 0 |             if (nBytes > 0) | 
| 2152 | 0 |             { | 
| 2153 | 0 |                 bool notify = false; | 
| 2154 | 0 |                 if (!pnode->ReceiveMsgBytes({pchBuf, (size_t)nBytes}, notify)) { | 
| 2155 | 0 |                     LogDebug(BCLog::NET, | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2156 | 0 |                         "receiving message bytes failed, %s\n", | 
| 2157 | 0 |                         pnode->DisconnectMsg(fLogIPs) | 
| 2158 | 0 |                     ); | 
| 2159 | 0 |                     pnode->CloseSocketDisconnect(); | 
| 2160 | 0 |                 } | 
| 2161 | 0 |                 RecordBytesRecv(nBytes); | 
| 2162 | 0 |                 if (notify) { | 
| 2163 | 0 |                     pnode->MarkReceivedMsgsForProcessing(); | 
| 2164 | 0 |                     WakeMessageHandler(); | 
| 2165 | 0 |                 } | 
| 2166 | 0 |             } | 
| 2167 | 0 |             else if (nBytes == 0) | 
| 2168 | 0 |             { | 
| 2169 |  |                 // socket closed gracefully | 
| 2170 | 0 |                 if (!pnode->fDisconnect) { | 
| 2171 | 0 |                     LogDebug(BCLog::NET, "socket closed, %s\n", pnode->DisconnectMsg(fLogIPs)); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2172 | 0 |                 } | 
| 2173 | 0 |                 pnode->CloseSocketDisconnect(); | 
| 2174 | 0 |             } | 
| 2175 | 0 |             else if (nBytes < 0) | 
| 2176 | 0 |             { | 
| 2177 |  |                 // error | 
| 2178 | 0 |                 int nErr = WSAGetLastError(); | Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 2179 | 0 |                 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | Line | Count | Source |  | 49 | 0 | #define WSAEWOULDBLOCK      EWOULDBLOCK | 
 |                 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | Line | Count | Source |  | 51 | 0 | #define WSAEMSGSIZE         EMSGSIZE | 
 |                 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | Line | Count | Source |  | 52 | 0 | #define WSAEINTR            EINTR | 
 |                 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | Line | Count | Source |  | 53 | 0 | #define WSAEINPROGRESS      EINPROGRESS | 
 | 
| 2180 | 0 |                 { | 
| 2181 | 0 |                     if (!pnode->fDisconnect) { | 
| 2182 | 0 |                         LogDebug(BCLog::NET, "socket recv error, %s: %s\n", pnode->DisconnectMsg(fLogIPs), NetworkErrorString(nErr)); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2183 | 0 |                     } | 
| 2184 | 0 |                     pnode->CloseSocketDisconnect(); | 
| 2185 | 0 |                 } | 
| 2186 | 0 |             } | 
| 2187 | 0 |         } | 
| 2188 |  |  | 
| 2189 | 0 |         if (InactivityCheck(*pnode)) pnode->fDisconnect = true; | 
| 2190 | 0 |     } | 
| 2191 | 0 | } | 
| 2192 |  |  | 
| 2193 |  | void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock) | 
| 2194 | 0 | { | 
| 2195 | 0 |     for (const ListenSocket& listen_socket : vhListenSocket) { | 
| 2196 | 0 |         if (m_interrupt_net->interrupted()) { | 
| 2197 | 0 |             return; | 
| 2198 | 0 |         } | 
| 2199 | 0 |         const auto it = events_per_sock.find(listen_socket.sock); | 
| 2200 | 0 |         if (it != events_per_sock.end() && it->second.occurred & Sock::RECV) { | 
| 2201 | 0 |             AcceptConnection(listen_socket); | 
| 2202 | 0 |         } | 
| 2203 | 0 |     } | 
| 2204 | 0 | } | 
| 2205 |  |  | 
| 2206 |  | void CConnman::ThreadSocketHandler() | 
| 2207 | 0 | { | 
| 2208 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2209 |  | 
 | 
| 2210 | 0 |     while (!m_interrupt_net->interrupted()) { | 
| 2211 | 0 |         DisconnectNodes(); | 
| 2212 | 0 |         NotifyNumConnectionsChanged(); | 
| 2213 | 0 |         SocketHandler(); | 
| 2214 | 0 |     } | 
| 2215 | 0 | } | 
| 2216 |  |  | 
| 2217 |  | void CConnman::WakeMessageHandler() | 
| 2218 | 20.3k | { | 
| 2219 | 20.3k |     { | 
| 2220 | 20.3k |         LOCK(mutexMsgProc); | Line | Count | Source |  | 259 | 20.3k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 20.3k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 20.3k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 20.3k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2221 | 20.3k |         fMsgProcWake = true; | 
| 2222 | 20.3k |     } | 
| 2223 | 20.3k |     condMsgProc.notify_one(); | 
| 2224 | 20.3k | } | 
| 2225 |  |  | 
| 2226 |  | void CConnman::ThreadDNSAddressSeed() | 
| 2227 | 0 | { | 
| 2228 | 0 |     int outbound_connection_count = 0; | 
| 2229 |  | 
 | 
| 2230 | 0 |     if (!gArgs.GetArgs("-seednode").empty()) { | 
| 2231 | 0 |         auto start = NodeClock::now(); | 
| 2232 | 0 |         constexpr std::chrono::seconds SEEDNODE_TIMEOUT = 30s; | 
| 2233 | 0 |         LogPrintf("-seednode enabled. Trying the provided seeds for %d seconds before defaulting to the dnsseeds.\n", SEEDNODE_TIMEOUT.count());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2234 | 0 |         while (!m_interrupt_net->interrupted()) { | 
| 2235 | 0 |             if (!m_interrupt_net->sleep_for(500ms)) { | 
| 2236 | 0 |                 return; | 
| 2237 | 0 |             } | 
| 2238 |  |  | 
| 2239 |  |             // Abort if we have spent enough time without reaching our target. | 
| 2240 |  |             // Giving seed nodes 30 seconds so this does not become a race against fixedseeds (which triggers after 1 min) | 
| 2241 | 0 |             if (NodeClock::now() > start + SEEDNODE_TIMEOUT) { | 
| 2242 | 0 |                 LogPrintf("Couldn't connect to enough peers via seed nodes. Handing fetch logic to the DNS seeds.\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2243 | 0 |                 break; | 
| 2244 | 0 |             } | 
| 2245 |  |  | 
| 2246 | 0 |             outbound_connection_count = GetFullOutboundConnCount(); | 
| 2247 | 0 |             if (outbound_connection_count >= SEED_OUTBOUND_CONNECTION_THRESHOLD) { | 
| 2248 | 0 |                 LogPrintf("P2P peers available. Finished fetching data from seed nodes.\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2249 | 0 |                 break; | 
| 2250 | 0 |             } | 
| 2251 | 0 |         } | 
| 2252 | 0 |     } | 
| 2253 |  |  | 
| 2254 | 0 |     FastRandomContext rng; | 
| 2255 | 0 |     std::vector<std::string> seeds = m_params.DNSSeeds(); | 
| 2256 | 0 |     std::shuffle(seeds.begin(), seeds.end(), rng); | 
| 2257 | 0 |     int seeds_right_now = 0; // Number of seeds left before testing if we have enough connections | 
| 2258 |  | 
 | 
| 2259 | 0 |     if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) { | 
| 2260 |  |         // When -forcednsseed is provided, query all. | 
| 2261 | 0 |         seeds_right_now = seeds.size(); | 
| 2262 | 0 |     } else if (addrman.Size() == 0) { | 
| 2263 |  |         // If we have no known peers, query all. | 
| 2264 |  |         // This will occur on the first run, or if peers.dat has been | 
| 2265 |  |         // deleted. | 
| 2266 | 0 |         seeds_right_now = seeds.size(); | 
| 2267 | 0 |     } | 
| 2268 |  |  | 
| 2269 |  |     // Proceed with dnsseeds if seednodes hasn't reached the target or if forcednsseed is set | 
| 2270 | 0 |     if (outbound_connection_count < SEED_OUTBOUND_CONNECTION_THRESHOLD || seeds_right_now) { | 
| 2271 |  |         // goal: only query DNS seed if address need is acute | 
| 2272 |  |         // * If we have a reasonable number of peers in addrman, spend | 
| 2273 |  |         //   some time trying them first. This improves user privacy by | 
| 2274 |  |         //   creating fewer identifying DNS requests, reduces trust by | 
| 2275 |  |         //   giving seeds less influence on the network topology, and | 
| 2276 |  |         //   reduces traffic to the seeds. | 
| 2277 |  |         // * When querying DNS seeds query a few at once, this ensures | 
| 2278 |  |         //   that we don't give DNS seeds the ability to eclipse nodes | 
| 2279 |  |         //   that query them. | 
| 2280 |  |         // * If we continue having problems, eventually query all the | 
| 2281 |  |         //   DNS seeds, and if that fails too, also try the fixed seeds. | 
| 2282 |  |         //   (done in ThreadOpenConnections) | 
| 2283 | 0 |         int found = 0; | 
| 2284 | 0 |         const std::chrono::seconds seeds_wait_time = (addrman.Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS); | 
| 2285 |  | 
 | 
| 2286 | 0 |         for (const std::string& seed : seeds) { | 
| 2287 | 0 |             if (seeds_right_now == 0) { | 
| 2288 | 0 |                 seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE; | 
| 2289 |  | 
 | 
| 2290 | 0 |                 if (addrman.Size() > 0) { | 
| 2291 | 0 |                     LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2292 | 0 |                     std::chrono::seconds to_wait = seeds_wait_time; | 
| 2293 | 0 |                     while (to_wait.count() > 0) { | 
| 2294 |  |                         // if sleeping for the MANY_PEERS interval, wake up | 
| 2295 |  |                         // early to see if we have enough peers and can stop | 
| 2296 |  |                         // this thread entirely freeing up its resources | 
| 2297 | 0 |                         std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait); | 
| 2298 | 0 |                         if (!m_interrupt_net->sleep_for(w)) return; | 
| 2299 | 0 |                         to_wait -= w; | 
| 2300 |  | 
 | 
| 2301 | 0 |                         if (GetFullOutboundConnCount() >= SEED_OUTBOUND_CONNECTION_THRESHOLD) { | 
| 2302 | 0 |                             if (found > 0) { | 
| 2303 | 0 |                                 LogPrintf("%d addresses found from DNS seeds\n", found);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2304 | 0 |                                 LogPrintf("P2P peers available. Finished DNS seeding.\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2305 | 0 |                             } else { | 
| 2306 | 0 |                                 LogPrintf("P2P peers available. Skipped DNS seeding.\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2307 | 0 |                             } | 
| 2308 | 0 |                             return; | 
| 2309 | 0 |                         } | 
| 2310 | 0 |                     } | 
| 2311 | 0 |                 } | 
| 2312 | 0 |             } | 
| 2313 |  |  | 
| 2314 | 0 |             if (m_interrupt_net->interrupted()) return; | 
| 2315 |  |  | 
| 2316 |  |             // hold off on querying seeds if P2P network deactivated | 
| 2317 | 0 |             if (!fNetworkActive) { | 
| 2318 | 0 |                 LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2319 | 0 |                 do { | 
| 2320 | 0 |                     if (!m_interrupt_net->sleep_for(1s)) return; | 
| 2321 | 0 |                 } while (!fNetworkActive); | 
| 2322 | 0 |             } | 
| 2323 |  |  | 
| 2324 | 0 |             LogPrintf("Loading addresses from DNS seed %s\n", seed);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2325 |  |             // If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address | 
| 2326 |  |             // for the base dns seed domain in chainparams | 
| 2327 | 0 |             if (HaveNameProxy()) { | 
| 2328 | 0 |                 AddAddrFetch(seed); | 
| 2329 | 0 |             } else { | 
| 2330 | 0 |                 std::vector<CAddress> vAdd; | 
| 2331 | 0 |                 constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()}; | 
| 2332 | 0 |                 std::string host = strprintf("x%x.%s", requiredServiceBits, seed);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 2333 | 0 |                 CNetAddr resolveSource; | 
| 2334 | 0 |                 if (!resolveSource.SetInternal(host)) { | 
| 2335 | 0 |                     continue; | 
| 2336 | 0 |                 } | 
| 2337 |  |                 // Limit number of IPs learned from a single DNS seed. This limit exists to prevent the results from | 
| 2338 |  |                 // one DNS seed from dominating AddrMan. Note that the number of results from a UDP DNS query is | 
| 2339 |  |                 // bounded to 33 already, but it is possible for it to use TCP where a larger number of results can be | 
| 2340 |  |                 // returned. | 
| 2341 | 0 |                 unsigned int nMaxIPs = 32; | 
| 2342 | 0 |                 const auto addresses{LookupHost(host, nMaxIPs, true)}; | 
| 2343 | 0 |                 if (!addresses.empty()) { | 
| 2344 | 0 |                     for (const CNetAddr& ip : addresses) { | 
| 2345 | 0 |                         CAddress addr = CAddress(CService(ip, m_params.GetDefaultPort()), requiredServiceBits); | 
| 2346 | 0 |                         addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old | 
| 2347 | 0 |                         vAdd.push_back(addr); | 
| 2348 | 0 |                         found++; | 
| 2349 | 0 |                     } | 
| 2350 | 0 |                     addrman.Add(vAdd, resolveSource); | 
| 2351 | 0 |                 } else { | 
| 2352 |  |                     // If the seed does not support a subdomain with our desired service bits, | 
| 2353 |  |                     // we make an ADDR_FETCH connection to the DNS resolved peer address for the | 
| 2354 |  |                     // base dns seed domain in chainparams | 
| 2355 | 0 |                     AddAddrFetch(seed); | 
| 2356 | 0 |                 } | 
| 2357 | 0 |             } | 
| 2358 | 0 |             --seeds_right_now; | 
| 2359 | 0 |         } | 
| 2360 | 0 |         LogPrintf("%d addresses found from DNS seeds\n", found);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2361 | 0 |     } else { | 
| 2362 | 0 |         LogPrintf("Skipping DNS seeds. Enough peers have been found\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2363 | 0 |     } | 
| 2364 | 0 | } | 
| 2365 |  |  | 
| 2366 |  | void CConnman::DumpAddresses() | 
| 2367 | 0 | { | 
| 2368 | 0 |     const auto start{SteadyClock::now()}; | 
| 2369 |  | 
 | 
| 2370 | 0 |     DumpPeerAddresses(::gArgs, addrman); | 
| 2371 |  | 
 | 
| 2372 | 0 |     LogDebug(BCLog::NET, "Flushed %d addresses to peers.dat  %dms\n", | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2373 | 0 |              addrman.Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); | 
| 2374 | 0 | } | 
| 2375 |  |  | 
| 2376 |  | void CConnman::ProcessAddrFetch() | 
| 2377 | 0 | { | 
| 2378 | 0 |     AssertLockNotHeld(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2379 | 0 |     std::string strDest; | 
| 2380 | 0 |     { | 
| 2381 | 0 |         LOCK(m_addr_fetches_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2382 | 0 |         if (m_addr_fetches.empty()) | 
| 2383 | 0 |             return; | 
| 2384 | 0 |         strDest = m_addr_fetches.front(); | 
| 2385 | 0 |         m_addr_fetches.pop_front(); | 
| 2386 | 0 |     } | 
| 2387 |  |     // Attempt v2 connection if we support v2 - we'll reconnect with v1 if our | 
| 2388 |  |     // peer doesn't support it or immediately disconnects us for another reason. | 
| 2389 | 0 |     const bool use_v2transport(GetLocalServices() & NODE_P2P_V2); | 
| 2390 | 0 |     CAddress addr; | 
| 2391 | 0 |     CountingSemaphoreGrant<> grant(*semOutbound, /*fTry=*/true); | 
| 2392 | 0 |     if (grant) { | 
| 2393 | 0 |         OpenNetworkConnection(addr, false, std::move(grant), strDest.c_str(), ConnectionType::ADDR_FETCH, use_v2transport); | 
| 2394 | 0 |     } | 
| 2395 | 0 | } | 
| 2396 |  |  | 
| 2397 |  | bool CConnman::GetTryNewOutboundPeer() const | 
| 2398 | 0 | { | 
| 2399 | 0 |     return m_try_another_outbound_peer; | 
| 2400 | 0 | } | 
| 2401 |  |  | 
| 2402 |  | void CConnman::SetTryNewOutboundPeer(bool flag) | 
| 2403 | 51.2k | { | 
| 2404 | 51.2k |     m_try_another_outbound_peer = flag; | 
| 2405 | 51.2k |     LogDebug(BCLog::NET, "setting try another outbound peer=%s\n", flag ? "true" : "false"); | Line | Count | Source |  | 381 | 51.2k | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 51.2k |     do {                                                              \ |  | 374 | 51.2k |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 51.2k |     } while (0) | 
 | 
 | 
| 2406 | 51.2k | } | 
| 2407 |  |  | 
| 2408 |  | void CConnman::StartExtraBlockRelayPeers() | 
| 2409 | 0 | { | 
| 2410 | 0 |     LogDebug(BCLog::NET, "enabling extra block-relay-only peers\n"); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2411 | 0 |     m_start_extra_block_relay_peers = true; | 
| 2412 | 0 | } | 
| 2413 |  |  | 
| 2414 |  | // Return the number of outbound connections that are full relay (not blocks only) | 
| 2415 |  | int CConnman::GetFullOutboundConnCount() const | 
| 2416 | 0 | { | 
| 2417 | 0 |     int nRelevant = 0; | 
| 2418 | 0 |     { | 
| 2419 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2420 | 0 |         for (const CNode* pnode : m_nodes) { | 
| 2421 | 0 |             if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant; | 
| 2422 | 0 |         } | 
| 2423 | 0 |     } | 
| 2424 | 0 |     return nRelevant; | 
| 2425 | 0 | } | 
| 2426 |  |  | 
| 2427 |  | // Return the number of peers we have over our outbound connection limit | 
| 2428 |  | // Exclude peers that are marked for disconnect, or are going to be | 
| 2429 |  | // disconnected soon (eg ADDR_FETCH and FEELER) | 
| 2430 |  | // Also exclude peers that haven't finished initial connection handshake yet | 
| 2431 |  | // (so that we don't decide we're over our desired connection limit, and then | 
| 2432 |  | // evict some peer that has finished the handshake) | 
| 2433 |  | int CConnman::GetExtraFullOutboundCount() const | 
| 2434 | 0 | { | 
| 2435 | 0 |     int full_outbound_peers = 0; | 
| 2436 | 0 |     { | 
| 2437 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2438 | 0 |         for (const CNode* pnode : m_nodes) { | 
| 2439 | 0 |             if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsFullOutboundConn()) { | 
| 2440 | 0 |                 ++full_outbound_peers; | 
| 2441 | 0 |             } | 
| 2442 | 0 |         } | 
| 2443 | 0 |     } | 
| 2444 | 0 |     return std::max(full_outbound_peers - m_max_outbound_full_relay, 0); | 
| 2445 | 0 | } | 
| 2446 |  |  | 
| 2447 |  | int CConnman::GetExtraBlockRelayCount() const | 
| 2448 | 0 | { | 
| 2449 | 0 |     int block_relay_peers = 0; | 
| 2450 | 0 |     { | 
| 2451 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2452 | 0 |         for (const CNode* pnode : m_nodes) { | 
| 2453 | 0 |             if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsBlockOnlyConn()) { | 
| 2454 | 0 |                 ++block_relay_peers; | 
| 2455 | 0 |             } | 
| 2456 | 0 |         } | 
| 2457 | 0 |     } | 
| 2458 | 0 |     return std::max(block_relay_peers - m_max_outbound_block_relay, 0); | 
| 2459 | 0 | } | 
| 2460 |  |  | 
| 2461 |  | std::unordered_set<Network> CConnman::GetReachableEmptyNetworks() const | 
| 2462 | 0 | { | 
| 2463 | 0 |     std::unordered_set<Network> networks{}; | 
| 2464 | 0 |     for (int n = 0; n < NET_MAX; n++) { | 
| 2465 | 0 |         enum Network net = (enum Network)n; | 
| 2466 | 0 |         if (net == NET_UNROUTABLE || net == NET_INTERNAL) continue; | 
| 2467 | 0 |         if (g_reachable_nets.Contains(net) && addrman.Size(net, std::nullopt) == 0) { | 
| 2468 | 0 |             networks.insert(net); | 
| 2469 | 0 |         } | 
| 2470 | 0 |     } | 
| 2471 | 0 |     return networks; | 
| 2472 | 0 | } | 
| 2473 |  |  | 
| 2474 |  | bool CConnman::MultipleManualOrFullOutboundConns(Network net) const | 
| 2475 | 0 | { | 
| 2476 | 0 |     AssertLockHeld(m_nodes_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2477 | 0 |     return m_network_conn_counts[net] > 1; | 
| 2478 | 0 | } | 
| 2479 |  |  | 
| 2480 |  | bool CConnman::MaybePickPreferredNetwork(std::optional<Network>& network) | 
| 2481 | 0 | { | 
| 2482 | 0 |     std::array<Network, 5> nets{NET_IPV4, NET_IPV6, NET_ONION, NET_I2P, NET_CJDNS}; | 
| 2483 | 0 |     std::shuffle(nets.begin(), nets.end(), FastRandomContext()); | 
| 2484 |  | 
 | 
| 2485 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2486 | 0 |     for (const auto net : nets) { | 
| 2487 | 0 |         if (g_reachable_nets.Contains(net) && m_network_conn_counts[net] == 0 && addrman.Size(net) != 0) { | 
| 2488 | 0 |             network = net; | 
| 2489 | 0 |             return true; | 
| 2490 | 0 |         } | 
| 2491 | 0 |     } | 
| 2492 |  |  | 
| 2493 | 0 |     return false; | 
| 2494 | 0 | } | 
| 2495 |  |  | 
| 2496 |  | void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std::span<const std::string> seed_nodes) | 
| 2497 | 0 | { | 
| 2498 | 0 |     AssertLockNotHeld(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2499 | 0 |     AssertLockNotHeld(m_reconnections_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2500 | 0 |     FastRandomContext rng; | 
| 2501 |  |     // Connect to specific addresses | 
| 2502 | 0 |     if (!connect.empty()) | 
| 2503 | 0 |     { | 
| 2504 |  |         // Attempt v2 connection if we support v2 - we'll reconnect with v1 if our | 
| 2505 |  |         // peer doesn't support it or immediately disconnects us for another reason. | 
| 2506 | 0 |         const bool use_v2transport(GetLocalServices() & NODE_P2P_V2); | 
| 2507 | 0 |         for (int64_t nLoop = 0;; nLoop++) | 
| 2508 | 0 |         { | 
| 2509 | 0 |             for (const std::string& strAddr : connect) | 
| 2510 | 0 |             { | 
| 2511 | 0 |                 CAddress addr(CService(), NODE_NONE); | 
| 2512 | 0 |                 OpenNetworkConnection(addr, false, {}, strAddr.c_str(), ConnectionType::MANUAL, /*use_v2transport=*/use_v2transport); | 
| 2513 | 0 |                 for (int i = 0; i < 10 && i < nLoop; i++) | 
| 2514 | 0 |                 { | 
| 2515 | 0 |                     if (!m_interrupt_net->sleep_for(500ms)) { | 
| 2516 | 0 |                         return; | 
| 2517 | 0 |                     } | 
| 2518 | 0 |                 } | 
| 2519 | 0 |             } | 
| 2520 | 0 |             if (!m_interrupt_net->sleep_for(500ms)) { | 
| 2521 | 0 |                 return; | 
| 2522 | 0 |             } | 
| 2523 | 0 |             PerformReconnections(); | 
| 2524 | 0 |         } | 
| 2525 | 0 |     } | 
| 2526 |  |  | 
| 2527 |  |     // Initiate network connections | 
| 2528 | 0 |     auto start = GetTime<std::chrono::microseconds>(); | 
| 2529 |  |  | 
| 2530 |  |     // Minimum time before next feeler connection (in microseconds). | 
| 2531 | 0 |     auto next_feeler = start + rng.rand_exp_duration(FEELER_INTERVAL); | 
| 2532 | 0 |     auto next_extra_block_relay = start + rng.rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); | 
| 2533 | 0 |     auto next_extra_network_peer{start + rng.rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL)}; | 
| 2534 | 0 |     const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED); | 
| 2535 | 0 |     bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS); | 
| 2536 | 0 |     const bool use_seednodes{!gArgs.GetArgs("-seednode").empty()}; | 
| 2537 |  | 
 | 
| 2538 | 0 |     auto seed_node_timer = NodeClock::now(); | 
| 2539 | 0 |     bool add_addr_fetch{addrman.Size() == 0 && !seed_nodes.empty()}; | 
| 2540 | 0 |     constexpr std::chrono::seconds ADD_NEXT_SEEDNODE = 10s; | 
| 2541 |  | 
 | 
| 2542 | 0 |     if (!add_fixed_seeds) { | 
| 2543 | 0 |         LogPrintf("Fixed seeds are disabled\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2544 | 0 |     } | 
| 2545 |  | 
 | 
| 2546 | 0 |     while (!m_interrupt_net->interrupted()) { | 
| 2547 | 0 |         if (add_addr_fetch) { | 
| 2548 | 0 |             add_addr_fetch = false; | 
| 2549 | 0 |             const auto& seed{SpanPopBack(seed_nodes)}; | 
| 2550 | 0 |             AddAddrFetch(seed); | 
| 2551 |  | 
 | 
| 2552 | 0 |             if (addrman.Size() == 0) { | 
| 2553 | 0 |                 LogInfo("Empty addrman, adding seednode (%s) to addrfetch\n", seed);| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 2554 | 0 |             } else { | 
| 2555 | 0 |                 LogInfo("Couldn't connect to peers from addrman after %d seconds. Adding seednode (%s) to addrfetch\n", ADD_NEXT_SEEDNODE.count(), seed);| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 2556 | 0 |             } | 
| 2557 | 0 |         } | 
| 2558 |  | 
 | 
| 2559 | 0 |         ProcessAddrFetch(); | 
| 2560 |  | 
 | 
| 2561 | 0 |         if (!m_interrupt_net->sleep_for(500ms)) { | 
| 2562 | 0 |             return; | 
| 2563 | 0 |         } | 
| 2564 |  |  | 
| 2565 | 0 |         PerformReconnections(); | 
| 2566 |  | 
 | 
| 2567 | 0 |         CountingSemaphoreGrant<> grant(*semOutbound); | 
| 2568 | 0 |         if (m_interrupt_net->interrupted()) { | 
| 2569 | 0 |             return; | 
| 2570 | 0 |         } | 
| 2571 |  |  | 
| 2572 | 0 |         const std::unordered_set<Network> fixed_seed_networks{GetReachableEmptyNetworks()}; | 
| 2573 | 0 |         if (add_fixed_seeds && !fixed_seed_networks.empty()) { | 
| 2574 |  |             // When the node starts with an empty peers.dat, there are a few other sources of peers before | 
| 2575 |  |             // we fallback on to fixed seeds: -dnsseed, -seednode, -addnode | 
| 2576 |  |             // If none of those are available, we fallback on to fixed seeds immediately, else we allow | 
| 2577 |  |             // 60 seconds for any of those sources to populate addrman. | 
| 2578 | 0 |             bool add_fixed_seeds_now = false; | 
| 2579 |  |             // It is cheapest to check if enough time has passed first. | 
| 2580 | 0 |             if (GetTime<std::chrono::seconds>() > start + std::chrono::minutes{1}) { | 
| 2581 | 0 |                 add_fixed_seeds_now = true; | 
| 2582 | 0 |                 LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty for at least one reachable network\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2583 | 0 |             } | 
| 2584 |  |  | 
| 2585 |  |             // Perform cheap checks before locking a mutex. | 
| 2586 | 0 |             else if (!dnsseed && !use_seednodes) { | 
| 2587 | 0 |                 LOCK(m_added_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2588 | 0 |                 if (m_added_node_params.empty()) { | 
| 2589 | 0 |                     add_fixed_seeds_now = true; | 
| 2590 | 0 |                     LogPrintf("Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet) and neither -addnode nor -seednode are provided\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2591 | 0 |                 } | 
| 2592 | 0 |             } | 
| 2593 |  | 
 | 
| 2594 | 0 |             if (add_fixed_seeds_now) { | 
| 2595 | 0 |                 std::vector<CAddress> seed_addrs{ConvertSeeds(m_params.FixedSeeds())}; | 
| 2596 |  |                 // We will not make outgoing connections to peers that are unreachable | 
| 2597 |  |                 // (e.g. because of -onlynet configuration). | 
| 2598 |  |                 // Therefore, we do not add them to addrman in the first place. | 
| 2599 |  |                 // In case previously unreachable networks become reachable | 
| 2600 |  |                 // (e.g. in case of -onlynet changes by the user), fixed seeds will | 
| 2601 |  |                 // be loaded only for networks for which we have no addresses. | 
| 2602 | 0 |                 seed_addrs.erase(std::remove_if(seed_addrs.begin(), seed_addrs.end(), | 
| 2603 | 0 |                                                 [&fixed_seed_networks](const CAddress& addr) { return fixed_seed_networks.count(addr.GetNetwork()) == 0; }), | 
| 2604 | 0 |                                  seed_addrs.end()); | 
| 2605 | 0 |                 CNetAddr local; | 
| 2606 | 0 |                 local.SetInternal("fixedseeds"); | 
| 2607 | 0 |                 addrman.Add(seed_addrs, local); | 
| 2608 | 0 |                 add_fixed_seeds = false; | 
| 2609 | 0 |                 LogPrintf("Added %d fixed seeds from reachable networks.\n", seed_addrs.size());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 2610 | 0 |             } | 
| 2611 | 0 |         } | 
| 2612 |  |  | 
| 2613 |  |         // | 
| 2614 |  |         // Choose an address to connect to based on most recently seen | 
| 2615 |  |         // | 
| 2616 | 0 |         CAddress addrConnect; | 
| 2617 |  |  | 
| 2618 |  |         // Only connect out to one peer per ipv4/ipv6 network group (/16 for IPv4). | 
| 2619 | 0 |         int nOutboundFullRelay = 0; | 
| 2620 | 0 |         int nOutboundBlockRelay = 0; | 
| 2621 | 0 |         int outbound_privacy_network_peers = 0; | 
| 2622 | 0 |         std::set<std::vector<unsigned char>> outbound_ipv46_peer_netgroups; | 
| 2623 |  | 
 | 
| 2624 | 0 |         { | 
| 2625 | 0 |             LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2626 | 0 |             for (const CNode* pnode : m_nodes) { | 
| 2627 | 0 |                 if (pnode->IsFullOutboundConn()) nOutboundFullRelay++; | 
| 2628 | 0 |                 if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++; | 
| 2629 |  |  | 
| 2630 |  |                 // Make sure our persistent outbound slots to ipv4/ipv6 peers belong to different netgroups. | 
| 2631 | 0 |                 switch (pnode->m_conn_type) { | 
| 2632 |  |                     // We currently don't take inbound connections into account. Since they are | 
| 2633 |  |                     // free to make, an attacker could make them to prevent us from connecting to | 
| 2634 |  |                     // certain peers. | 
| 2635 | 0 |                     case ConnectionType::INBOUND: | 
| 2636 |  |                     // Short-lived outbound connections should not affect how we select outbound | 
| 2637 |  |                     // peers from addrman. | 
| 2638 | 0 |                     case ConnectionType::ADDR_FETCH: | 
| 2639 | 0 |                     case ConnectionType::FEELER: | 
| 2640 | 0 |                         break; | 
| 2641 | 0 |                     case ConnectionType::MANUAL: | 
| 2642 | 0 |                     case ConnectionType::OUTBOUND_FULL_RELAY: | 
| 2643 | 0 |                     case ConnectionType::BLOCK_RELAY: | 
| 2644 | 0 |                         const CAddress address{pnode->addr}; | 
| 2645 | 0 |                         if (address.IsTor() || address.IsI2P() || address.IsCJDNS()) { | 
| 2646 |  |                             // Since our addrman-groups for these networks are | 
| 2647 |  |                             // random, without relation to the route we | 
| 2648 |  |                             // take to connect to these peers or to the | 
| 2649 |  |                             // difficulty in obtaining addresses with diverse | 
| 2650 |  |                             // groups, we don't worry about diversity with | 
| 2651 |  |                             // respect to our addrman groups when connecting to | 
| 2652 |  |                             // these networks. | 
| 2653 | 0 |                             ++outbound_privacy_network_peers; | 
| 2654 | 0 |                         } else { | 
| 2655 | 0 |                             outbound_ipv46_peer_netgroups.insert(m_netgroupman.GetGroup(address)); | 
| 2656 | 0 |                         } | 
| 2657 | 0 |                 } // no default case, so the compiler can warn about missing cases | 
| 2658 | 0 |             } | 
| 2659 | 0 |         } | 
| 2660 |  |  | 
| 2661 | 0 |         if (!seed_nodes.empty() && nOutboundFullRelay < SEED_OUTBOUND_CONNECTION_THRESHOLD) { | 
| 2662 | 0 |             if (NodeClock::now() > seed_node_timer + ADD_NEXT_SEEDNODE) { | 
| 2663 | 0 |                 seed_node_timer = NodeClock::now(); | 
| 2664 | 0 |                 add_addr_fetch = true; | 
| 2665 | 0 |             } | 
| 2666 | 0 |         } | 
| 2667 |  | 
 | 
| 2668 | 0 |         ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY; | 
| 2669 | 0 |         auto now = GetTime<std::chrono::microseconds>(); | 
| 2670 | 0 |         bool anchor = false; | 
| 2671 | 0 |         bool fFeeler = false; | 
| 2672 | 0 |         std::optional<Network> preferred_net; | 
| 2673 |  |  | 
| 2674 |  |         // Determine what type of connection to open. Opening | 
| 2675 |  |         // BLOCK_RELAY connections to addresses from anchors.dat gets the highest | 
| 2676 |  |         // priority. Then we open OUTBOUND_FULL_RELAY priority until we | 
| 2677 |  |         // meet our full-relay capacity. Then we open BLOCK_RELAY connection | 
| 2678 |  |         // until we hit our block-relay-only peer limit. | 
| 2679 |  |         // GetTryNewOutboundPeer() gets set when a stale tip is detected, so we | 
| 2680 |  |         // try opening an additional OUTBOUND_FULL_RELAY connection. If none of | 
| 2681 |  |         // these conditions are met, check to see if it's time to try an extra | 
| 2682 |  |         // block-relay-only peer (to confirm our tip is current, see below) or the next_feeler | 
| 2683 |  |         // timer to decide if we should open a FEELER. | 
| 2684 |  | 
 | 
| 2685 | 0 |         if (!m_anchors.empty() && (nOutboundBlockRelay < m_max_outbound_block_relay)) { | 
| 2686 | 0 |             conn_type = ConnectionType::BLOCK_RELAY; | 
| 2687 | 0 |             anchor = true; | 
| 2688 | 0 |         } else if (nOutboundFullRelay < m_max_outbound_full_relay) { | 
| 2689 |  |             // OUTBOUND_FULL_RELAY | 
| 2690 | 0 |         } else if (nOutboundBlockRelay < m_max_outbound_block_relay) { | 
| 2691 | 0 |             conn_type = ConnectionType::BLOCK_RELAY; | 
| 2692 | 0 |         } else if (GetTryNewOutboundPeer()) { | 
| 2693 |  |             // OUTBOUND_FULL_RELAY | 
| 2694 | 0 |         } else if (now > next_extra_block_relay && m_start_extra_block_relay_peers) { | 
| 2695 |  |             // Periodically connect to a peer (using regular outbound selection | 
| 2696 |  |             // methodology from addrman) and stay connected long enough to sync | 
| 2697 |  |             // headers, but not much else. | 
| 2698 |  |             // | 
| 2699 |  |             // Then disconnect the peer, if we haven't learned anything new. | 
| 2700 |  |             // | 
| 2701 |  |             // The idea is to make eclipse attacks very difficult to pull off, | 
| 2702 |  |             // because every few minutes we're finding a new peer to learn headers | 
| 2703 |  |             // from. | 
| 2704 |  |             // | 
| 2705 |  |             // This is similar to the logic for trying extra outbound (full-relay) | 
| 2706 |  |             // peers, except: | 
| 2707 |  |             // - we do this all the time on an exponential timer, rather than just when | 
| 2708 |  |             //   our tip is stale | 
| 2709 |  |             // - we potentially disconnect our next-youngest block-relay-only peer, if our | 
| 2710 |  |             //   newest block-relay-only peer delivers a block more recently. | 
| 2711 |  |             //   See the eviction logic in net_processing.cpp. | 
| 2712 |  |             // | 
| 2713 |  |             // Because we can promote these connections to block-relay-only | 
| 2714 |  |             // connections, they do not get their own ConnectionType enum | 
| 2715 |  |             // (similar to how we deal with extra outbound peers). | 
| 2716 | 0 |             next_extra_block_relay = now + rng.rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); | 
| 2717 | 0 |             conn_type = ConnectionType::BLOCK_RELAY; | 
| 2718 | 0 |         } else if (now > next_feeler) { | 
| 2719 | 0 |             next_feeler = now + rng.rand_exp_duration(FEELER_INTERVAL); | 
| 2720 | 0 |             conn_type = ConnectionType::FEELER; | 
| 2721 | 0 |             fFeeler = true; | 
| 2722 | 0 |         } else if (nOutboundFullRelay == m_max_outbound_full_relay && | 
| 2723 | 0 |                    m_max_outbound_full_relay == MAX_OUTBOUND_FULL_RELAY_CONNECTIONS && | 
| 2724 | 0 |                    now > next_extra_network_peer && | 
| 2725 | 0 |                    MaybePickPreferredNetwork(preferred_net)) { | 
| 2726 |  |             // Full outbound connection management: Attempt to get at least one | 
| 2727 |  |             // outbound peer from each reachable network by making extra connections | 
| 2728 |  |             // and then protecting "only" peers from a network during outbound eviction. | 
| 2729 |  |             // This is not attempted if the user changed -maxconnections to a value | 
| 2730 |  |             // so low that less than MAX_OUTBOUND_FULL_RELAY_CONNECTIONS are made, | 
| 2731 |  |             // to prevent interactions with otherwise protected outbound peers. | 
| 2732 | 0 |             next_extra_network_peer = now + rng.rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL); | 
| 2733 | 0 |         } else { | 
| 2734 |  |             // skip to next iteration of while loop | 
| 2735 | 0 |             continue; | 
| 2736 | 0 |         } | 
| 2737 |  |  | 
| 2738 | 0 |         addrman.ResolveCollisions(); | 
| 2739 |  | 
 | 
| 2740 | 0 |         const auto current_time{NodeClock::now()}; | 
| 2741 | 0 |         int nTries = 0; | 
| 2742 | 0 |         const auto reachable_nets{g_reachable_nets.All()}; | 
| 2743 |  | 
 | 
| 2744 | 0 |         while (!m_interrupt_net->interrupted()) { | 
| 2745 | 0 |             if (anchor && !m_anchors.empty()) { | 
| 2746 | 0 |                 const CAddress addr = m_anchors.back(); | 
| 2747 | 0 |                 m_anchors.pop_back(); | 
| 2748 | 0 |                 if (!addr.IsValid() || IsLocal(addr) || !g_reachable_nets.Contains(addr) || | 
| 2749 | 0 |                     !m_msgproc->HasAllDesirableServiceFlags(addr.nServices) || | 
| 2750 | 0 |                     outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) continue; | 
| 2751 | 0 |                 addrConnect = addr; | 
| 2752 | 0 |                 LogDebug(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2753 | 0 |                 break; | 
| 2754 | 0 |             } | 
| 2755 |  |  | 
| 2756 |  |             // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman, | 
| 2757 |  |             // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates | 
| 2758 |  |             // already-connected network ranges, ...) before trying new addrman addresses. | 
| 2759 | 0 |             nTries++; | 
| 2760 | 0 |             if (nTries > 100) | 
| 2761 | 0 |                 break; | 
| 2762 |  |  | 
| 2763 | 0 |             CAddress addr; | 
| 2764 | 0 |             NodeSeconds addr_last_try{0s}; | 
| 2765 |  | 
 | 
| 2766 | 0 |             if (fFeeler) { | 
| 2767 |  |                 // First, try to get a tried table collision address. This returns | 
| 2768 |  |                 // an empty (invalid) address if there are no collisions to try. | 
| 2769 | 0 |                 std::tie(addr, addr_last_try) = addrman.SelectTriedCollision(); | 
| 2770 |  | 
 | 
| 2771 | 0 |                 if (!addr.IsValid()) { | 
| 2772 |  |                     // No tried table collisions. Select a new table address | 
| 2773 |  |                     // for our feeler. | 
| 2774 | 0 |                     std::tie(addr, addr_last_try) = addrman.Select(true, reachable_nets); | 
| 2775 | 0 |                 } else if (AlreadyConnectedToAddress(addr)) { | 
| 2776 |  |                     // If test-before-evict logic would have us connect to a | 
| 2777 |  |                     // peer that we're already connected to, just mark that | 
| 2778 |  |                     // address as Good(). We won't be able to initiate the | 
| 2779 |  |                     // connection anyway, so this avoids inadvertently evicting | 
| 2780 |  |                     // a currently-connected peer. | 
| 2781 | 0 |                     addrman.Good(addr); | 
| 2782 |  |                     // Select a new table address for our feeler instead. | 
| 2783 | 0 |                     std::tie(addr, addr_last_try) = addrman.Select(true, reachable_nets); | 
| 2784 | 0 |                 } | 
| 2785 | 0 |             } else { | 
| 2786 |  |                 // Not a feeler | 
| 2787 |  |                 // If preferred_net has a value set, pick an extra outbound | 
| 2788 |  |                 // peer from that network. The eviction logic in net_processing | 
| 2789 |  |                 // ensures that a peer from another network will be evicted. | 
| 2790 | 0 |                 std::tie(addr, addr_last_try) = preferred_net.has_value() | 
| 2791 | 0 |                     ? addrman.Select(false, {*preferred_net}) | 
| 2792 | 0 |                     : addrman.Select(false, reachable_nets); | 
| 2793 | 0 |             } | 
| 2794 |  |  | 
| 2795 |  |             // Require outbound IPv4/IPv6 connections, other than feelers, to be to distinct network groups | 
| 2796 | 0 |             if (!fFeeler && outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) { | 
| 2797 | 0 |                 continue; | 
| 2798 | 0 |             } | 
| 2799 |  |  | 
| 2800 |  |             // if we selected an invalid or local address, restart | 
| 2801 | 0 |             if (!addr.IsValid() || IsLocal(addr)) { | 
| 2802 | 0 |                 break; | 
| 2803 | 0 |             } | 
| 2804 |  |  | 
| 2805 | 0 |             if (!g_reachable_nets.Contains(addr)) { | 
| 2806 | 0 |                 continue; | 
| 2807 | 0 |             } | 
| 2808 |  |  | 
| 2809 |  |             // only consider very recently tried nodes after 30 failed attempts | 
| 2810 | 0 |             if (current_time - addr_last_try < 10min && nTries < 30) { | 
| 2811 | 0 |                 continue; | 
| 2812 | 0 |             } | 
| 2813 |  |  | 
| 2814 |  |             // for non-feelers, require all the services we'll want, | 
| 2815 |  |             // for feelers, only require they be a full node (only because most | 
| 2816 |  |             // SPV clients don't have a good address DB available) | 
| 2817 | 0 |             if (!fFeeler && !m_msgproc->HasAllDesirableServiceFlags(addr.nServices)) { | 
| 2818 | 0 |                 continue; | 
| 2819 | 0 |             } else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) { | 
| 2820 | 0 |                 continue; | 
| 2821 | 0 |             } | 
| 2822 |  |  | 
| 2823 |  |             // Do not connect to bad ports, unless 50 invalid addresses have been selected already. | 
| 2824 | 0 |             if (nTries < 50 && (addr.IsIPv4() || addr.IsIPv6()) && IsBadPort(addr.GetPort())) { | 
| 2825 | 0 |                 continue; | 
| 2826 | 0 |             } | 
| 2827 |  |  | 
| 2828 |  |             // Do not make automatic outbound connections to addnode peers, to | 
| 2829 |  |             // not use our limited outbound slots for them and to ensure | 
| 2830 |  |             // addnode connections benefit from their intended protections. | 
| 2831 | 0 |             if (AddedNodesContain(addr)) { | 
| 2832 | 0 |                 LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "Not making automatic %s%s connection to %s peer selected for manual (addnode) connection%s\n", | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 2833 | 0 |                               preferred_net.has_value() ? "network-specific " : "", | 
| 2834 | 0 |                               ConnectionTypeAsString(conn_type), GetNetworkName(addr.GetNetwork()), | 
| 2835 | 0 |                               fLogIPs ? strprintf(": %s", addr.ToStringAddrPort()) : ""); | 
| 2836 | 0 |                 continue; | 
| 2837 | 0 |             } | 
| 2838 |  |  | 
| 2839 | 0 |             addrConnect = addr; | 
| 2840 | 0 |             break; | 
| 2841 | 0 |         } | 
| 2842 |  | 
 | 
| 2843 | 0 |         if (addrConnect.IsValid()) { | 
| 2844 | 0 |             if (fFeeler) { | 
| 2845 |  |                 // Add small amount of random noise before connection to avoid synchronization. | 
| 2846 | 0 |                 if (!m_interrupt_net->sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) { | 
| 2847 | 0 |                     return; | 
| 2848 | 0 |                 } | 
| 2849 | 0 |                 LogDebug(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2850 | 0 |             } | 
| 2851 |  |  | 
| 2852 | 0 |             if (preferred_net != std::nullopt) LogDebug(BCLog::NET, "Making network specific connection to %s on %s.\n", addrConnect.ToStringAddrPort(), GetNetworkName(preferred_net.value())); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 2853 |  |  | 
| 2854 |  |             // Record addrman failure attempts when node has at least 2 persistent outbound connections to peers with | 
| 2855 |  |             // different netgroups in ipv4/ipv6 networks + all peers in Tor/I2P/CJDNS networks. | 
| 2856 |  |             // Don't record addrman failure attempts when node is offline. This can be identified since all local | 
| 2857 |  |             // network connections (if any) belong in the same netgroup, and the size of `outbound_ipv46_peer_netgroups` would only be 1. | 
| 2858 | 0 |             const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(m_max_automatic_connections - 1, 2)}; | 
| 2859 |  |             // Use BIP324 transport when both us and them have NODE_V2_P2P set. | 
| 2860 | 0 |             const bool use_v2transport(addrConnect.nServices & GetLocalServices() & NODE_P2P_V2); | 
| 2861 | 0 |             OpenNetworkConnection(addrConnect, count_failures, std::move(grant), /*strDest=*/nullptr, conn_type, use_v2transport); | 
| 2862 | 0 |         } | 
| 2863 | 0 |     } | 
| 2864 | 0 | } | 
| 2865 |  |  | 
| 2866 |  | std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const | 
| 2867 | 0 | { | 
| 2868 | 0 |     std::vector<CAddress> ret; | 
| 2869 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2870 | 0 |     for (const CNode* pnode : m_nodes) { | 
| 2871 | 0 |         if (pnode->IsBlockOnlyConn()) { | 
| 2872 | 0 |             ret.push_back(pnode->addr); | 
| 2873 | 0 |         } | 
| 2874 | 0 |     } | 
| 2875 |  | 
 | 
| 2876 | 0 |     return ret; | 
| 2877 | 0 | } | 
| 2878 |  |  | 
| 2879 |  | std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo(bool include_connected) const | 
| 2880 | 0 | { | 
| 2881 | 0 |     std::vector<AddedNodeInfo> ret; | 
| 2882 |  | 
 | 
| 2883 | 0 |     std::list<AddedNodeParams> lAddresses(0); | 
| 2884 | 0 |     { | 
| 2885 | 0 |         LOCK(m_added_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2886 | 0 |         ret.reserve(m_added_node_params.size()); | 
| 2887 | 0 |         std::copy(m_added_node_params.cbegin(), m_added_node_params.cend(), std::back_inserter(lAddresses)); | 
| 2888 | 0 |     } | 
| 2889 |  |  | 
| 2890 |  |  | 
| 2891 |  |     // Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService | 
| 2892 | 0 |     std::map<CService, bool> mapConnected; | 
| 2893 | 0 |     std::map<std::string, std::pair<bool, CService>> mapConnectedByName; | 
| 2894 | 0 |     { | 
| 2895 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 2896 | 0 |         for (const CNode* pnode : m_nodes) { | 
| 2897 | 0 |             if (pnode->addr.IsValid()) { | 
| 2898 | 0 |                 mapConnected[pnode->addr] = pnode->IsInboundConn(); | 
| 2899 | 0 |             } | 
| 2900 | 0 |             std::string addrName{pnode->m_addr_name}; | 
| 2901 | 0 |             if (!addrName.empty()) { | 
| 2902 | 0 |                 mapConnectedByName[std::move(addrName)] = std::make_pair(pnode->IsInboundConn(), static_cast<const CService&>(pnode->addr)); | 
| 2903 | 0 |             } | 
| 2904 | 0 |         } | 
| 2905 | 0 |     } | 
| 2906 |  | 
 | 
| 2907 | 0 |     for (const auto& addr : lAddresses) { | 
| 2908 | 0 |         CService service{MaybeFlipIPv6toCJDNS(LookupNumeric(addr.m_added_node, GetDefaultPort(addr.m_added_node)))}; | 
| 2909 | 0 |         AddedNodeInfo addedNode{addr, CService(), false, false}; | 
| 2910 | 0 |         if (service.IsValid()) { | 
| 2911 |  |             // strAddNode is an IP:port | 
| 2912 | 0 |             auto it = mapConnected.find(service); | 
| 2913 | 0 |             if (it != mapConnected.end()) { | 
| 2914 | 0 |                 if (!include_connected) { | 
| 2915 | 0 |                     continue; | 
| 2916 | 0 |                 } | 
| 2917 | 0 |                 addedNode.resolvedAddress = service; | 
| 2918 | 0 |                 addedNode.fConnected = true; | 
| 2919 | 0 |                 addedNode.fInbound = it->second; | 
| 2920 | 0 |             } | 
| 2921 | 0 |         } else { | 
| 2922 |  |             // strAddNode is a name | 
| 2923 | 0 |             auto it = mapConnectedByName.find(addr.m_added_node); | 
| 2924 | 0 |             if (it != mapConnectedByName.end()) { | 
| 2925 | 0 |                 if (!include_connected) { | 
| 2926 | 0 |                     continue; | 
| 2927 | 0 |                 } | 
| 2928 | 0 |                 addedNode.resolvedAddress = it->second.second; | 
| 2929 | 0 |                 addedNode.fConnected = true; | 
| 2930 | 0 |                 addedNode.fInbound = it->second.first; | 
| 2931 | 0 |             } | 
| 2932 | 0 |         } | 
| 2933 | 0 |         ret.emplace_back(std::move(addedNode)); | 
| 2934 | 0 |     } | 
| 2935 |  | 
 | 
| 2936 | 0 |     return ret; | 
| 2937 | 0 | } | 
| 2938 |  |  | 
| 2939 |  | void CConnman::ThreadOpenAddedConnections() | 
| 2940 | 0 | { | 
| 2941 | 0 |     AssertLockNotHeld(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2942 | 0 |     AssertLockNotHeld(m_reconnections_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2943 | 0 |     while (true) | 
| 2944 | 0 |     { | 
| 2945 | 0 |         CountingSemaphoreGrant<> grant(*semAddnode); | 
| 2946 | 0 |         std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo(/*include_connected=*/false); | 
| 2947 | 0 |         bool tried = false; | 
| 2948 | 0 |         for (const AddedNodeInfo& info : vInfo) { | 
| 2949 | 0 |             if (!grant) { | 
| 2950 |  |                 // If we've used up our semaphore and need a new one, let's not wait here since while we are waiting | 
| 2951 |  |                 // the addednodeinfo state might change. | 
| 2952 | 0 |                 break; | 
| 2953 | 0 |             } | 
| 2954 | 0 |             tried = true; | 
| 2955 | 0 |             CAddress addr(CService(), NODE_NONE); | 
| 2956 | 0 |             OpenNetworkConnection(addr, false, std::move(grant), info.m_params.m_added_node.c_str(), ConnectionType::MANUAL, info.m_params.m_use_v2transport); | 
| 2957 | 0 |             if (!m_interrupt_net->sleep_for(500ms)) return; | 
| 2958 | 0 |             grant = CountingSemaphoreGrant<>(*semAddnode, /*fTry=*/true); | 
| 2959 | 0 |         } | 
| 2960 |  |         // See if any reconnections are desired. | 
| 2961 | 0 |         PerformReconnections(); | 
| 2962 |  |         // Retry every 60 seconds if a connection was attempted, otherwise two seconds | 
| 2963 | 0 |         if (!m_interrupt_net->sleep_for(tried ? 60s : 2s)) { | 
| 2964 | 0 |             return; | 
| 2965 | 0 |         } | 
| 2966 | 0 |     } | 
| 2967 | 0 | } | 
| 2968 |  |  | 
| 2969 |  | // if successful, this moves the passed grant to the constructed node | 
| 2970 |  | void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CountingSemaphoreGrant<>&& grant_outbound, const char *pszDest, ConnectionType conn_type, bool use_v2transport) | 
| 2971 | 0 | { | 
| 2972 | 0 |     AssertLockNotHeld(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 2973 | 0 |     assert(conn_type != ConnectionType::INBOUND); | 
| 2974 |  |  | 
| 2975 |  |     // | 
| 2976 |  |     // Initiate outbound network connection | 
| 2977 |  |     // | 
| 2978 | 0 |     if (m_interrupt_net->interrupted()) { | 
| 2979 | 0 |         return; | 
| 2980 | 0 |     } | 
| 2981 | 0 |     if (!fNetworkActive) { | 
| 2982 | 0 |         return; | 
| 2983 | 0 |     } | 
| 2984 | 0 |     if (!pszDest) { | 
| 2985 | 0 |         bool banned_or_discouraged = m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect)); | 
| 2986 | 0 |         if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) { | 
| 2987 | 0 |             return; | 
| 2988 | 0 |         } | 
| 2989 | 0 |     } else if (AlreadyConnectedToHost(pszDest)) { | 
| 2990 | 0 |         return; | 
| 2991 | 0 |     } | 
| 2992 |  |  | 
| 2993 | 0 |     CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport); | 
| 2994 |  | 
 | 
| 2995 | 0 |     if (!pnode) | 
| 2996 | 0 |         return; | 
| 2997 | 0 |     pnode->grantOutbound = std::move(grant_outbound); | 
| 2998 |  | 
 | 
| 2999 | 0 |     m_msgproc->InitializeNode(*pnode, m_local_services); | 
| 3000 | 0 |     { | 
| 3001 | 0 |         LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3002 | 0 |         m_nodes.push_back(pnode); | 
| 3003 |  |  | 
| 3004 |  |         // update connection count by network | 
| 3005 | 0 |         if (pnode->IsManualOrFullOutboundConn()) ++m_network_conn_counts[pnode->addr.GetNetwork()]; | 
| 3006 | 0 |     } | 
| 3007 |  | 
 | 
| 3008 | 0 |     TRACEPOINT(net, outbound_connection, | 
| 3009 | 0 |         pnode->GetId(), | 
| 3010 | 0 |         pnode->m_addr_name.c_str(), | 
| 3011 | 0 |         pnode->ConnectionTypeAsString().c_str(), | 
| 3012 | 0 |         pnode->ConnectedThroughNetwork(), | 
| 3013 | 0 |         GetNodeCount(ConnectionDirection::Out)); | 
| 3014 | 0 | } | 
| 3015 |  |  | 
| 3016 |  | Mutex NetEventsInterface::g_msgproc_mutex; | 
| 3017 |  |  | 
| 3018 |  | void CConnman::ThreadMessageHandler() | 
| 3019 | 0 | { | 
| 3020 | 0 |     LOCK(NetEventsInterface::g_msgproc_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3021 |  | 
 | 
| 3022 | 0 |     while (!flagInterruptMsgProc) | 
| 3023 | 0 |     { | 
| 3024 | 0 |         bool fMoreWork = false; | 
| 3025 |  | 
 | 
| 3026 | 0 |         { | 
| 3027 |  |             // Randomize the order in which we process messages from/to our peers. | 
| 3028 |  |             // This prevents attacks in which an attacker exploits having multiple | 
| 3029 |  |             // consecutive connections in the m_nodes list. | 
| 3030 | 0 |             const NodesSnapshot snap{*this, /*shuffle=*/true}; | 
| 3031 |  | 
 | 
| 3032 | 0 |             for (CNode* pnode : snap.Nodes()) { | 
| 3033 | 0 |                 if (pnode->fDisconnect) | 
| 3034 | 0 |                     continue; | 
| 3035 |  |  | 
| 3036 |  |                 // Receive messages | 
| 3037 | 0 |                 bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc); | 
| 3038 | 0 |                 fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); | 
| 3039 | 0 |                 if (flagInterruptMsgProc) | 
| 3040 | 0 |                     return; | 
| 3041 |  |                 // Send messages | 
| 3042 | 0 |                 m_msgproc->SendMessages(pnode); | 
| 3043 |  | 
 | 
| 3044 | 0 |                 if (flagInterruptMsgProc) | 
| 3045 | 0 |                     return; | 
| 3046 | 0 |             } | 
| 3047 | 0 |         } | 
| 3048 |  |  | 
| 3049 | 0 |         WAIT_LOCK(mutexMsgProc, lock); | Line | Count | Source |  | 265 | 0 | #define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs)) | Line | Count | Source |  | 263 | 0 | #define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__ | 
 | 
 | 
| 3050 | 0 |         if (!fMoreWork) { | 
| 3051 | 0 |             condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100), [this]() EXCLUSIVE_LOCKS_REQUIRED(mutexMsgProc) { return fMsgProcWake; }); | 
| 3052 | 0 |         } | 
| 3053 | 0 |         fMsgProcWake = false; | 
| 3054 | 0 |     } | 
| 3055 | 0 | } | 
| 3056 |  |  | 
| 3057 |  | void CConnman::ThreadI2PAcceptIncoming() | 
| 3058 | 0 | { | 
| 3059 | 0 |     static constexpr auto err_wait_begin = 1s; | 
| 3060 | 0 |     static constexpr auto err_wait_cap = 5min; | 
| 3061 | 0 |     auto err_wait = err_wait_begin; | 
| 3062 |  | 
 | 
| 3063 | 0 |     bool advertising_listen_addr = false; | 
| 3064 | 0 |     i2p::Connection conn; | 
| 3065 |  | 
 | 
| 3066 | 0 |     auto SleepOnFailure = [&]() { | 
| 3067 | 0 |         m_interrupt_net->sleep_for(err_wait); | 
| 3068 | 0 |         if (err_wait < err_wait_cap) { | 
| 3069 | 0 |             err_wait += 1s; | 
| 3070 | 0 |         } | 
| 3071 | 0 |     }; | 
| 3072 |  | 
 | 
| 3073 | 0 |     while (!m_interrupt_net->interrupted()) { | 
| 3074 |  | 
 | 
| 3075 | 0 |         if (!m_i2p_sam_session->Listen(conn)) { | 
| 3076 | 0 |             if (advertising_listen_addr && conn.me.IsValid()) { | 
| 3077 | 0 |                 RemoveLocal(conn.me); | 
| 3078 | 0 |                 advertising_listen_addr = false; | 
| 3079 | 0 |             } | 
| 3080 | 0 |             SleepOnFailure(); | 
| 3081 | 0 |             continue; | 
| 3082 | 0 |         } | 
| 3083 |  |  | 
| 3084 | 0 |         if (!advertising_listen_addr) { | 
| 3085 | 0 |             AddLocal(conn.me, LOCAL_MANUAL); | 
| 3086 | 0 |             advertising_listen_addr = true; | 
| 3087 | 0 |         } | 
| 3088 |  | 
 | 
| 3089 | 0 |         if (!m_i2p_sam_session->Accept(conn)) { | 
| 3090 | 0 |             SleepOnFailure(); | 
| 3091 | 0 |             continue; | 
| 3092 | 0 |         } | 
| 3093 |  |  | 
| 3094 | 0 |         CreateNodeFromAcceptedSocket(std::move(conn.sock), NetPermissionFlags::None, conn.me, conn.peer); | 
| 3095 |  | 
 | 
| 3096 | 0 |         err_wait = err_wait_begin; | 
| 3097 | 0 |     } | 
| 3098 | 0 | } | 
| 3099 |  |  | 
| 3100 |  | bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, NetPermissionFlags permissions) | 
| 3101 | 0 | { | 
| 3102 | 0 |     int nOne = 1; | 
| 3103 |  |  | 
| 3104 |  |     // Create socket for listening for incoming connections | 
| 3105 | 0 |     struct sockaddr_storage sockaddr; | 
| 3106 | 0 |     socklen_t len = sizeof(sockaddr); | 
| 3107 | 0 |     if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len)) | 
| 3108 | 0 |     { | 
| 3109 | 0 |         strError = Untranslated(strprintf("Bind address family for %s not supported", addrBind.ToStringAddrPort()));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 3110 | 0 |         LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 3111 | 0 |         return false; | 
| 3112 | 0 |     } | 
| 3113 |  |  | 
| 3114 | 0 |     std::unique_ptr<Sock> sock = CreateSock(addrBind.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP); | 
| 3115 | 0 |     if (!sock) { | 
| 3116 | 0 |         strError = Untranslated(strprintf("Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError())));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 |         strError = Untranslated(strprintf("Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError())));| Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 3117 | 0 |         LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 3118 | 0 |         return false; | 
| 3119 | 0 |     } | 
| 3120 |  |  | 
| 3121 |  |     // Allow binding if the port is still in TIME_WAIT state after | 
| 3122 |  |     // the program was closed and restarted. | 
| 3123 | 0 |     if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &nOne, sizeof(int)) == SOCKET_ERROR) {| Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 3124 | 0 |         strError = Untranslated(strprintf("Error setting SO_REUSEADDR on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 |         strError = Untranslated(strprintf("Error setting SO_REUSEADDR on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));| Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 3125 | 0 |         LogPrintf("%s\n", strError.original);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 3126 | 0 |     } | 
| 3127 |  |  | 
| 3128 |  |     // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option | 
| 3129 |  |     // and enable it by default or not. Try to enable it, if possible. | 
| 3130 | 0 |     if (addrBind.IsIPv6()) { | 
| 3131 | 0 | #ifdef IPV6_V6ONLY | 
| 3132 | 0 |         if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, &nOne, sizeof(int)) == SOCKET_ERROR) {| Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 3133 | 0 |             strError = Untranslated(strprintf("Error setting IPV6_V6ONLY on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 |             strError = Untranslated(strprintf("Error setting IPV6_V6ONLY on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));| Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 3134 | 0 |             LogPrintf("%s\n", strError.original);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 3135 | 0 |         } | 
| 3136 | 0 | #endif | 
| 3137 |  | #ifdef WIN32 | 
| 3138 |  |         int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED; | 
| 3139 |  |         if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &nProtLevel, sizeof(int)) == SOCKET_ERROR) { | 
| 3140 |  |             strError = Untranslated(strprintf("Error setting IPV6_PROTECTION_LEVEL on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError()))); | 
| 3141 |  |             LogPrintf("%s\n", strError.original); | 
| 3142 |  |         } | 
| 3143 |  | #endif | 
| 3144 | 0 |     } | 
| 3145 |  | 
 | 
| 3146 | 0 |     if (sock->Bind(reinterpret_cast<struct sockaddr*>(&sockaddr), len) == SOCKET_ERROR) {| Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 3147 | 0 |         int nErr = WSAGetLastError(); | Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 3148 | 0 |         if (nErr == WSAEADDRINUSE) | Line | Count | Source |  | 54 | 0 | #define WSAEADDRINUSE       EADDRINUSE | 
 | 
| 3149 | 0 |             strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToStringAddrPort(), CLIENT_NAME);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 |             strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToStringAddrPort(), CLIENT_NAME);| Line | Count | Source |  | 98 | 0 | #define CLIENT_NAME "Bitcoin Core" | 
 | 
| 3150 | 0 |         else | 
| 3151 | 0 |             strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToStringAddrPort(), NetworkErrorString(nErr));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 3152 | 0 |         LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 3153 | 0 |         return false; | 
| 3154 | 0 |     } | 
| 3155 | 0 |     LogPrintf("Bound to %s\n", addrBind.ToStringAddrPort());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 3156 |  |  | 
| 3157 |  |     // Listen for incoming connections | 
| 3158 | 0 |     if (sock->Listen(SOMAXCONN) == SOCKET_ERROR) | Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 3159 | 0 |     { | 
| 3160 | 0 |         strError = strprintf(_("Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 |         strError = strprintf(_("Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));| Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 3161 | 0 |         LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 3162 | 0 |         return false; | 
| 3163 | 0 |     } | 
| 3164 |  |  | 
| 3165 | 0 |     vhListenSocket.emplace_back(std::move(sock), permissions); | 
| 3166 | 0 |     return true; | 
| 3167 | 0 | } | 
| 3168 |  |  | 
| 3169 |  | void Discover() | 
| 3170 | 0 | { | 
| 3171 | 0 |     if (!fDiscover) | 
| 3172 | 0 |         return; | 
| 3173 |  |  | 
| 3174 | 0 |     for (const CNetAddr &addr: GetLocalAddresses()) { | 
| 3175 | 0 |         if (AddLocal(addr, LOCAL_IF)) | 
| 3176 | 0 |             LogPrintf("%s: %s\n", __func__, addr.ToStringAddr());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 3177 | 0 |     } | 
| 3178 | 0 | } | 
| 3179 |  |  | 
| 3180 |  | void CConnman::SetNetworkActive(bool active) | 
| 3181 | 51.2k | { | 
| 3182 | 51.2k |     LogPrintf("%s: %s\n", __func__, active);| Line | Count | Source |  | 361 | 51.2k | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 51.2k | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 51.2k | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 3183 |  |  | 
| 3184 | 51.2k |     if (fNetworkActive == active) { | 
| 3185 | 51.2k |         return; | 
| 3186 | 51.2k |     } | 
| 3187 |  |  | 
| 3188 | 0 |     fNetworkActive = active; | 
| 3189 |  | 
 | 
| 3190 | 0 |     if (m_client_interface) { | 
| 3191 | 0 |         m_client_interface->NotifyNetworkActiveChanged(fNetworkActive); | 
| 3192 | 0 |     } | 
| 3193 | 0 | } | 
| 3194 |  |  | 
| 3195 |  | CConnman::CConnman(uint64_t nSeed0In, | 
| 3196 |  |                    uint64_t nSeed1In, | 
| 3197 |  |                    AddrMan& addrman_in, | 
| 3198 |  |                    const NetGroupManager& netgroupman, | 
| 3199 |  |                    const CChainParams& params, | 
| 3200 |  |                    bool network_active, | 
| 3201 |  |                    std::shared_ptr<CThreadInterrupt> interrupt_net) | 
| 3202 | 51.2k |     : addrman(addrman_in) | 
| 3203 | 51.2k |     , m_netgroupman{netgroupman} | 
| 3204 | 51.2k |     , nSeed0(nSeed0In) | 
| 3205 | 51.2k |     , nSeed1(nSeed1In) | 
| 3206 | 51.2k |     , m_interrupt_net{interrupt_net} | 
| 3207 | 51.2k |     , m_params(params) | 
| 3208 | 51.2k | { | 
| 3209 | 51.2k |     SetTryNewOutboundPeer(false); | 
| 3210 |  |  | 
| 3211 | 51.2k |     Options connOptions; | 
| 3212 | 51.2k |     Init(connOptions); | 
| 3213 | 51.2k |     SetNetworkActive(network_active); | 
| 3214 | 51.2k | } | 
| 3215 |  |  | 
| 3216 |  | NodeId CConnman::GetNewNodeId() | 
| 3217 | 0 | { | 
| 3218 | 0 |     return nLastNodeId.fetch_add(1, std::memory_order_relaxed); | 
| 3219 | 0 | } | 
| 3220 |  |  | 
| 3221 |  | uint16_t CConnman::GetDefaultPort(Network net) const | 
| 3222 | 0 | { | 
| 3223 | 0 |     return net == NET_I2P ? I2P_SAM31_PORT : m_params.GetDefaultPort(); | 
| 3224 | 0 | } | 
| 3225 |  |  | 
| 3226 |  | uint16_t CConnman::GetDefaultPort(const std::string& addr) const | 
| 3227 | 0 | { | 
| 3228 | 0 |     CNetAddr a; | 
| 3229 | 0 |     return a.SetSpecial(addr) ? GetDefaultPort(a.GetNetwork()) : m_params.GetDefaultPort(); | 
| 3230 | 0 | } | 
| 3231 |  |  | 
| 3232 |  | bool CConnman::Bind(const CService& addr_, unsigned int flags, NetPermissionFlags permissions) | 
| 3233 | 0 | { | 
| 3234 | 0 |     const CService addr{MaybeFlipIPv6toCJDNS(addr_)}; | 
| 3235 |  | 
 | 
| 3236 | 0 |     bilingual_str strError; | 
| 3237 | 0 |     if (!BindListenPort(addr, strError, permissions)) { | 
| 3238 | 0 |         if ((flags & BF_REPORT_ERROR) && m_client_interface) { | 
| 3239 | 0 |             m_client_interface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR); | 
| 3240 | 0 |         } | 
| 3241 | 0 |         return false; | 
| 3242 | 0 |     } | 
| 3243 |  |  | 
| 3244 | 0 |     if (addr.IsRoutable() && fDiscover && !(flags & BF_DONT_ADVERTISE) && !NetPermissions::HasFlag(permissions, NetPermissionFlags::NoBan)) { | 
| 3245 | 0 |         AddLocal(addr, LOCAL_BIND); | 
| 3246 | 0 |     } | 
| 3247 |  | 
 | 
| 3248 | 0 |     return true; | 
| 3249 | 0 | } | 
| 3250 |  |  | 
| 3251 |  | bool CConnman::InitBinds(const Options& options) | 
| 3252 | 0 | { | 
| 3253 | 0 |     for (const auto& addrBind : options.vBinds) { | 
| 3254 | 0 |         if (!Bind(addrBind, BF_REPORT_ERROR, NetPermissionFlags::None)) { | 
| 3255 | 0 |             return false; | 
| 3256 | 0 |         } | 
| 3257 | 0 |     } | 
| 3258 | 0 |     for (const auto& addrBind : options.vWhiteBinds) { | 
| 3259 | 0 |         if (!Bind(addrBind.m_service, BF_REPORT_ERROR, addrBind.m_flags)) { | 
| 3260 | 0 |             return false; | 
| 3261 | 0 |         } | 
| 3262 | 0 |     } | 
| 3263 | 0 |     for (const auto& addr_bind : options.onion_binds) { | 
| 3264 | 0 |         if (!Bind(addr_bind, BF_REPORT_ERROR | BF_DONT_ADVERTISE, NetPermissionFlags::None)) { | 
| 3265 | 0 |             return false; | 
| 3266 | 0 |         } | 
| 3267 | 0 |     } | 
| 3268 | 0 |     if (options.bind_on_any) { | 
| 3269 |  |         // Don't consider errors to bind on IPv6 "::" fatal because the host OS | 
| 3270 |  |         // may not have IPv6 support and the user did not explicitly ask us to | 
| 3271 |  |         // bind on that. | 
| 3272 | 0 |         const CService ipv6_any{in6_addr(IN6ADDR_ANY_INIT), GetListenPort()}; // :: | 
| 3273 | 0 |         Bind(ipv6_any, BF_NONE, NetPermissionFlags::None); | 
| 3274 |  | 
 | 
| 3275 | 0 |         struct in_addr inaddr_any; | 
| 3276 | 0 |         inaddr_any.s_addr = htonl(INADDR_ANY); | 
| 3277 | 0 |         const CService ipv4_any{inaddr_any, GetListenPort()}; // 0.0.0.0 | 
| 3278 | 0 |         if (!Bind(ipv4_any, BF_REPORT_ERROR, NetPermissionFlags::None)) { | 
| 3279 | 0 |             return false; | 
| 3280 | 0 |         } | 
| 3281 | 0 |     } | 
| 3282 | 0 |     return true; | 
| 3283 | 0 | } | 
| 3284 |  |  | 
| 3285 |  | bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) | 
| 3286 | 0 | { | 
| 3287 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3288 | 0 |     Init(connOptions); | 
| 3289 |  | 
 | 
| 3290 | 0 |     if (fListen && !InitBinds(connOptions)) { | 
| 3291 | 0 |         if (m_client_interface) { | 
| 3292 | 0 |             m_client_interface->ThreadSafeMessageBox( | 
| 3293 | 0 |                 _("Failed to listen on any port. Use -listen=0 if you want this."), | 
| 3294 | 0 |                 "", CClientUIInterface::MSG_ERROR); | 
| 3295 | 0 |         } | 
| 3296 | 0 |         return false; | 
| 3297 | 0 |     } | 
| 3298 |  |  | 
| 3299 | 0 |     Proxy i2p_sam; | 
| 3300 | 0 |     if (GetProxy(NET_I2P, i2p_sam) && connOptions.m_i2p_accept_incoming) { | 
| 3301 | 0 |         m_i2p_sam_session = std::make_unique<i2p::sam::Session>(gArgs.GetDataDirNet() / "i2p_private_key", | 
| 3302 | 0 |                                                                 i2p_sam, m_interrupt_net); | 
| 3303 | 0 |     } | 
| 3304 |  |  | 
| 3305 |  |     // Randomize the order in which we may query seednode to potentially prevent connecting to the same one every restart (and signal that we have restarted) | 
| 3306 | 0 |     std::vector<std::string> seed_nodes = connOptions.vSeedNodes; | 
| 3307 | 0 |     if (!seed_nodes.empty()) { | 
| 3308 | 0 |         std::shuffle(seed_nodes.begin(), seed_nodes.end(), FastRandomContext{}); | 
| 3309 | 0 |     } | 
| 3310 |  | 
 | 
| 3311 | 0 |     if (m_use_addrman_outgoing) { | 
| 3312 |  |         // Load addresses from anchors.dat | 
| 3313 | 0 |         m_anchors = ReadAnchors(gArgs.GetDataDirNet() / ANCHORS_DATABASE_FILENAME); | 
| 3314 | 0 |         if (m_anchors.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) { | 
| 3315 | 0 |             m_anchors.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS); | 
| 3316 | 0 |         } | 
| 3317 | 0 |         LogPrintf("%i block-relay-only anchors will be tried for connections.\n", m_anchors.size());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 3318 | 0 |     } | 
| 3319 |  | 
 | 
| 3320 | 0 |     if (m_client_interface) { | 
| 3321 | 0 |         m_client_interface->InitMessage(_("Starting network threads…")); | 
| 3322 | 0 |     } | 
| 3323 |  | 
 | 
| 3324 | 0 |     fAddressesInitialized = true; | 
| 3325 |  | 
 | 
| 3326 | 0 |     if (semOutbound == nullptr) { | 
| 3327 |  |         // initialize semaphore | 
| 3328 | 0 |         semOutbound = std::make_unique<std::counting_semaphore<>>(std::min(m_max_automatic_outbound, m_max_automatic_connections)); | 
| 3329 | 0 |     } | 
| 3330 | 0 |     if (semAddnode == nullptr) { | 
| 3331 |  |         // initialize semaphore | 
| 3332 | 0 |         semAddnode = std::make_unique<std::counting_semaphore<>>(m_max_addnode); | 
| 3333 | 0 |     } | 
| 3334 |  |  | 
| 3335 |  |     // | 
| 3336 |  |     // Start threads | 
| 3337 |  |     // | 
| 3338 | 0 |     assert(m_msgproc); | 
| 3339 | 0 |     m_interrupt_net->reset(); | 
| 3340 | 0 |     flagInterruptMsgProc = false; | 
| 3341 |  | 
 | 
| 3342 | 0 |     { | 
| 3343 | 0 |         LOCK(mutexMsgProc); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3344 | 0 |         fMsgProcWake = false; | 
| 3345 | 0 |     } | 
| 3346 |  |  | 
| 3347 |  |     // Send and receive from sockets, accept connections | 
| 3348 | 0 |     threadSocketHandler = std::thread(&util::TraceThread, "net", [this] { ThreadSocketHandler(); }); | 
| 3349 |  | 
 | 
| 3350 | 0 |     if (!gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED)) | 
| 3351 | 0 |         LogPrintf("DNS seeding disabled\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 3352 | 0 |     else | 
| 3353 | 0 |         threadDNSAddressSeed = std::thread(&util::TraceThread, "dnsseed", [this] { ThreadDNSAddressSeed(); }); | 
| 3354 |  |  | 
| 3355 |  |     // Initiate manual connections | 
| 3356 | 0 |     threadOpenAddedConnections = std::thread(&util::TraceThread, "addcon", [this] { ThreadOpenAddedConnections(); }); | 
| 3357 |  | 
 | 
| 3358 | 0 |     if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) { | 
| 3359 | 0 |         if (m_client_interface) { | 
| 3360 | 0 |             m_client_interface->ThreadSafeMessageBox( | 
| 3361 | 0 |                 _("Cannot provide specific connections and have addrman find outgoing connections at the same time."), | 
| 3362 | 0 |                 "", CClientUIInterface::MSG_ERROR); | 
| 3363 | 0 |         } | 
| 3364 | 0 |         return false; | 
| 3365 | 0 |     } | 
| 3366 | 0 |     if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty()) { | 
| 3367 | 0 |         threadOpenConnections = std::thread( | 
| 3368 | 0 |             &util::TraceThread, "opencon", | 
| 3369 | 0 |             [this, connect = connOptions.m_specified_outgoing, seed_nodes = std::move(seed_nodes)] { ThreadOpenConnections(connect, seed_nodes); }); | 
| 3370 | 0 |     } | 
| 3371 |  |  | 
| 3372 |  |     // Process messages | 
| 3373 | 0 |     threadMessageHandler = std::thread(&util::TraceThread, "msghand", [this] { ThreadMessageHandler(); }); | 
| 3374 |  | 
 | 
| 3375 | 0 |     if (m_i2p_sam_session) { | 
| 3376 | 0 |         threadI2PAcceptIncoming = | 
| 3377 | 0 |             std::thread(&util::TraceThread, "i2paccept", [this] { ThreadI2PAcceptIncoming(); }); | 
| 3378 | 0 |     } | 
| 3379 |  |  | 
| 3380 |  |     // Dump network addresses | 
| 3381 | 0 |     scheduler.scheduleEvery([this] { DumpAddresses(); }, DUMP_PEERS_INTERVAL); | 
| 3382 |  |  | 
| 3383 |  |     // Run the ASMap Health check once and then schedule it to run every 24h. | 
| 3384 | 0 |     if (m_netgroupman.UsingASMap()) { | 
| 3385 | 0 |         ASMapHealthCheck(); | 
| 3386 | 0 |         scheduler.scheduleEvery([this] { ASMapHealthCheck(); }, ASMAP_HEALTH_CHECK_INTERVAL); | 
| 3387 | 0 |     } | 
| 3388 |  | 
 | 
| 3389 | 0 |     return true; | 
| 3390 | 0 | } | 
| 3391 |  |  | 
| 3392 |  | class CNetCleanup | 
| 3393 |  | { | 
| 3394 |  | public: | 
| 3395 |  |     CNetCleanup() = default; | 
| 3396 |  |  | 
| 3397 |  |     ~CNetCleanup() | 
| 3398 | 0 |     { | 
| 3399 |  | #ifdef WIN32 | 
| 3400 |  |         // Shutdown Windows Sockets | 
| 3401 |  |         WSACleanup(); | 
| 3402 |  | #endif | 
| 3403 | 0 |     } | 
| 3404 |  | }; | 
| 3405 |  | static CNetCleanup instance_of_cnetcleanup; | 
| 3406 |  |  | 
| 3407 |  | void CConnman::Interrupt() | 
| 3408 | 51.2k | { | 
| 3409 | 51.2k |     { | 
| 3410 | 51.2k |         LOCK(mutexMsgProc); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3411 | 51.2k |         flagInterruptMsgProc = true; | 
| 3412 | 51.2k |     } | 
| 3413 | 51.2k |     condMsgProc.notify_all(); | 
| 3414 |  |  | 
| 3415 | 51.2k |     (*m_interrupt_net)(); | 
| 3416 | 51.2k |     g_socks5_interrupt(); | 
| 3417 |  |  | 
| 3418 | 51.2k |     if (semOutbound) { | 
| 3419 | 0 |         for (int i=0; i<m_max_automatic_outbound; i++) { | 
| 3420 | 0 |             semOutbound->release(); | 
| 3421 | 0 |         } | 
| 3422 | 0 |     } | 
| 3423 |  |  | 
| 3424 | 51.2k |     if (semAddnode) { | 
| 3425 | 0 |         for (int i=0; i<m_max_addnode; i++) { | 
| 3426 | 0 |             semAddnode->release(); | 
| 3427 | 0 |         } | 
| 3428 | 0 |     } | 
| 3429 | 51.2k | } | 
| 3430 |  |  | 
| 3431 |  | void CConnman::StopThreads() | 
| 3432 | 51.2k | { | 
| 3433 | 51.2k |     if (threadI2PAcceptIncoming.joinable()) { | 
| 3434 | 0 |         threadI2PAcceptIncoming.join(); | 
| 3435 | 0 |     } | 
| 3436 | 51.2k |     if (threadMessageHandler.joinable()) | 
| 3437 | 0 |         threadMessageHandler.join(); | 
| 3438 | 51.2k |     if (threadOpenConnections.joinable()) | 
| 3439 | 0 |         threadOpenConnections.join(); | 
| 3440 | 51.2k |     if (threadOpenAddedConnections.joinable()) | 
| 3441 | 0 |         threadOpenAddedConnections.join(); | 
| 3442 | 51.2k |     if (threadDNSAddressSeed.joinable()) | 
| 3443 | 0 |         threadDNSAddressSeed.join(); | 
| 3444 | 51.2k |     if (threadSocketHandler.joinable()) | 
| 3445 | 0 |         threadSocketHandler.join(); | 
| 3446 | 51.2k | } | 
| 3447 |  |  | 
| 3448 |  | void CConnman::StopNodes() | 
| 3449 | 96.7k | { | 
| 3450 | 96.7k |     if (fAddressesInitialized) { | 
| 3451 | 0 |         DumpAddresses(); | 
| 3452 | 0 |         fAddressesInitialized = false; | 
| 3453 |  | 
 | 
| 3454 | 0 |         if (m_use_addrman_outgoing) { | 
| 3455 |  |             // Anchor connections are only dumped during clean shutdown. | 
| 3456 | 0 |             std::vector<CAddress> anchors_to_dump = GetCurrentBlockRelayOnlyConns(); | 
| 3457 | 0 |             if (anchors_to_dump.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) { | 
| 3458 | 0 |                 anchors_to_dump.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS); | 
| 3459 | 0 |             } | 
| 3460 | 0 |             DumpAnchors(gArgs.GetDataDirNet() / ANCHORS_DATABASE_FILENAME, anchors_to_dump); | 
| 3461 | 0 |         } | 
| 3462 | 0 |     } | 
| 3463 |  |  | 
| 3464 |  |     // Delete peer connections. | 
| 3465 | 96.7k |     std::vector<CNode*> nodes; | 
| 3466 | 96.7k |     WITH_LOCK(m_nodes_mutex, nodes.swap(m_nodes)); | Line | Count | Source |  | 290 | 96.7k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) | 
 | 
| 3467 | 192k |     for (CNode* pnode : nodes) { | 
| 3468 | 192k |         LogDebug(BCLog::NET, "Stopping node, %s", pnode->DisconnectMsg(fLogIPs)); | Line | Count | Source |  | 381 | 192k | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 192k |     do {                                                              \ |  | 374 | 192k |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 192k |     } while (0) | 
 | 
 | 
| 3469 | 192k |         pnode->CloseSocketDisconnect(); | 
| 3470 | 192k |         DeleteNode(pnode); | 
| 3471 | 192k |     } | 
| 3472 |  |  | 
| 3473 | 96.7k |     for (CNode* pnode : m_nodes_disconnected) { | 
| 3474 | 0 |         DeleteNode(pnode); | 
| 3475 | 0 |     } | 
| 3476 | 96.7k |     m_nodes_disconnected.clear(); | 
| 3477 | 96.7k |     vhListenSocket.clear(); | 
| 3478 | 96.7k |     semOutbound.reset(); | 
| 3479 | 96.7k |     semAddnode.reset(); | 
| 3480 | 96.7k | } | 
| 3481 |  |  | 
| 3482 |  | void CConnman::DeleteNode(CNode* pnode) | 
| 3483 | 192k | { | 
| 3484 | 192k |     assert(pnode); | 
| 3485 | 192k |     m_msgproc->FinalizeNode(*pnode); | 
| 3486 | 192k |     delete pnode; | 
| 3487 | 192k | } | 
| 3488 |  |  | 
| 3489 |  | CConnman::~CConnman() | 
| 3490 | 51.2k | { | 
| 3491 | 51.2k |     Interrupt(); | 
| 3492 | 51.2k |     Stop(); | 
| 3493 | 51.2k | } | 
| 3494 |  |  | 
| 3495 |  | std::vector<CAddress> CConnman::GetAddressesUnsafe(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const | 
| 3496 | 0 | { | 
| 3497 | 0 |     std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct, network, filtered); | 
| 3498 | 0 |     if (m_banman) { | 
| 3499 | 0 |         addresses.erase(std::remove_if(addresses.begin(), addresses.end(), | 
| 3500 | 0 |                         [this](const CAddress& addr){return m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr);}), | 
| 3501 | 0 |                         addresses.end()); | 
| 3502 | 0 |     } | 
| 3503 | 0 |     return addresses; | 
| 3504 | 0 | } | 
| 3505 |  |  | 
| 3506 |  | std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct) | 
| 3507 | 0 | { | 
| 3508 | 0 |     auto local_socket_bytes = requestor.addrBind.GetAddrBytes(); | 
| 3509 | 0 |     uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE) | 
| 3510 | 0 |         .Write(requestor.ConnectedThroughNetwork()) | 
| 3511 | 0 |         .Write(local_socket_bytes) | 
| 3512 |  |         // For outbound connections, the port of the bound address is randomly | 
| 3513 |  |         // assigned by the OS and would therefore not be useful for seeding. | 
| 3514 | 0 |         .Write(requestor.IsInboundConn() ? requestor.addrBind.GetPort() : 0) | 
| 3515 | 0 |         .Finalize(); | 
| 3516 | 0 |     const auto current_time = GetTime<std::chrono::microseconds>(); | 
| 3517 | 0 |     auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{}); | 
| 3518 | 0 |     CachedAddrResponse& cache_entry = r.first->second; | 
| 3519 | 0 |     if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0. | 
| 3520 | 0 |         cache_entry.m_addrs_response_cache = GetAddressesUnsafe(max_addresses, max_pct, /*network=*/std::nullopt); | 
| 3521 |  |         // Choosing a proper cache lifetime is a trade-off between the privacy leak minimization | 
| 3522 |  |         // and the usefulness of ADDR responses to honest users. | 
| 3523 |  |         // | 
| 3524 |  |         // Longer cache lifetime makes it more difficult for an attacker to scrape | 
| 3525 |  |         // enough AddrMan data to maliciously infer something useful. | 
| 3526 |  |         // By the time an attacker scraped enough AddrMan records, most of | 
| 3527 |  |         // the records should be old enough to not leak topology info by | 
| 3528 |  |         // e.g. analyzing real-time changes in timestamps. | 
| 3529 |  |         // | 
| 3530 |  |         // It takes only several hundred requests to scrape everything from an AddrMan containing 100,000 nodes, | 
| 3531 |  |         // so ~24 hours of cache lifetime indeed makes the data less inferable by the time | 
| 3532 |  |         // most of it could be scraped (considering that timestamps are updated via | 
| 3533 |  |         // ADDR self-announcements and when nodes communicate). | 
| 3534 |  |         // We also should be robust to those attacks which may not require scraping *full* victim's AddrMan | 
| 3535 |  |         // (because even several timestamps of the same handful of nodes may leak privacy). | 
| 3536 |  |         // | 
| 3537 |  |         // On the other hand, longer cache lifetime makes ADDR responses | 
| 3538 |  |         // outdated and less useful for an honest requestor, e.g. if most nodes | 
| 3539 |  |         // in the ADDR response are no longer active. | 
| 3540 |  |         // | 
| 3541 |  |         // However, the churn in the network is known to be rather low. Since we consider | 
| 3542 |  |         // nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days, | 
| 3543 |  |         // max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference | 
| 3544 |  |         // in terms of the freshness of the response. | 
| 3545 | 0 |         cache_entry.m_cache_entry_expiration = current_time + | 
| 3546 | 0 |             21h + FastRandomContext().randrange<std::chrono::microseconds>(6h); | 
| 3547 | 0 |     } | 
| 3548 | 0 |     return cache_entry.m_addrs_response_cache; | 
| 3549 | 0 | } | 
| 3550 |  |  | 
| 3551 |  | bool CConnman::AddNode(const AddedNodeParams& add) | 
| 3552 | 0 | { | 
| 3553 | 0 |     const CService resolved(LookupNumeric(add.m_added_node, GetDefaultPort(add.m_added_node))); | 
| 3554 | 0 |     const bool resolved_is_valid{resolved.IsValid()}; | 
| 3555 |  | 
 | 
| 3556 | 0 |     LOCK(m_added_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3557 | 0 |     for (const auto& it : m_added_node_params) { | 
| 3558 | 0 |         if (add.m_added_node == it.m_added_node || (resolved_is_valid && resolved == LookupNumeric(it.m_added_node, GetDefaultPort(it.m_added_node)))) return false; | 
| 3559 | 0 |     } | 
| 3560 |  |  | 
| 3561 | 0 |     m_added_node_params.push_back(add); | 
| 3562 | 0 |     return true; | 
| 3563 | 0 | } | 
| 3564 |  |  | 
| 3565 |  | bool CConnman::RemoveAddedNode(const std::string& strNode) | 
| 3566 | 0 | { | 
| 3567 | 0 |     LOCK(m_added_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3568 | 0 |     for (auto it = m_added_node_params.begin(); it != m_added_node_params.end(); ++it) { | 
| 3569 | 0 |         if (strNode == it->m_added_node) { | 
| 3570 | 0 |             m_added_node_params.erase(it); | 
| 3571 | 0 |             return true; | 
| 3572 | 0 |         } | 
| 3573 | 0 |     } | 
| 3574 | 0 |     return false; | 
| 3575 | 0 | } | 
| 3576 |  |  | 
| 3577 |  | bool CConnman::AddedNodesContain(const CAddress& addr) const | 
| 3578 | 0 | { | 
| 3579 | 0 |     AssertLockNotHeld(m_added_nodes_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3580 | 0 |     const std::string addr_str{addr.ToStringAddr()}; | 
| 3581 | 0 |     const std::string addr_port_str{addr.ToStringAddrPort()}; | 
| 3582 | 0 |     LOCK(m_added_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3583 | 0 |     return (m_added_node_params.size() < 24 // bound the query to a reasonable limit | 
| 3584 | 0 |             && std::any_of(m_added_node_params.cbegin(), m_added_node_params.cend(), | 
| 3585 | 0 |                            [&](const auto& p) { return p.m_added_node == addr_str || p.m_added_node == addr_port_str; })); | 
| 3586 | 0 | } | 
| 3587 |  |  | 
| 3588 |  | size_t CConnman::GetNodeCount(ConnectionDirection flags) const | 
| 3589 | 0 | { | 
| 3590 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3591 | 0 |     if (flags == ConnectionDirection::Both) // Shortcut if we want total | 
| 3592 | 0 |         return m_nodes.size(); | 
| 3593 |  |  | 
| 3594 | 0 |     int nNum = 0; | 
| 3595 | 0 |     for (const auto& pnode : m_nodes) { | 
| 3596 | 0 |         if (flags & (pnode->IsInboundConn() ? ConnectionDirection::In : ConnectionDirection::Out)) { | 
| 3597 | 0 |             nNum++; | 
| 3598 | 0 |         } | 
| 3599 | 0 |     } | 
| 3600 |  | 
 | 
| 3601 | 0 |     return nNum; | 
| 3602 | 0 | } | 
| 3603 |  |  | 
| 3604 |  |  | 
| 3605 |  | std::map<CNetAddr, LocalServiceInfo> CConnman::getNetLocalAddresses() const | 
| 3606 | 0 | { | 
| 3607 | 0 |     LOCK(g_maplocalhost_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3608 | 0 |     return mapLocalHost; | 
| 3609 | 0 | } | 
| 3610 |  |  | 
| 3611 |  | uint32_t CConnman::GetMappedAS(const CNetAddr& addr) const | 
| 3612 | 196k | { | 
| 3613 | 196k |     return m_netgroupman.GetMappedAS(addr); | 
| 3614 | 196k | } | 
| 3615 |  |  | 
| 3616 |  | void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const | 
| 3617 | 0 | { | 
| 3618 | 0 |     vstats.clear(); | 
| 3619 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3620 | 0 |     vstats.reserve(m_nodes.size()); | 
| 3621 | 0 |     for (CNode* pnode : m_nodes) { | 
| 3622 | 0 |         vstats.emplace_back(); | 
| 3623 | 0 |         pnode->CopyStats(vstats.back()); | 
| 3624 | 0 |         vstats.back().m_mapped_as = GetMappedAS(pnode->addr); | 
| 3625 | 0 |     } | 
| 3626 | 0 | } | 
| 3627 |  |  | 
| 3628 |  | bool CConnman::DisconnectNode(const std::string& strNode) | 
| 3629 | 0 | { | 
| 3630 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3631 | 0 |     auto it = std::ranges::find_if(m_nodes, [&strNode](CNode* node) { return node->m_addr_name == strNode; }); | 
| 3632 | 0 |     if (it != m_nodes.end()) { | 
| 3633 | 0 |         CNode* node{*it}; | 
| 3634 | 0 |         LogDebug(BCLog::NET, "disconnect by address%s match, %s", (fLogIPs ? strprintf("=%s", strNode) : ""), node->DisconnectMsg(fLogIPs));| Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 3635 | 0 |         node->fDisconnect = true; | 
| 3636 | 0 |         return true; | 
| 3637 | 0 |     } | 
| 3638 | 0 |     return false; | 
| 3639 | 0 | } | 
| 3640 |  |  | 
| 3641 |  | bool CConnman::DisconnectNode(const CSubNet& subnet) | 
| 3642 | 224k | { | 
| 3643 | 224k |     bool disconnected = false; | 
| 3644 | 224k |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 224k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 224k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 224k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 224k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3645 | 897k |     for (CNode* pnode : m_nodes) { | 
| 3646 | 897k |         if (subnet.Match(pnode->addr)) { | 
| 3647 | 4.77k |             LogDebug(BCLog::NET, "disconnect by subnet%s match, %s", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->DisconnectMsg(fLogIPs));| Line | Count | Source |  | 381 | 4.77k | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 4.77k |     do {                                                              \ |  | 374 | 4.77k |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 4.77k |     } while (0) | 
 | 
 | 
| 3648 | 4.77k |             pnode->fDisconnect = true; | 
| 3649 | 4.77k |             disconnected = true; | 
| 3650 | 4.77k |         } | 
| 3651 | 897k |     } | 
| 3652 | 224k |     return disconnected; | 
| 3653 | 224k | } | 
| 3654 |  |  | 
| 3655 |  | bool CConnman::DisconnectNode(const CNetAddr& addr) | 
| 3656 | 224k | { | 
| 3657 | 224k |     return DisconnectNode(CSubNet(addr)); | 
| 3658 | 224k | } | 
| 3659 |  |  | 
| 3660 |  | bool CConnman::DisconnectNode(NodeId id) | 
| 3661 | 0 | { | 
| 3662 | 0 |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3663 | 0 |     for(CNode* pnode : m_nodes) { | 
| 3664 | 0 |         if (id == pnode->GetId()) { | 
| 3665 | 0 |             LogDebug(BCLog::NET, "disconnect by id, %s", pnode->DisconnectMsg(fLogIPs)); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 3666 | 0 |             pnode->fDisconnect = true; | 
| 3667 | 0 |             return true; | 
| 3668 | 0 |         } | 
| 3669 | 0 |     } | 
| 3670 | 0 |     return false; | 
| 3671 | 0 | } | 
| 3672 |  |  | 
| 3673 |  | void CConnman::RecordBytesRecv(uint64_t bytes) | 
| 3674 | 0 | { | 
| 3675 | 0 |     nTotalBytesRecv += bytes; | 
| 3676 | 0 | } | 
| 3677 |  |  | 
| 3678 |  | void CConnman::RecordBytesSent(uint64_t bytes) | 
| 3679 | 1.20M | { | 
| 3680 | 1.20M |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 1.20M | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3681 | 1.20M |     LOCK(m_total_bytes_sent_mutex); | Line | Count | Source |  | 259 | 1.20M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 1.20M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 1.20M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 1.20M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3682 |  |  | 
| 3683 | 1.20M |     nTotalBytesSent += bytes; | 
| 3684 |  |  | 
| 3685 | 1.20M |     const auto now = GetTime<std::chrono::seconds>(); | 
| 3686 | 1.20M |     if (nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME < now) | 
| 3687 | 49.8k |     { | 
| 3688 |  |         // timeframe expired, reset cycle | 
| 3689 | 49.8k |         nMaxOutboundCycleStartTime = now; | 
| 3690 | 49.8k |         nMaxOutboundTotalBytesSentInCycle = 0; | 
| 3691 | 49.8k |     } | 
| 3692 |  |  | 
| 3693 | 1.20M |     nMaxOutboundTotalBytesSentInCycle += bytes; | 
| 3694 | 1.20M | } | 
| 3695 |  |  | 
| 3696 |  | uint64_t CConnman::GetMaxOutboundTarget() const | 
| 3697 | 0 | { | 
| 3698 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3699 | 0 |     LOCK(m_total_bytes_sent_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3700 | 0 |     return nMaxOutboundLimit; | 
| 3701 | 0 | } | 
| 3702 |  |  | 
| 3703 |  | std::chrono::seconds CConnman::GetMaxOutboundTimeframe() const | 
| 3704 | 0 | { | 
| 3705 | 0 |     return MAX_UPLOAD_TIMEFRAME; | 
| 3706 | 0 | } | 
| 3707 |  |  | 
| 3708 |  | std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const | 
| 3709 | 0 | { | 
| 3710 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3711 | 0 |     LOCK(m_total_bytes_sent_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3712 | 0 |     return GetMaxOutboundTimeLeftInCycle_(); | 
| 3713 | 0 | } | 
| 3714 |  |  | 
| 3715 |  | std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle_() const | 
| 3716 | 0 | { | 
| 3717 | 0 |     AssertLockHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 137 | 0 | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3718 |  | 
 | 
| 3719 | 0 |     if (nMaxOutboundLimit == 0) | 
| 3720 | 0 |         return 0s; | 
| 3721 |  |  | 
| 3722 | 0 |     if (nMaxOutboundCycleStartTime.count() == 0) | 
| 3723 | 0 |         return MAX_UPLOAD_TIMEFRAME; | 
| 3724 |  |  | 
| 3725 | 0 |     const std::chrono::seconds cycleEndTime = nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME; | 
| 3726 | 0 |     const auto now = GetTime<std::chrono::seconds>(); | 
| 3727 | 0 |     return (cycleEndTime < now) ? 0s : cycleEndTime - now; | 
| 3728 | 0 | } | 
| 3729 |  |  | 
| 3730 |  | bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const | 
| 3731 | 0 | { | 
| 3732 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3733 | 0 |     LOCK(m_total_bytes_sent_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3734 | 0 |     if (nMaxOutboundLimit == 0) | 
| 3735 | 0 |         return false; | 
| 3736 |  |  | 
| 3737 | 0 |     if (historicalBlockServingLimit) | 
| 3738 | 0 |     { | 
| 3739 |  |         // keep a large enough buffer to at least relay each block once | 
| 3740 | 0 |         const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle_(); | 
| 3741 | 0 |         const uint64_t buffer = timeLeftInCycle / std::chrono::minutes{10} * MAX_BLOCK_SERIALIZED_SIZE; | 
| 3742 | 0 |         if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer) | 
| 3743 | 0 |             return true; | 
| 3744 | 0 |     } | 
| 3745 | 0 |     else if (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) | 
| 3746 | 0 |         return true; | 
| 3747 |  |  | 
| 3748 | 0 |     return false; | 
| 3749 | 0 | } | 
| 3750 |  |  | 
| 3751 |  | uint64_t CConnman::GetOutboundTargetBytesLeft() const | 
| 3752 | 0 | { | 
| 3753 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3754 | 0 |     LOCK(m_total_bytes_sent_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3755 | 0 |     if (nMaxOutboundLimit == 0) | 
| 3756 | 0 |         return 0; | 
| 3757 |  |  | 
| 3758 | 0 |     return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle; | 
| 3759 | 0 | } | 
| 3760 |  |  | 
| 3761 |  | uint64_t CConnman::GetTotalBytesRecv() const | 
| 3762 | 0 | { | 
| 3763 | 0 |     return nTotalBytesRecv; | 
| 3764 | 0 | } | 
| 3765 |  |  | 
| 3766 |  | uint64_t CConnman::GetTotalBytesSent() const | 
| 3767 | 0 | { | 
| 3768 | 0 |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3769 | 0 |     LOCK(m_total_bytes_sent_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3770 | 0 |     return nTotalBytesSent; | 
| 3771 | 0 | } | 
| 3772 |  |  | 
| 3773 |  | ServiceFlags CConnman::GetLocalServices() const | 
| 3774 | 102k | { | 
| 3775 | 102k |     return m_local_services; | 
| 3776 | 102k | } | 
| 3777 |  |  | 
| 3778 |  | static std::unique_ptr<Transport> MakeTransport(NodeId id, bool use_v2transport, bool inbound) noexcept | 
| 3779 | 192k | { | 
| 3780 | 192k |     if (use_v2transport) { | 
| 3781 | 0 |         return std::make_unique<V2Transport>(id, /*initiating=*/!inbound); | 
| 3782 | 192k |     } else { | 
| 3783 | 192k |         return std::make_unique<V1Transport>(id); | 
| 3784 | 192k |     } | 
| 3785 | 192k | } | 
| 3786 |  |  | 
| 3787 |  | CNode::CNode(NodeId idIn, | 
| 3788 |  |              std::shared_ptr<Sock> sock, | 
| 3789 |  |              const CAddress& addrIn, | 
| 3790 |  |              uint64_t nKeyedNetGroupIn, | 
| 3791 |  |              uint64_t nLocalHostNonceIn, | 
| 3792 |  |              const CService& addrBindIn, | 
| 3793 |  |              const std::string& addrNameIn, | 
| 3794 |  |              ConnectionType conn_type_in, | 
| 3795 |  |              bool inbound_onion, | 
| 3796 |  |              CNodeOptions&& node_opts) | 
| 3797 | 192k |     : m_transport{MakeTransport(idIn, node_opts.use_v2transport, conn_type_in == ConnectionType::INBOUND)}, | 
| 3798 | 192k |       m_permission_flags{node_opts.permission_flags}, | 
| 3799 | 192k |       m_sock{sock}, | 
| 3800 | 192k |       m_connected{GetTime<std::chrono::seconds>()}, | 
| 3801 | 192k |       addr{addrIn}, | 
| 3802 | 192k |       addrBind{addrBindIn}, | 
| 3803 | 192k |       m_addr_name{addrNameIn.empty() ? addr.ToStringAddrPort()5.49k: addrNameIn186k}, | 
| 3804 | 192k |       m_dest(addrNameIn), | 
| 3805 | 192k |       m_inbound_onion{inbound_onion}, | 
| 3806 | 192k |       m_prefer_evict{node_opts.prefer_evict}, | 
| 3807 | 192k |       nKeyedNetGroup{nKeyedNetGroupIn}, | 
| 3808 | 192k |       m_conn_type{conn_type_in}, | 
| 3809 | 192k |       id{idIn}, | 
| 3810 | 192k |       nLocalHostNonce{nLocalHostNonceIn}, | 
| 3811 | 192k |       m_recv_flood_size{node_opts.recv_flood_size}, | 
| 3812 | 192k |       m_i2p_sam_session{std::move(node_opts.i2p_sam_session)} | 
| 3813 | 192k | { | 
| 3814 | 192k |     if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND); | 
| 3815 |  |  | 
| 3816 | 6.73M |     for (const auto& msg : ALL_NET_MESSAGE_TYPES)192k{ | 
| 3817 | 6.73M |         mapRecvBytesPerMsgType[msg] = 0; | 
| 3818 | 6.73M |     } | 
| 3819 | 192k |     mapRecvBytesPerMsgType[NET_MESSAGE_TYPE_OTHER] = 0; | 
| 3820 |  |  | 
| 3821 | 192k |     if (fLogIPs) { | 
| 3822 | 0 |         LogDebug(BCLog::NET, "Added connection to %s peer=%d\n", m_addr_name, id); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 3823 | 192k |     } else { | 
| 3824 | 192k |         LogDebug(BCLog::NET, "Added connection peer=%d\n", id); | Line | Count | Source |  | 381 | 192k | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 192k |     do {                                                              \ |  | 374 | 192k |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 192k |     } while (0) | 
 | 
 | 
| 3825 | 192k |     } | 
| 3826 | 192k | } | 
| 3827 |  |  | 
| 3828 |  | void CNode::MarkReceivedMsgsForProcessing() | 
| 3829 | 6.84M | { | 
| 3830 | 6.84M |     AssertLockNotHeld(m_msg_process_queue_mutex); | Line | Count | Source |  | 142 | 6.84M | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3831 |  |  | 
| 3832 | 6.84M |     size_t nSizeAdded = 0; | 
| 3833 | 6.84M |     for (const auto& msg : vRecvMsg) { | 
| 3834 |  |         // vRecvMsg contains only completed CNetMessage | 
| 3835 |  |         // the single possible partially deserialized message are held by TransportDeserializer | 
| 3836 | 6.84M |         nSizeAdded += msg.GetMemoryUsage(); | 
| 3837 | 6.84M |     } | 
| 3838 |  |  | 
| 3839 | 6.84M |     LOCK(m_msg_process_queue_mutex); | Line | Count | Source |  | 259 | 6.84M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 6.84M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 6.84M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 6.84M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3840 | 6.84M |     m_msg_process_queue.splice(m_msg_process_queue.end(), vRecvMsg); | 
| 3841 | 6.84M |     m_msg_process_queue_size += nSizeAdded; | 
| 3842 | 6.84M |     fPauseRecv = m_msg_process_queue_size > m_recv_flood_size; | 
| 3843 | 6.84M | } | 
| 3844 |  |  | 
| 3845 |  | std::optional<std::pair<CNetMessage, bool>> CNode::PollMessage() | 
| 3846 | 6.33M | { | 
| 3847 | 6.33M |     LOCK(m_msg_process_queue_mutex); | Line | Count | Source |  | 259 | 6.33M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 6.33M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 6.33M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 6.33M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3848 | 6.33M |     if (m_msg_process_queue.empty()) return std::nullopt0; | 
| 3849 |  |  | 
| 3850 | 6.33M |     std::list<CNetMessage> msgs; | 
| 3851 |  |     // Just take one message | 
| 3852 | 6.33M |     msgs.splice(msgs.begin(), m_msg_process_queue, m_msg_process_queue.begin()); | 
| 3853 | 6.33M |     m_msg_process_queue_size -= msgs.front().GetMemoryUsage(); | 
| 3854 | 6.33M |     fPauseRecv = m_msg_process_queue_size > m_recv_flood_size; | 
| 3855 |  |  | 
| 3856 | 6.33M |     return std::make_pair(std::move(msgs.front()), !m_msg_process_queue.empty()); | 
| 3857 | 6.33M | } | 
| 3858 |  |  | 
| 3859 |  | bool CConnman::NodeFullyConnected(const CNode* pnode) | 
| 3860 | 89.2k | { | 
| 3861 | 89.2k |     return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect64.4k; | 
| 3862 | 89.2k | } | 
| 3863 |  |  | 
| 3864 |  | void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) | 
| 3865 | 1.71M | { | 
| 3866 | 1.71M |     AssertLockNotHeld(m_total_bytes_sent_mutex); | Line | Count | Source |  | 142 | 1.71M | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3867 | 1.71M |     size_t nMessageSize = msg.data.size(); | 
| 3868 | 1.71M |     LogDebug(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId()); | Line | Count | Source |  | 381 | 1.71M | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 1.71M |     do {                                                              \ |  | 374 | 1.71M |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 1.71M |     } while (0) | 
 | 
 | 
| 3869 | 1.71M |     if (gArgs.GetBoolArg("-capturemessages", false)) { | 
| 3870 | 0 |         CaptureMessage(pnode->addr, msg.m_type, msg.data, /*is_incoming=*/false); | 
| 3871 | 0 |     } | 
| 3872 |  |  | 
| 3873 | 1.71M |     TRACEPOINT(net, outbound_message, | 
| 3874 | 1.71M |         pnode->GetId(), | 
| 3875 | 1.71M |         pnode->m_addr_name.c_str(), | 
| 3876 | 1.71M |         pnode->ConnectionTypeAsString().c_str(), | 
| 3877 | 1.71M |         msg.m_type.c_str(), | 
| 3878 | 1.71M |         msg.data.size(), | 
| 3879 | 1.71M |         msg.data.data() | 
| 3880 | 1.71M |     ); | 
| 3881 |  |  | 
| 3882 | 1.71M |     size_t nBytesSent = 0; | 
| 3883 | 1.71M |     { | 
| 3884 | 1.71M |         LOCK(pnode->cs_vSend); | Line | Count | Source |  | 259 | 1.71M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 1.71M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 1.71M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 1.71M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3885 |  |         // Check if the transport still has unsent bytes, and indicate to it that we're about to | 
| 3886 |  |         // give it a message to send. | 
| 3887 | 1.71M |         const auto& [to_send, more, _msg_type] = | 
| 3888 | 1.71M |             pnode->m_transport->GetBytesToSend(/*have_next_message=*/true); | 
| 3889 | 1.71M |         const bool queue_was_empty{to_send.empty() && pnode->vSendMsg.empty()1.21M}; | 
| 3890 |  |  | 
| 3891 |  |         // Update memory usage of send buffer. | 
| 3892 | 1.71M |         pnode->m_send_memusage += msg.GetMemoryUsage(); | 
| 3893 | 1.71M |         if (pnode->m_send_memusage + pnode->m_transport->GetSendMemoryUsage() > nSendBufferMaxSize) pnode->fPauseSend = true; | 
| 3894 |  |         // Move message to vSendMsg queue. | 
| 3895 | 1.71M |         pnode->vSendMsg.push_back(std::move(msg)); | 
| 3896 |  |  | 
| 3897 |  |         // If there was nothing to send before, and there is now (predicted by the "more" value | 
| 3898 |  |         // returned by the GetBytesToSend call above), attempt "optimistic write": | 
| 3899 |  |         // because the poll/select loop may pause for SELECT_TIMEOUT_MILLISECONDS before actually | 
| 3900 |  |         // doing a send, try sending from the calling thread if the queue was empty before. | 
| 3901 |  |         // With a V1Transport, more will always be true here, because adding a message always | 
| 3902 |  |         // results in sendable bytes there, but with V2Transport this is not the case (it may | 
| 3903 |  |         // still be in the handshake). | 
| 3904 | 1.71M |         if (queue_was_empty && more1.21M) { | 
| 3905 | 1.21M |             std::tie(nBytesSent, std::ignore) = SocketSendData(*pnode); | 
| 3906 | 1.21M |         } | 
| 3907 | 1.71M |     } | 
| 3908 | 1.71M |     if (nBytesSent) RecordBytesSent(nBytesSent)1.20M; | 
| 3909 | 1.71M | } | 
| 3910 |  |  | 
| 3911 |  | bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func) | 
| 3912 | 2.10k | { | 
| 3913 | 2.10k |     CNode* found = nullptr; | 
| 3914 | 2.10k |     LOCK(m_nodes_mutex); | Line | Count | Source |  | 259 | 2.10k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 2.10k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 2.10k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 2.10k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3915 | 8.33k |     for (auto&& pnode : m_nodes) { | 
| 3916 | 8.33k |         if(pnode->GetId() == id) { | 
| 3917 | 2.10k |             found = pnode; | 
| 3918 | 2.10k |             break; | 
| 3919 | 2.10k |         } | 
| 3920 | 8.33k |     } | 
| 3921 | 2.10k |     return found != nullptr && NodeFullyConnected(found) && func(found); | 
| 3922 | 2.10k | } | 
| 3923 |  |  | 
| 3924 |  | CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const | 
| 3925 | 0 | { | 
| 3926 | 0 |     return CSipHasher(nSeed0, nSeed1).Write(id); | 
| 3927 | 0 | } | 
| 3928 |  |  | 
| 3929 |  | uint64_t CConnman::CalculateKeyedNetGroup(const CNetAddr& address) const | 
| 3930 | 0 | { | 
| 3931 | 0 |     std::vector<unsigned char> vchNetGroup(m_netgroupman.GetGroup(address)); | 
| 3932 |  | 
 | 
| 3933 | 0 |     return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup).Finalize(); | 
| 3934 | 0 | } | 
| 3935 |  |  | 
| 3936 |  | void CConnman::PerformReconnections() | 
| 3937 | 0 | { | 
| 3938 | 0 |     AssertLockNotHeld(m_reconnections_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3939 | 0 |     AssertLockNotHeld(m_unused_i2p_sessions_mutex); | Line | Count | Source |  | 142 | 0 | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 3940 | 0 |     while (true) { | 
| 3941 |  |         // Move first element of m_reconnections to todo (avoiding an allocation inside the lock). | 
| 3942 | 0 |         decltype(m_reconnections) todo; | 
| 3943 | 0 |         { | 
| 3944 | 0 |             LOCK(m_reconnections_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 3945 | 0 |             if (m_reconnections.empty()) break; | 
| 3946 | 0 |             todo.splice(todo.end(), m_reconnections, m_reconnections.begin()); | 
| 3947 | 0 |         } | 
| 3948 |  |  | 
| 3949 | 0 |         auto& item = *todo.begin(); | 
| 3950 | 0 |         OpenNetworkConnection(item.addr_connect, | 
| 3951 |  |                               // We only reconnect if the first attempt to connect succeeded at | 
| 3952 |  |                               // connection time, but then failed after the CNode object was | 
| 3953 |  |                               // created. Since we already know connecting is possible, do not | 
| 3954 |  |                               // count failure to reconnect. | 
| 3955 | 0 |                               /*fCountFailure=*/false, | 
| 3956 | 0 |                               std::move(item.grant), | 
| 3957 | 0 |                               item.destination.empty() ? nullptr : item.destination.c_str(), | 
| 3958 | 0 |                               item.conn_type, | 
| 3959 | 0 |                               item.use_v2transport); | 
| 3960 | 0 |     } | 
| 3961 | 0 | } | 
| 3962 |  |  | 
| 3963 |  | void CConnman::ASMapHealthCheck() | 
| 3964 | 0 | { | 
| 3965 | 0 |     const std::vector<CAddress> v4_addrs{GetAddressesUnsafe(/*max_addresses=*/0, /*max_pct=*/0, Network::NET_IPV4, /*filtered=*/false)}; | 
| 3966 | 0 |     const std::vector<CAddress> v6_addrs{GetAddressesUnsafe(/*max_addresses=*/0, /*max_pct=*/0, Network::NET_IPV6, /*filtered=*/false)}; | 
| 3967 | 0 |     std::vector<CNetAddr> clearnet_addrs; | 
| 3968 | 0 |     clearnet_addrs.reserve(v4_addrs.size() + v6_addrs.size()); | 
| 3969 | 0 |     std::transform(v4_addrs.begin(), v4_addrs.end(), std::back_inserter(clearnet_addrs), | 
| 3970 | 0 |         [](const CAddress& addr) { return static_cast<CNetAddr>(addr); }); | 
| 3971 | 0 |     std::transform(v6_addrs.begin(), v6_addrs.end(), std::back_inserter(clearnet_addrs), | 
| 3972 | 0 |         [](const CAddress& addr) { return static_cast<CNetAddr>(addr); }); | 
| 3973 | 0 |     m_netgroupman.ASMapHealthCheck(clearnet_addrs); | 
| 3974 | 0 | } | 
| 3975 |  |  | 
| 3976 |  | // Dump binary message to file, with timestamp. | 
| 3977 |  | static void CaptureMessageToFile(const CAddress& addr, | 
| 3978 |  |                                  const std::string& msg_type, | 
| 3979 |  |                                  std::span<const unsigned char> data, | 
| 3980 |  |                                  bool is_incoming) | 
| 3981 | 0 | { | 
| 3982 |  |     // Note: This function captures the message at the time of processing, | 
| 3983 |  |     // not at socket receive/send time. | 
| 3984 |  |     // This ensures that the messages are always in order from an application | 
| 3985 |  |     // layer (processing) perspective. | 
| 3986 | 0 |     auto now = GetTime<std::chrono::microseconds>(); | 
| 3987 |  |  | 
| 3988 |  |     // Windows folder names cannot include a colon | 
| 3989 | 0 |     std::string clean_addr = addr.ToStringAddrPort(); | 
| 3990 | 0 |     std::replace(clean_addr.begin(), clean_addr.end(), ':', '_'); | 
| 3991 |  | 
 | 
| 3992 | 0 |     fs::path base_path = gArgs.GetDataDirNet() / "message_capture" / fs::u8path(clean_addr); | 
| 3993 | 0 |     fs::create_directories(base_path); | 
| 3994 |  | 
 | 
| 3995 | 0 |     fs::path path = base_path / (is_incoming ? "msgs_recv.dat" : "msgs_sent.dat"); | 
| 3996 | 0 |     AutoFile f{fsbridge::fopen(path, "ab")}; | 
| 3997 |  | 
 | 
| 3998 | 0 |     ser_writedata64(f, now.count()); | 
| 3999 | 0 |     f << std::span{msg_type}; | 
| 4000 | 0 |     for (auto i = msg_type.length(); i < CMessageHeader::MESSAGE_TYPE_SIZE; ++i) { | 
| 4001 | 0 |         f << uint8_t{'\0'}; | 
| 4002 | 0 |     } | 
| 4003 | 0 |     uint32_t size = data.size(); | 
| 4004 | 0 |     ser_writedata32(f, size); | 
| 4005 | 0 |     f << data; | 
| 4006 |  | 
 | 
| 4007 | 0 |     if (f.fclose() != 0) { | 
| 4008 | 0 |         throw std::ios_base::failure( | 
| 4009 | 0 |             strprintf("Error closing %s after write, file contents are likely incomplete", fs::PathToString(path)));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 4010 | 0 |     } | 
| 4011 | 0 | } | 
| 4012 |  |  | 
| 4013 |  | std::function<void(const CAddress& addr, | 
| 4014 |  |                    const std::string& msg_type, | 
| 4015 |  |                    std::span<const unsigned char> data, | 
| 4016 |  |                    bool is_incoming)> | 
| 4017 |  |     CaptureMessage = CaptureMessageToFile; |