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.
3001}3003return ret;3004}3006std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo(bool include_connected) const3007{3008AssertLockNotHeld(m_nodes_mutex);3010std::vector<AddedNodeInfo> ret;3012std::list<AddedNodeParams> lAddresses(0);3013{3014LOCK(m_added_nodes_mutex);3015ret.reserve(m_added_node_params.size());3016std::copy(m_added_node_params.cbegin(), m_added_node_params.cend(), std::back_inserter(lAddresses));3017}3020// Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService3021std::map<CService, bool> mapConnected;3022std::map<std::string, std::pair<bool, CService>> mapConnectedByName;3023{3024LOCK(m_nodes_mutex);3025for (const CNode* pnode : m_nodes) {3026if (pnode->addr.IsValid()) {3027mapConnected[pnode->addr] = pnode->IsInboundConn();3028}3029std::string addrName{pnode->m_addr_name};3030if (!addrName.empty()) {3031mapConnectedByName[std::move(addrName)] = std::make_pair(pnode->IsInboundConn(), static_cast<const CService&>(pnode->addr));3032}3033}3034}3036for (const auto& addr : lAddresses) {3037CService service{MaybeFlipIPv6toCJDNS(LookupNumeric(addr.m_added_node, GetDefaultPort(addr.m_added_node)))};3038AddedNodeInfo addedNode{addr, CService(), false, false};3039if (service.IsValid()) {3040// strAddNode is an IP:port3041auto it = mapConnected.find(service);3042if (it != mapConnected.end()) {3043if (!include_connected) {3044continue;3045}3046addedNode.resolvedAddress = service;3047addedNode.fConnected = true;3048addedNode.fInbound = it->second;3049}3050} else {3051// strAddNode is a name3052auto it = mapConnectedByName.find(addr.m_added_node);3053if (it != mapConnectedByName.end()) {3054if (!include_connected) {3055continue;3056}3057addedNode.resolvedAddress = it->second.second;3058addedNode.fConnected = true;3059addedNode.fInbound = it->second.first;3060}3061}3062ret.emplace_back(std::move(addedNode));3063}3065return ret;3066}3068void CConnman::ThreadOpenAddedConnections()3069{3070AssertLockNotHeld(m_nodes_mutex);3071AssertLockNotHeld(m_reconnections_mutex);3072AssertLockNotHeld(m_unused_i2p_sessions_mutex);3074while (true)3075{3076CountingSemaphoreGrant<> grant(*semAddnode);3077std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo(/*include_connected=*/false);3078bool tried = false;3079for (const AddedNodeInfo& info : vInfo) {3080if (!grant) {3081// If we've used up our semaphore and need a new one, let's not wait here since while we are waiting3082// the addednodeinfo state might change.3083break;3084}3085tried = true;3086OpenNetworkConnection(/*addrConnect=*/CAddress{CService{}, NODE_NONE},3087/*fCountFailure=*/false,3088/*grant_outbound=*/std::move(grant),3089/*pszDest=*/info.m_params.m_added_node.c_str(),3090/*conn_type=*/ConnectionType::MANUAL,3091/*use_v2transport=*/info.m_params.m_use_v2transport,3092/*proxy_override=*/std::nullopt);3093if (!m_interrupt_net->sleep_for(500ms)) return;3094grant = CountingSemaphoreGrant<>(*semAddnode, /*fTry=*/true);3095}3096// See if any reconnections are desired.3097PerformReconnections();3098// Retry every 60 seconds if a connection was attempted, otherwise two seconds3099if (!m_interrupt_net->sleep_for(tried ? 60s : 2s)) {3100return;3101}3102}3103}3105// if successful, this moves the passed grant to the constructed node3106bool CConnman::OpenNetworkConnection(const CAddress& addrConnect,3107bool fCountFailure,3108CountingSemaphoreGrant<>&& grant_outbound,3109const char* pszDest,3110ConnectionType conn_type,3111bool use_v2transport,3112const std::optional<Proxy>& proxy_override)3113{3114AssertLockNotHeld(m_nodes_mutex);3115AssertLockNotHeld(m_unused_i2p_sessions_mutex);3116assert(conn_type != ConnectionType::INBOUND);3118//3119// Initiate outbound network connection3120//3121if (m_interrupt_net->interrupted()) {3122return false;3123}3124if (!fNetworkActive) {3125return false;3126}3127if (!pszDest) {3128bool banned_or_discouraged = m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect));3129if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) {3130return false;3131}3132} else if (AlreadyConnectedToHost(pszDest)) {3133return false;3134}3136CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport, proxy_override);3138if (!pnode)3139return false;3140pnode->grantOutbound = std::move(grant_outbound);3142m_msgproc->InitializeNode(*pnode, m_local_services);3143{3144LOCK(m_nodes_mutex);3145m_nodes.push_back(pnode);3147// update connection count by network3148if (pnode->IsManualOrFullOutboundConn()) ++m_network_conn_counts[pnode->addr.GetNetwork()];3149}3151TRACEPOINT(net, outbound_connection,3152pnode->GetId(),3153pnode->m_addr_name.c_str(),3154pnode->ConnectionTypeAsString().c_str(),3155pnode->ConnectedThroughNetwork(),3156GetNodeCount(ConnectionDirection::Out));3158return true;3159}3161std::optional<Network> CConnman::PrivateBroadcast::PickNetwork(std::optional<Proxy>& proxy) const3162{3163prevector<4, Network> nets;3164std::optional<Proxy> clearnet_proxy;3165proxy.reset();3166if (g_reachable_nets.Contains(NET_ONION)) {3167nets.push_back(NET_ONION);3169clearnet_proxy = ProxyForIPv4or6();3170if (clearnet_proxy.has_value()) {3171if (g_reachable_nets.Contains(NET_IPV4)) {3172nets.push_back(NET_IPV4);3173}3174if (g_reachable_nets.Contains(NET_IPV6)) {3175nets.push_back(NET_IPV6);3176}3177}3178}3179if (g_reachable_nets.Contains(NET_I2P)) {3180nets.push_back(NET_I2P);3181}3183if (nets.empty()) {3184return std::nullopt;3185}3187const Network net{nets[FastRandomContext{}.randrange(nets.size())]};3188if (net == NET_IPV4 || net == NET_IPV6) {3189proxy = clearnet_proxy;3190}3191return net;3192}3194size_t CConnman::PrivateBroadcast::NumToOpen() const3195{3196return m_num_to_open;3197}3199void CConnman::PrivateBroadcast::NumToOpenAdd(size_t n)3200{3201m_num_to_open += n;3202m_num_to_open.notify_all();3203}3205size_t CConnman::PrivateBroadcast::NumToOpenSub(size_t n)3206{3207size_t current_value{m_num_to_open.load()};3208size_t new_value;3209do {3210new_value = current_value > n ? current_value - n : 0;3211} while (!m_num_to_open.compare_exchange_strong(current_value, new_value));3212return new_value;3213}3215void CConnman::PrivateBroadcast::NumToOpenWait() const3216{3217m_num_to_open.wait(0);3218}3220std::optional<Proxy> CConnman::PrivateBroadcast::ProxyForIPv4or6() const3221{3222if (m_outbound_tor_ok_at_least_once.load()) {3223if (const auto tor_proxy = GetProxy(NET_ONION)) {3224return tor_proxy;3225}3226}3227return std::nullopt;3228}3230Mutex NetEventsInterface::g_msgproc_mutex;3232void CConnman::ThreadMessageHandler()3233{3234AssertLockNotHeld(m_nodes_mutex);3236LOCK(NetEventsInterface::g_msgproc_mutex);3238while (!flagInterruptMsgProc)3239{3240bool fMoreWork = false;3242{3243// Randomize the order in which we process messages from/to our peers.3244// This prevents attacks in which an attacker exploits having multiple3245// consecutive connections in the m_nodes list.3246const NodesSnapshot snap{*this, /*shuffle=*/true};3248for (CNode* pnode : snap.Nodes()) {3249if (pnode->fDisconnect)3250continue;