diff options
Diffstat (limited to 'src/net.cpp')
-rw-r--r-- | src/net.cpp | 430 |
1 files changed, 214 insertions, 216 deletions
diff --git a/src/net.cpp b/src/net.cpp index 0994af3021..0f9de81d7f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -89,10 +89,6 @@ std::string strSubVersion; limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ); -// Signals for message handling -static CNodeSignals g_signals; -CNodeSignals& GetNodeSignals() { return g_signals; } - void CConnman::AddOneShot(const std::string& strDest) { LOCK(cs_vOneShots); @@ -101,7 +97,7 @@ void CConnman::AddOneShot(const std::string& strDest) unsigned short GetListenPort() { - return (unsigned short)(GetArg("-port", Params().GetDefaultPort())); + return (unsigned short)(gArgs.GetArg("-port", Params().GetDefaultPort())); } // find 'best' local address for a particular peer @@ -139,11 +135,10 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn const int64_t nOneWeek = 7*24*60*60; std::vector<CAddress> vSeedsOut; vSeedsOut.reserve(vSeedsIn.size()); - for (std::vector<SeedSpec6>::const_iterator i(vSeedsIn.begin()); i != vSeedsIn.end(); ++i) - { + for (const auto& seed_in : vSeedsIn) { struct in6_addr ip; - memcpy(&ip, i->addr, sizeof(ip)); - CAddress addr(CService(ip, i->port), NODE_NETWORK); + memcpy(&ip, seed_in.addr, sizeof(ip)); + CAddress addr(CService(ip, seed_in.port), NODE_NETWORK); addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek; vSeedsOut.push_back(addr); } @@ -303,19 +298,23 @@ bool IsReachable(const CNetAddr& addr) CNode* CConnman::FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); - for (CNode* pnode : vNodes) - if ((CNetAddr)pnode->addr == ip) - return (pnode); - return NULL; + for (CNode* pnode : vNodes) { + if ((CNetAddr)pnode->addr == ip) { + return pnode; + } + } + return nullptr; } CNode* CConnman::FindNode(const CSubNet& subNet) { LOCK(cs_vNodes); - for (CNode* pnode : vNodes) - if (subNet.Match((CNetAddr)pnode->addr)) - return (pnode); - return NULL; + for (CNode* pnode : vNodes) { + if (subNet.Match((CNetAddr)pnode->addr)) { + return pnode; + } + } + return nullptr; } CNode* CConnman::FindNode(const std::string& addrName) @@ -323,19 +322,21 @@ CNode* CConnman::FindNode(const std::string& addrName) LOCK(cs_vNodes); for (CNode* pnode : vNodes) { if (pnode->GetAddrName() == addrName) { - return (pnode); + return pnode; } } - return NULL; + return nullptr; } CNode* CConnman::FindNode(const CService& addr) { LOCK(cs_vNodes); - for (CNode* pnode : vNodes) - if ((CService)pnode->addr == addr) - return (pnode); - return NULL; + for (CNode* pnode : vNodes) { + if ((CService)pnode->addr == addr) { + return pnode; + } + } + return nullptr; } bool CConnman::CheckIncomingNonce(uint64_t nonce) @@ -366,16 +367,16 @@ static CAddress GetBindAddress(SOCKET sock) CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { - if (pszDest == NULL) { + if (pszDest == nullptr) { if (IsLocal(addrConnect)) - return NULL; + return nullptr; // Look for an existing connection CNode* pnode = FindNode((CService)addrConnect); if (pnode) { LogPrintf("Failed to open new connection, already connected\n"); - return NULL; + return nullptr; } } @@ -384,19 +385,16 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo pszDest ? pszDest : addrConnect.ToString(), pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0); - // Connect - SOCKET hSocket; - bool proxyConnectionFailed = false; - if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) : - ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed)) - { - if (!IsSelectableSocket(hSocket)) { - LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n"); - CloseSocket(hSocket); - return NULL; - } - - if (pszDest && addrConnect.IsValid()) { + // Resolve + const int default_port = Params().GetDefaultPort(); + if (pszDest) { + std::vector<CService> resolved; + if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) { + addrConnect = CAddress(resolved[GetRand(resolved.size())], NODE_NONE); + if (!addrConnect.IsValid()) { + LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s", addrConnect.ToString(), pszDest); + return nullptr; + } // It is possible that we already have a connection to the IP/port pszDest resolved to. // In that case, drop the connection that was just created, and return the existing CNode instead. // Also store the name we used to connect in that CNode, so that future FindNode() calls to that @@ -406,30 +404,52 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo if (pnode) { pnode->MaybeSetAddrName(std::string(pszDest)); - CloseSocket(hSocket); LogPrintf("Failed to open new connection, already connected\n"); - return NULL; + return nullptr; } } + } - addrman.Attempt(addrConnect, fCountFailure); + // Connect + bool connected = false; + SOCKET hSocket; + proxyType proxy; + if (addrConnect.IsValid()) { + bool proxyConnectionFailed = false; + + if (GetProxy(addrConnect.GetNetwork(), proxy)) + connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, &proxyConnectionFailed); + else // no proxy needed (none set for target network) + connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout); + if (!proxyConnectionFailed) { + // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to + // the proxy, mark this as an attempt. + addrman.Attempt(addrConnect, fCountFailure); + } + } else if (pszDest && GetNameProxy(proxy)) { + std::string host; + int port = default_port; + SplitHostPort(std::string(pszDest), port, host); + connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, nullptr); + } + if (connected) { + if (!IsSelectableSocket(hSocket)) { + LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n"); + CloseSocket(hSocket); + return nullptr; + } // Add node NodeId id = GetNewNodeId(); uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CAddress addr_bind = GetBindAddress(hSocket); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false); - pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); pnode->AddRef(); return pnode; - } else if (!proxyConnectionFailed) { - // If connecting to the node failed, and failure is not caused by a problem connecting to - // the proxy, mark this as an attempt. - addrman.Attempt(addrConnect, fCountFailure); } - return NULL; + return nullptr; } void CConnman::DumpBanlist() @@ -478,10 +498,9 @@ void CConnman::ClearBanned() bool CConnman::IsBanned(CNetAddr ip) { LOCK(cs_setBanned); - for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++) - { - CSubNet subNet = (*it).first; - CBanEntry banEntry = (*it).second; + for (const auto& it : setBanned) { + CSubNet subNet = it.first; + CBanEntry banEntry = it.second; if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) { return true; @@ -514,7 +533,7 @@ void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t ba banEntry.banReason = banReason; if (bantimeoffset <= 0) { - bantimeoffset = GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME); + bantimeoffset = gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME); sinceUnixEpoch = false; } banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; @@ -665,7 +684,7 @@ void CNode::copyStats(CNodeStats &stats) X(cleanSubVer); } X(fInbound); - X(fAddnode); + X(m_manual_connection); X(nStartingHeight); { LOCK(cs_vSend); @@ -942,6 +961,16 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction return a.nTimeConnected > b.nTimeConnected; } + +//! Sort an array by the specified comparator, then erase the last K elements. +template<typename T, typename Comparator> +static void EraseLastKElements(std::vector<T> &elements, Comparator comparator, size_t k) +{ + std::sort(elements.begin(), elements.end(), comparator); + size_t eraseSize = std::min(k, elements.size()); + elements.erase(elements.end() - eraseSize, elements.end()); +} + /** Try to find a connection to evict when the node is full. * Extreme care must be taken to avoid opening the node to attacker * triggered network partitioning. @@ -956,7 +985,7 @@ bool CConnman::AttemptToEvictConnection() { LOCK(cs_vNodes); - for (CNode *node : vNodes) { + for (const CNode* node : vNodes) { if (node->fWhitelisted) continue; if (!node->fInbound) @@ -965,48 +994,29 @@ bool CConnman::AttemptToEvictConnection() continue; NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime, node->nLastBlockTime, node->nLastTXTime, - (node->nServices & nRelevantServices) == nRelevantServices, - node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup}; + HasAllDesirableServiceFlags(node->nServices), + node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } } - if (vEvictionCandidates.empty()) return false; - // Protect connections with certain characteristics // Deterministically select 4 peers to protect by netgroup. // An attacker cannot predict which netgroups will be protected - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNetGroupKeyed); - vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end()); - - if (vEvictionCandidates.empty()) return false; - + EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4); // Protect the 8 nodes with the lowest minimum ping time. // An attacker cannot manipulate this metric without physically moving nodes closer to the target. - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime); - vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end()); - - if (vEvictionCandidates.empty()) return false; - + EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8); // Protect 4 nodes that most recently sent us transactions. // An attacker cannot manipulate this metric without performing useful work. - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeTXTime); - vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end()); - - if (vEvictionCandidates.empty()) return false; - + EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4); // Protect 4 nodes that most recently sent us blocks. // An attacker cannot manipulate this metric without performing useful work. - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeBlockTime); - vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end()); - - if (vEvictionCandidates.empty()) return false; - + EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4); // Protect the half of the remaining nodes which have been connected the longest. // This replicates the non-eviction implicit behavior, and precludes attacks that start later. - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); - vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end()); + EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size() / 2); if (vEvictionCandidates.empty()) return false; @@ -1017,12 +1027,12 @@ bool CConnman::AttemptToEvictConnection() int64_t nMostConnectionsTime = 0; std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes; for (const NodeEvictionCandidate &node : vEvictionCandidates) { - mapNetGroupNodes[node.nKeyedNetGroup].push_back(node); - int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected; - size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size(); + std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup]; + group.push_back(node); + int64_t grouptime = group[0].nTimeConnected; - if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { - nMostConnections = groupsize; + if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) { + nMostConnections = group.size(); nMostConnectionsTime = grouptime; naMostConnections = node.nKeyedNetGroup; } @@ -1034,9 +1044,9 @@ bool CConnman::AttemptToEvictConnection() // Disconnect from the network group with the most connections NodeId evicted = vEvictionCandidates.front().id; LOCK(cs_vNodes); - for(std::vector<CNode*>::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) { - if ((*it)->GetId() == evicted) { - (*it)->fDisconnect = true; + for (CNode* pnode : vNodes) { + if (pnode->GetId() == evicted) { + pnode->fDisconnect = true; return true; } } @@ -1060,9 +1070,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr); { LOCK(cs_vNodes); - for (CNode* pnode : vNodes) - if (pnode->fInbound) - nInbound++; + for (const CNode* pnode : vNodes) { + if (pnode->fInbound) nInbound++; + } } if (hSocket == INVALID_SOCKET) @@ -1114,7 +1124,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true); pnode->AddRef(); pnode->fWhitelisted = whitelisted; - GetNodeSignals().InitializeNode(pnode, *this); + m_msgproc->InitializeNode(pnode); LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString()); @@ -1438,9 +1448,9 @@ void CConnman::WakeMessageHandler() void ThreadMapPort() { std::string port = strprintf("%u", GetListenPort()); - const char * multicastif = 0; - const char * minissdpdpath = 0; - struct UPNPDev * devlist = 0; + const char * multicastif = nullptr; + const char * minissdpdpath = nullptr; + struct UPNPDev * devlist = nullptr; char lanaddr[64]; #ifndef UPNPDISCOVER_SUCCESS @@ -1510,13 +1520,13 @@ void ThreadMapPort() { r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r); - freeUPNPDevlist(devlist); devlist = 0; + freeUPNPDevlist(devlist); devlist = nullptr; FreeUPNPUrls(&urls); throw; } } else { LogPrintf("No valid UPnP IGDs found\n"); - freeUPNPDevlist(devlist); devlist = 0; + freeUPNPDevlist(devlist); devlist = nullptr; if (r != 0) FreeUPNPUrls(&urls); } @@ -1524,22 +1534,20 @@ void ThreadMapPort() void MapPort(bool fUseUPnP) { - static boost::thread* upnp_thread = NULL; + static std::unique_ptr<boost::thread> upnp_thread; if (fUseUPnP) { if (upnp_thread) { upnp_thread->interrupt(); upnp_thread->join(); - delete upnp_thread; } - upnp_thread = new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)); + upnp_thread.reset(new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort))); } else if (upnp_thread) { upnp_thread->interrupt(); upnp_thread->join(); - delete upnp_thread; - upnp_thread = NULL; + upnp_thread.reset(); } } @@ -1575,14 +1583,14 @@ void CConnman::ThreadDNSAddressSeed() // creating fewer identifying DNS requests, reduces trust by giving seeds // less influence on the network topology, and reduces traffic to the seeds. if ((addrman.size() > 0) && - (!GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) { + (!gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) { if (!interruptNet.sleep_for(std::chrono::seconds(11))) return; LOCK(cs_vNodes); int nRelevant = 0; for (auto pnode : vNodes) { - nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices); + nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound; } if (nRelevant >= 2) { LogPrintf("P2P peers available. Skipped DNS seeding.\n"); @@ -1604,7 +1612,7 @@ void CConnman::ThreadDNSAddressSeed() } else { std::vector<CNetAddr> vIPs; std::vector<CAddress> vAdd; - ServiceFlags requiredServiceBits = nRelevantServices; + ServiceFlags requiredServiceBits = GetDesirableServiceFlags(NODE_NONE); std::string host = GetDNSHost(seed, &requiredServiceBits); CNetAddr resolveSource; if (!resolveSource.SetInternal(host)) { @@ -1674,18 +1682,49 @@ void CConnman::ProcessOneShot() } } -void CConnman::ThreadOpenConnections() +bool CConnman::GetTryNewOutboundPeer() +{ + return m_try_another_outbound_peer; +} + +void CConnman::SetTryNewOutboundPeer(bool flag) +{ + m_try_another_outbound_peer = flag; + LogPrint(BCLog::NET, "net: setting try another outbound peer=%s\n", flag ? "true" : "false"); +} + +// Return the number of peers we have over our outbound connection limit +// Exclude peers that are marked for disconnect, or are going to be +// disconnected soon (eg one-shots and feelers) +// Also exclude peers that haven't finished initial connection handshake yet +// (so that we don't decide we're over our desired connection limit, and then +// evict some peer that has finished the handshake) +int CConnman::GetExtraOutboundCount() +{ + int nOutbound = 0; + { + LOCK(cs_vNodes); + for (CNode* pnode : vNodes) { + if (!pnode->fInbound && !pnode->m_manual_connection && !pnode->fFeeler && !pnode->fDisconnect && !pnode->fOneShot && pnode->fSuccessfullyConnected) { + ++nOutbound; + } + } + } + return std::max(nOutbound - nMaxOutbound, 0); +} + +void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) { // Connect to specific addresses - if (gArgs.IsArgSet("-connect")) + if (!connect.empty()) { for (int64_t nLoop = 0;; nLoop++) { ProcessOneShot(); - for (const std::string& strAddr : gArgs.GetArgs("-connect")) + for (const std::string& strAddr : connect) { CAddress addr(CService(), NODE_NONE); - OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); + OpenNetworkConnection(addr, false, nullptr, strAddr.c_str(), false, false, true); for (int i = 0; i < 10 && i < nLoop; i++) { if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) @@ -1733,17 +1772,11 @@ void CConnman::ThreadOpenConnections() // Only connect out to one peer per network group (/16 for IPv4). // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. int nOutbound = 0; - int nOutboundRelevant = 0; std::set<std::vector<unsigned char> > setConnected; { LOCK(cs_vNodes); for (CNode* pnode : vNodes) { - if (!pnode->fInbound && !pnode->fAddnode) { - - // Count the peers that have all relevant services - if (pnode->fSuccessfullyConnected && !pnode->fFeeler && ((pnode->nServices & nRelevantServices) == nRelevantServices)) { - nOutboundRelevant++; - } + if (!pnode->fInbound && !pnode->m_manual_connection) { // Netgroups for inbound and addnode peers are not excluded because our goal here // is to not use multiple of our limited outbound slots on a single netgroup // but inbound and addnode peers do not use our outbound slots. Inbound peers @@ -1768,7 +1801,8 @@ void CConnman::ThreadOpenConnections() // * Only make a feeler connection once every few minutes. // bool fFeeler = false; - if (nOutbound >= nMaxOutbound) { + + if (nOutbound >= nMaxOutbound && !GetTryNewOutboundPeer()) { int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds). if (nTime > nNextFeeler) { nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL); @@ -1798,21 +1832,16 @@ void CConnman::ThreadOpenConnections() if (IsLimited(addr)) continue; - // only connect to full nodes - if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES) - continue; - // only consider very recently tried nodes after 30 failed attempts if (nANow - addr.nLastTry < 600 && nTries < 30) continue; - // only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up. - ServiceFlags nRequiredServices = nRelevantServices; - if (nTries >= 40 && nOutbound < (nMaxOutbound >> 1)) { - nRequiredServices = REQUIRED_SERVICES; - } - - if ((addr.nServices & nRequiredServices) != nRequiredServices) { + // for non-feelers, require all the services we'll want, + // for feelers, only require they be a full node (only because most + // SPV clients don't have a good address DB available) + if (!fFeeler && !HasAllDesirableServiceFlags(addr.nServices)) { + continue; + } else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) { continue; } @@ -1821,13 +1850,6 @@ void CConnman::ThreadOpenConnections() continue; addrConnect = addr; - - // regardless of the services assumed to be available, only require the minimum if half or more outbound have relevant services - if (nOutboundRelevant >= (nMaxOutbound >> 1)) { - addrConnect.nServices = REQUIRED_SERVICES; - } else { - addrConnect.nServices = nRequiredServices; - } break; } @@ -1841,7 +1863,7 @@ void CConnman::ThreadOpenConnections() LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString()); } - OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, NULL, false, fFeeler); + OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, false, fFeeler); } } } @@ -1854,8 +1876,7 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() { LOCK(cs_vAddedNodes); ret.reserve(vAddedNodes.size()); - for (const std::string& strAddNode : vAddedNodes) - lAddresses.push_back(strAddNode); + std::copy(vAddedNodes.cbegin(), vAddedNodes.cend(), std::back_inserter(lAddresses)); } @@ -1901,11 +1922,6 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() void CConnman::ThreadOpenAddedConnections() { - { - LOCK(cs_vAddedNodes); - vAddedNodes = gArgs.GetArgs("-addnode"); - } - while (true) { CSemaphoreGrant grant(*semAddnode); @@ -1918,11 +1934,9 @@ void CConnman::ThreadOpenAddedConnections() // the addednodeinfo state might change. break; } - // If strAddedNode is an IP/port, decode it immediately, so - // OpenNetworkConnection can detect existing connections to that IP/port. tried = true; - CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort())); - OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true); + CAddress addr(CService(), NODE_NONE); + OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), false, false, true); if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) return; } @@ -1934,7 +1948,7 @@ void CConnman::ThreadOpenAddedConnections() } // if successful, this moves the passed grant to the constructed node -bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode) +bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool manual_connection) { // // Initiate outbound network connection @@ -1963,10 +1977,10 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai pnode->fOneShot = true; if (fFeeler) pnode->fFeeler = true; - if (fAddnode) - pnode->fAddnode = true; + if (manual_connection) + pnode->m_manual_connection = true; - GetNodeSignals().InitializeNode(pnode, *this); + m_msgproc->InitializeNode(pnode); { LOCK(cs_vNodes); vNodes.push_back(pnode); @@ -1996,16 +2010,16 @@ void CConnman::ThreadMessageHandler() continue; // Receive messages - bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc); + bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc); fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); if (flagInterruptMsgProc) return; - // Send messages { LOCK(pnode->cs_sendProcessing); - GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); + m_msgproc->SendMessages(pnode, flagInterruptMsgProc); } + if (flagInterruptMsgProc) return; } @@ -2153,9 +2167,9 @@ void Discover(boost::thread_group& threadGroup) struct ifaddrs* myaddrs; if (getifaddrs(&myaddrs) == 0) { - for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) + for (struct ifaddrs* ifa = myaddrs; ifa != nullptr; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == NULL) continue; + if (ifa->ifa_addr == nullptr) continue; if ((ifa->ifa_flags & IFF_UP) == 0) continue; if (strcmp(ifa->ifa_name, "lo") == 0) continue; if (strcmp(ifa->ifa_name, "lo0") == 0) continue; @@ -2183,16 +2197,18 @@ void CConnman::SetNetworkActive(bool active) { LogPrint(BCLog::NET, "SetNetworkActive: %s\n", active); - if (!active) { - fNetworkActive = false; + if (fNetworkActive == active) { + return; + } + + fNetworkActive = active; + if (!fNetworkActive) { LOCK(cs_vNodes); // Close sockets to all nodes for (CNode* pnode : vNodes) { pnode->CloseSocketDisconnect(); } - } else { - fNetworkActive = true; } uiInterface.NotifyNetworkActiveChanged(fNetworkActive); @@ -2206,14 +2222,11 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe nLastNodeId = 0; nSendBufferMaxSize = 0; nReceiveFloodSize = 0; - semOutbound = NULL; - semAddnode = NULL; - nMaxConnections = 0; - nMaxOutbound = 0; - nMaxAddnode = 0; - nBestHeight = 0; - clientInterface = NULL; flagInterruptMsgProc = false; + SetTryNewOutboundPeer(false); + + Options connOptions; + Init(connOptions); } NodeId CConnman::GetNewNodeId() @@ -2252,30 +2265,15 @@ bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<C return fBound; } -bool CConnman::Start(CScheduler& scheduler, Options connOptions) +bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) { + Init(connOptions); + nTotalBytesRecv = 0; nTotalBytesSent = 0; nMaxOutboundTotalBytesSentInCycle = 0; nMaxOutboundCycleStartTime = 0; - nRelevantServices = connOptions.nRelevantServices; - nLocalServices = connOptions.nLocalServices; - nMaxConnections = connOptions.nMaxConnections; - nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); - nMaxAddnode = connOptions.nMaxAddnode; - nMaxFeeler = connOptions.nMaxFeeler; - - nSendBufferMaxSize = connOptions.nSendBufferMaxSize; - nReceiveFloodSize = connOptions.nReceiveFloodSize; - - nMaxOutboundLimit = connOptions.nMaxOutboundLimit; - nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; - - SetBestHeight(connOptions.nBestHeight); - - clientInterface = connOptions.uiInterface; - if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) { if (clientInterface) { clientInterface->ThreadSafeMessageBox( @@ -2285,8 +2283,6 @@ bool CConnman::Start(CScheduler& scheduler, Options connOptions) return false; } - vWhitelistedRange = connOptions.vWhitelistedRange; - for (const auto& strDest : connOptions.vSeedNodes) { AddOneShot(strDest); } @@ -2329,18 +2325,19 @@ bool CConnman::Start(CScheduler& scheduler, Options connOptions) fAddressesInitialized = true; - if (semOutbound == NULL) { + if (semOutbound == nullptr) { // initialize semaphore - semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); + semOutbound = MakeUnique<CSemaphore>(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); } - if (semAddnode == NULL) { + if (semAddnode == nullptr) { // initialize semaphore - semAddnode = new CSemaphore(nMaxAddnode); + semAddnode = MakeUnique<CSemaphore>(nMaxAddnode); } // // Start threads // + assert(m_msgproc); InterruptSocks5(false); interruptNet.reset(); flagInterruptMsgProc = false; @@ -2353,7 +2350,7 @@ bool CConnman::Start(CScheduler& scheduler, Options connOptions) // Send and receive from sockets, accept connections threadSocketHandler = std::thread(&TraceThread<std::function<void()> >, "net", std::function<void()>(std::bind(&CConnman::ThreadSocketHandler, this))); - if (!GetBoolArg("-dnsseed", true)) + if (!gArgs.GetBoolArg("-dnsseed", true)) LogPrintf("DNS seeding disabled\n"); else threadDNSAddressSeed = std::thread(&TraceThread<std::function<void()> >, "dnsseed", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this))); @@ -2361,9 +2358,16 @@ bool CConnman::Start(CScheduler& scheduler, Options connOptions) // Initiate outbound connections from -addnode threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this))); - // Initiate outbound connections unless connect=0 - if (!gArgs.IsArgSet("-connect") || gArgs.GetArgs("-connect").size() != 1 || gArgs.GetArgs("-connect")[0] != "0") - threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this))); + if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) { + if (clientInterface) { + clientInterface->ThreadSafeMessageBox( + _("Cannot provide specific connections and have addrman find outgoing connections at the same."), + "", CClientUIInterface::MSG_ERROR); + } + return false; + } + if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty()) + threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this, connOptions.m_specified_outgoing))); // Process messages threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this))); @@ -2450,19 +2454,18 @@ void CConnman::Stop() vNodes.clear(); vNodesDisconnected.clear(); vhListenSocket.clear(); - delete semOutbound; - semOutbound = NULL; - delete semAddnode; - semAddnode = NULL; + semOutbound.reset(); + semAddnode.reset(); } void CConnman::DeleteNode(CNode* pnode) { assert(pnode); bool fUpdateConnectionTime = false; - GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime); - if(fUpdateConnectionTime) + m_msgproc->FinalizeNode(pnode->GetId(), fUpdateConnectionTime); + if(fUpdateConnectionTime) { addrman.Connected(pnode->addr); + } delete pnode; } @@ -2500,9 +2503,8 @@ std::vector<CAddress> CConnman::GetAddresses() bool CConnman::AddNode(const std::string& strNode) { LOCK(cs_vAddedNodes); - for(std::vector<std::string>::const_iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) { - if (strNode == *it) - return false; + for (const std::string& it : vAddedNodes) { + if (strNode == it) return false; } vAddedNodes.push_back(strNode); @@ -2528,9 +2530,11 @@ size_t CConnman::GetNodeCount(NumConnections flags) return vNodes.size(); int nNum = 0; - for(std::vector<CNode*>::const_iterator it = vNodes.begin(); it != vNodes.end(); ++it) - if (flags & ((*it)->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) + for (const auto& pnode : vNodes) { + if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) { nNum++; + } + } return nNum; } @@ -2540,8 +2544,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) vstats.clear(); LOCK(cs_vNodes); vstats.reserve(vNodes.size()); - for(std::vector<CNode*>::iterator it = vNodes.begin(); it != vNodes.end(); ++it) { - CNode* pnode = *it; + for (CNode* pnode : vNodes) { vstats.emplace_back(); pnode->copyStats(vstats.back()); } @@ -2692,7 +2695,6 @@ int CConnman::GetBestHeight() const } unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } -unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string& addrNameIn, bool fInboundIn) : nTimeConnected(GetSystemTimeInSeconds()), @@ -2709,7 +2711,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nSendVersion(0) { nServices = NODE_NONE; - nServicesExpected = NODE_NONE; hSocket = hSocketIn; nRecvVersion = INIT_PROTO_VERSION; nLastSend = 0; @@ -2722,7 +2723,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn strSubVer = ""; fWhitelisted = false; fOneShot = false; - fAddnode = false; + m_manual_connection = false; fClient = false; // set by version message fFeeler = false; fSuccessfullyConnected = false; @@ -2740,7 +2741,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nNextInvSend = 0; fRelayTxes = false; fSentAddr = false; - pfilter = new CBloomFilter(); + pfilter = MakeUnique<CBloomFilter>(); timeLastMempoolReq = 0; nLastBlockTime = 0; nLastTXTime = 0; @@ -2770,9 +2771,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn CNode::~CNode() { CloseSocket(hSocket); - - if (pfilter) - delete pfilter; } void CNode::AskFor(const CInv& inv) |