Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
2251pnode->CloseSocketDisconnect();2252}2253else if (nBytes < 0)2254{2255// error2256int nErr = WSAGetLastError();2257if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)2258{2259if (!pnode->fDisconnect) {2260LogDebug(BCLog::NET, "socket recv error, %s: %s", pnode->DisconnectMsg(), NetworkErrorString(nErr));2261}2262pnode->CloseSocketDisconnect();2263}2264}2265}2267if (InactivityCheck(*pnode, now)) pnode->fDisconnect = true;2268}2269}2271void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)2272{2273AssertLockNotHeld(m_nodes_mutex);2275for (const ListenSocket& listen_socket : vhListenSocket) {2276if (m_interrupt_net->interrupted()) {2277return;2278}2279const auto it = events_per_sock.find(listen_socket.sock);2280if (it != events_per_sock.end() && it->second.occurred & Sock::RecvEvent) {2281AcceptConnection(listen_socket);2282}2283}2284}2286void CConnman::ThreadSocketHandler()2287{2288AssertLockNotHeld(m_total_bytes_sent_mutex);2290while (!m_interrupt_net->interrupted()) {2291DisconnectNodes();2292NotifyNumConnectionsChanged();2293SocketHandler();2294}2295}2297void CConnman::WakeMessageHandler()2298{2299{2300LOCK(mutexMsgProc);2301fMsgProcWake = true;2302}2303condMsgProc.notify_one();2304}2306void CConnman::ThreadDNSAddressSeed()2307{2308int outbound_connection_count = 0;2310if (!gArgs.GetArgs("-seednode").empty()) {2311auto start = NodeClock::now();2312constexpr std::chrono::seconds SEEDNODE_TIMEOUT = 30s;2313LogInfo("-seednode enabled. Trying the provided seeds for %d seconds before defaulting to the dnsseeds.\n", SEEDNODE_TIMEOUT.count());2314while (!m_interrupt_net->interrupted()) {2315if (!m_interrupt_net->sleep_for(500ms)) {2316return;2317}2319// Abort if we have spent enough time without reaching our target.2320// Giving seed nodes 30 seconds so this does not become a race against fixedseeds (which triggers after 1 min)2321if (NodeClock::now() > start + SEEDNODE_TIMEOUT) {2322LogInfo("Couldn't connect to enough peers via seed nodes. Handing fetch logic to the DNS seeds.\n");2323break;2324}2326outbound_connection_count = GetFullOutboundConnCount();2327if (outbound_connection_count >= SEED_OUTBOUND_CONNECTION_THRESHOLD) {2328LogInfo("P2P peers available. Finished fetching data from seed nodes.\n");2329break;2330}2331}2332}2334FastRandomContext rng;2335std::vector<std::string> seeds = m_params.DNSSeeds();2336std::shuffle(seeds.begin(), seeds.end(), rng);2337int seeds_right_now = 0; // Number of seeds left before testing if we have enough connections2339if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) {2340// When -forcednsseed is provided, query all.2341seeds_right_now = seeds.size();2342} else if (addrman.get().Size() == 0) {2343// If we have no known peers, query all.2344// This will occur on the first run, or if peers.dat has been2345// deleted.2346seeds_right_now = seeds.size();2347}2349// Proceed with dnsseeds if seednodes hasn't reached the target or if forcednsseed is set2350if (outbound_connection_count < SEED_OUTBOUND_CONNECTION_THRESHOLD || seeds_right_now) {2351// goal: only query DNS seed if address need is acute2352// * If we have a reasonable number of peers in addrman, spend2353// some time trying them first. This improves user privacy by2354// creating fewer identifying DNS requests, reduces trust by2355// giving seeds less influence on the network topology, and2356// reduces traffic to the seeds.2357// * When querying DNS seeds query a few at once, this ensures2358// that we don't give DNS seeds the ability to eclipse nodes2359// that query them.2360// * If we continue having problems, eventually query all the2361// DNS seeds, and if that fails too, also try the fixed seeds.2362// (done in ThreadOpenConnections)2363int found = 0;2364const std::chrono::seconds seeds_wait_time = (addrman.get().Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);2366for (const std::string& seed : seeds) {2367if (seeds_right_now == 0) {2368seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;2370if (addrman.get().Size() > 0) {2371LogInfo("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());2372std::chrono::seconds to_wait = seeds_wait_time;2373while (to_wait.count() > 0) {2374// if sleeping for the MANY_PEERS interval, wake up2375// early to see if we have enough peers and can stop2376// this thread entirely freeing up its resources2377std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);2378if (!m_interrupt_net->sleep_for(w)) return;2379to_wait -= w;2381if (GetFullOutboundConnCount() >= SEED_OUTBOUND_CONNECTION_THRESHOLD) {2382if (found > 0) {2383LogInfo("%d addresses found from DNS seeds\n", found);2384LogInfo("P2P peers available. Finished DNS seeding.\n");2385} else {2386LogInfo("P2P peers available. Skipped DNS seeding.\n");2387}2388return;2389}2390}2391}2392}2394if (m_interrupt_net->interrupted()) return;2396// hold off on querying seeds if P2P network deactivated2397if (!fNetworkActive) {2398LogInfo("Waiting for network to be reactivated before querying DNS seeds.\n");2399do {2400if (!m_interrupt_net->sleep_for(1s)) return;2401} while (!fNetworkActive);2402}2404LogInfo("Loading addresses from DNS seed %s\n", seed);2405// If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address2406// for the base dns seed domain in chainparams2407if (HaveNameProxy()) {2408AddAddrFetch(seed);2409} else {2410std::vector<CAddress> vAdd;2411constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()};2412std::string host = strprintf("x%x.%s", requiredServiceBits, seed);2413CNetAddr resolveSource;2414if (!resolveSource.SetInternal(host)) {2415continue;2416}2417// Limit number of IPs learned from a single DNS seed. This limit exists to prevent the results from2418// one DNS seed from dominating AddrMan. Note that the number of results from a UDP DNS query is2419// bounded to 33 already, but it is possible for it to use TCP where a larger number of results can be2420// returned.2421unsigned int nMaxIPs = 32;2422const auto addresses{LookupHost(host, nMaxIPs, true)};2423if (!addresses.empty()) {2424for (const CNetAddr& ip : addresses) {2425CAddress addr = CAddress(CService(ip, m_params.GetDefaultPort()), SeedsAssumedServiceFlags());2426addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old2427vAdd.push_back(addr);2428found++;2429}2430addrman.get().Add(vAdd, resolveSource);2431} else {2432// If the seed does not support a subdomain with our desired service bits,2433// we make an ADDR_FETCH connection to the DNS resolved peer address for the2434// base dns seed domain in chainparams2435AddAddrFetch(seed);2436}2437}2438--seeds_right_now;2439}2440LogInfo("%d addresses found from DNS seeds\n", found);2441} else {2442LogInfo("Skipping DNS seeds. Enough peers have been found\n");2443}2444}2446void CConnman::DumpAddresses()2447{2448const auto start{SteadyClock::now()};2450DumpPeerAddresses(::gArgs, addrman);2452LogDebug(BCLog::NET, "Flushed %d addresses to peers.dat %dms",2453addrman.get().Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));2454}2456void CConnman::ProcessAddrFetch()2457{2458AssertLockNotHeld(m_nodes_mutex);2459AssertLockNotHeld(m_unused_i2p_sessions_mutex);2460std::string strDest;2461{2462LOCK(m_addr_fetches_mutex);2463if (m_addr_fetches.empty())2464return;2465strDest = m_addr_fetches.front();2466m_addr_fetches.pop_front();2467}2468// Attempt v2 connection if we support v2 - we'll reconnect with v1 if our2469// peer doesn't support it or immediately disconnects us for another reason.2470const bool use_v2transport(GetLocalServices() & NODE_P2P_V2);2471CAddress addr;2472CountingSemaphoreGrant<> grant(*semOutbound, /*fTry=*/true);2473if (grant) {2474OpenNetworkConnection(/*addrConnect=*/addr,2475/*fCountFailure=*/false,2476/*grant_outbound=*/std::move(grant),2477/*pszDest=*/strDest.c_str(),2478/*conn_type=*/ConnectionType::ADDR_FETCH,2479/*use_v2transport=*/use_v2transport,2480/*proxy_override=*/std::nullopt);2481}2482}2484bool CConnman::GetTryNewOutboundPeer() const2485{2486return m_try_another_outbound_peer;2487}2489void CConnman::SetTryNewOutboundPeer(bool flag)2490{2491m_try_another_outbound_peer = flag;2492LogDebug(BCLog::NET, "setting try another outbound peer=%s\n", flag ? "true" : "false");2493}2495void CConnman::StartExtraBlockRelayPeers()2496{2497LogDebug(BCLog::NET, "enabling extra block-relay-only peers\n");2498m_start_extra_block_relay_peers = true;2499}