From a9ac95c1bc67726a7d6eecb35d7650eed6c89361 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Sun, 31 May 2015 15:36:44 +0200 Subject: use const references where appropriate --- src/net.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3908be682..42ac0e50e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -107,7 +107,7 @@ boost::condition_variable messageHandlerCondition; static CNodeSignals g_signals; CNodeSignals& GetNodeSignals() { return g_signals; } -void AddOneShot(string strDest) +void AddOneShot(const std::string& strDest) { LOCK(cs_vOneShots); vOneShots.push_back(strDest); @@ -1124,7 +1124,7 @@ void ThreadDNSAddressSeed() vector vAdd; if (LookupHost(seed.host.c_str(), vIPs)) { - BOOST_FOREACH(CNetAddr& ip, vIPs) + BOOST_FOREACH(const CNetAddr& ip, vIPs) { int nOneDay = 24*3600; CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); @@ -1188,7 +1188,7 @@ void ThreadOpenConnections() for (int64_t nLoop = 0;; nLoop++) { ProcessOneShot(); - BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"]) + BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"]) { CAddress addr; OpenNetworkConnection(addr, NULL, strAddr.c_str()); @@ -1291,10 +1291,10 @@ void ThreadOpenAddedConnections() list lAddresses(0); { LOCK(cs_vAddedNodes); - BOOST_FOREACH(string& strAddNode, vAddedNodes) + BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) lAddresses.push_back(strAddNode); } - BOOST_FOREACH(string& strAddNode, lAddresses) { + BOOST_FOREACH(const std::string& strAddNode, lAddresses) { CAddress addr; CSemaphoreGrant grant(*semOutbound); OpenNetworkConnection(addr, &grant, strAddNode.c_str()); @@ -1309,20 +1309,19 @@ void ThreadOpenAddedConnections() list lAddresses(0); { LOCK(cs_vAddedNodes); - BOOST_FOREACH(string& strAddNode, vAddedNodes) + BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) lAddresses.push_back(strAddNode); } list > lservAddressesToAdd(0); - BOOST_FOREACH(string& strAddNode, lAddresses) - { + BOOST_FOREACH(const std::string& strAddNode, lAddresses) { vector vservNode(0); if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) { lservAddressesToAdd.push_back(vservNode); { LOCK(cs_setservAddNodeAddresses); - BOOST_FOREACH(CService& serv, vservNode) + BOOST_FOREACH(const CService& serv, vservNode) setservAddNodeAddresses.insert(serv); } } @@ -1333,7 +1332,7 @@ void ThreadOpenAddedConnections() LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) for (list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) - BOOST_FOREACH(CService& addrNode, *(it)) + BOOST_FOREACH(const CService& addrNode, *(it)) if (pnode->addr == addrNode) { it = lservAddressesToAdd.erase(it); @@ -1906,7 +1905,7 @@ bool CAddrDB::Read(CAddrMan& addr) unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } -CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : +CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addrKnown(5000, 0.001, insecure_rand()), setInventoryKnown(SendBufferSize() / 1000) -- cgit v1.2.3 From e3cae525382520ddbef92bf86f43eaf0521f4325 Mon Sep 17 00:00:00 2001 From: Josh Lehan Date: Sun, 16 Nov 2014 03:19:23 -0800 Subject: Added -whiteconnections= option This sets aside a number of connection slots for whitelisted peers, useful for ensuring your local users and miners can always get in, even if your limit on inbound connections has already been reached. --- src/net.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 42ac0e50e..541318e74 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -79,6 +79,7 @@ uint64_t nLocalHostNonce = 0; static std::vector vhListenSocket; CAddrMan addrman; int nMaxConnections = 125; +int nWhiteConnections = 0; bool fAddressesInitialized = false; vector vNodes; @@ -827,6 +828,7 @@ void ThreadSocketHandler() SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; + int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS; if (hSocket != INVALID_SOCKET) if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) @@ -846,8 +848,14 @@ void ThreadSocketHandler() if (nErr != WSAEWOULDBLOCK) LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); } - else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) + else if (nInbound >= nMaxInbound) { + LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); + CloseSocket(hSocket); + } + else if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) + { + LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString()); CloseSocket(hSocket); } else if (CNode::IsBanned(addr) && !whitelisted) @@ -861,6 +869,8 @@ void ThreadSocketHandler() pnode->AddRef(); pnode->fWhitelisted = whitelisted; + LogPrint("net", "connection from %s accepted\n", addr.ToString()); + { LOCK(cs_vNodes); vNodes.push_back(pnode); -- cgit v1.2.3 From 2b890dd424b32320be6fc0333e67e2d7c9616065 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 16 Jun 2015 04:02:25 -0400 Subject: locking: fix a few small issues uncovered by -Wthread-safety - rpcwallet: No need to lock twice here - openssl: Clang doesn't understand selective lock/unlock here. Ignore it. - CNode: Fix a legitimate (though very unlikely) locking bug. --- src/net.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 42ac0e50e..adf89554d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2032,8 +2032,10 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) Fuzz(GetArg("-fuzzmessagestest", 10)); if (ssSend.size() == 0) + { + LEAVE_CRITICAL_SECTION(cs_vSend); return; - + } // Set the size unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); -- cgit v1.2.3 From 2252fb91cd19832c8baa63a10aaf7ce32bb400f8 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 19 May 2015 10:07:23 +0200 Subject: [net] extend core functionallity for ban/unban/listban --- src/net.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 42ac0e50e..51d1c5333 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -458,16 +458,31 @@ bool CNode::IsBanned(CNetAddr ip) return fResult; } -bool CNode::Ban(const CNetAddr &addr) { +bool CNode::Ban(const CNetAddr &addr, int64_t bantimeoffset) { int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban - { - LOCK(cs_setBanned); - if (setBanned[addr] < banTime) - setBanned[addr] = banTime; - } + if (bantimeoffset > 0) + banTime = GetTime()+bantimeoffset; + + LOCK(cs_setBanned); + if (setBanned[addr] < banTime) + setBanned[addr] = banTime; + return true; } +bool CNode::Unban(const CNetAddr &addr) { + LOCK(cs_setBanned); + if (setBanned.erase(addr)) + return true; + return false; +} + +void CNode::GetBanned(std::map &banMap) +{ + LOCK(cs_setBanned); + banMap = setBanned; //create a thread safe copy +} + std::vector CNode::vWhitelistedRange; CCriticalSection CNode::cs_vWhitelistedRange; -- cgit v1.2.3 From e8b93473f12ec901f965cd244a7437646ee66c43 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 19 May 2015 17:15:25 +0200 Subject: [net] remove unused return type bool from CNode::Ban() --- src/net.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 51d1c5333..a065bb29b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -458,7 +458,7 @@ bool CNode::IsBanned(CNetAddr ip) return fResult; } -bool CNode::Ban(const CNetAddr &addr, int64_t bantimeoffset) { +void CNode::Ban(const CNetAddr &addr, int64_t bantimeoffset) { int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban if (bantimeoffset > 0) banTime = GetTime()+bantimeoffset; @@ -466,8 +466,6 @@ bool CNode::Ban(const CNetAddr &addr, int64_t bantimeoffset) { LOCK(cs_setBanned); if (setBanned[addr] < banTime) setBanned[addr] = banTime; - - return true; } bool CNode::Unban(const CNetAddr &addr) { -- cgit v1.2.3 From 433fb1a95d7a96a033d7454e198d274e92108865 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 25 May 2015 20:03:51 +0200 Subject: [RPC] extend setban to allow subnets --- src/net.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a065bb29b..3ba2379ea 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -332,6 +332,15 @@ CNode* FindNode(const CNetAddr& ip) return NULL; } +CNode* FindNode(const CSubNet& subNet) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (subNet.Match((CNetAddr)pnode->addr)) + return (pnode); + return NULL; +} + CNode* FindNode(const std::string& addrName) { LOCK(cs_vNodes); @@ -434,7 +443,7 @@ void CNode::PushVersion() -std::map CNode::setBanned; +std::map CNode::setBanned; CCriticalSection CNode::cs_setBanned; void CNode::ClearBanned() @@ -447,7 +456,24 @@ bool CNode::IsBanned(CNetAddr ip) bool fResult = false; { LOCK(cs_setBanned); - std::map::iterator i = setBanned.find(ip); + for (std::map::iterator it = setBanned.begin(); it != setBanned.end(); it++) + { + CSubNet subNet = (*it).first; + int64_t t = (*it).second; + + if(subNet.Match(ip) && GetTime() < t) + fResult = true; + } + } + return fResult; +} + +bool CNode::IsBanned(CSubNet subnet) +{ + bool fResult = false; + { + LOCK(cs_setBanned); + std::map::iterator i = setBanned.find(subnet); if (i != setBanned.end()) { int64_t t = (*i).second; @@ -458,24 +484,34 @@ bool CNode::IsBanned(CNetAddr ip) return fResult; } -void CNode::Ban(const CNetAddr &addr, int64_t bantimeoffset) { +void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset) { + CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); + Ban(subNet, bantimeoffset); +} + +void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset) { int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban if (bantimeoffset > 0) banTime = GetTime()+bantimeoffset; LOCK(cs_setBanned); - if (setBanned[addr] < banTime) - setBanned[addr] = banTime; + if (setBanned[subNet] < banTime) + setBanned[subNet] = banTime; } bool CNode::Unban(const CNetAddr &addr) { + CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); + return Unban(subNet); +} + +bool CNode::Unban(const CSubNet &subNet) { LOCK(cs_setBanned); - if (setBanned.erase(addr)) + if (setBanned.erase(subNet)) return true; return false; } -void CNode::GetBanned(std::map &banMap) +void CNode::GetBanned(std::map &banMap) { LOCK(cs_setBanned); banMap = setBanned; //create a thread safe copy -- cgit v1.2.3 From 4e36e9bcc7d071bba4c45fd89c0cfd2e2361ffe3 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 12 Jun 2015 18:31:47 +0200 Subject: setban: rewrite to UniValue, allow absolute bantime --- src/net.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3ba2379ea..6b8a0a2b1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -484,15 +484,15 @@ bool CNode::IsBanned(CSubNet subnet) return fResult; } -void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset) { +void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset, bool sinceUnixEpoch) { CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); - Ban(subNet, bantimeoffset); + Ban(subNet, bantimeoffset, sinceUnixEpoch); } -void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset) { +void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoch) { int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban if (bantimeoffset > 0) - banTime = GetTime()+bantimeoffset; + banTime = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; LOCK(cs_setBanned); if (setBanned[subNet] < banTime) -- cgit v1.2.3 From 62909f68a087e85475b7fbad6d9a3a8873d0c811 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 19 Jun 2015 13:31:33 +0200 Subject: fix missing lock in CNode::ClearBanned() --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6b8a0a2b1..0511256e5 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -448,6 +448,7 @@ CCriticalSection CNode::cs_setBanned; void CNode::ClearBanned() { + LOCK(cs_setBanned); setBanned.clear(); } -- cgit v1.2.3 From f581d3d656cf269ea09ac6f130f4bd70b40a9e55 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 19 Jun 2015 15:27:37 +0200 Subject: banlist.dat: store banlist on disk --- src/net.cpp | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 0511256e5..3a549d65c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -445,11 +445,13 @@ void CNode::PushVersion() std::map CNode::setBanned; CCriticalSection CNode::cs_setBanned; +bool CNode::setBannedIsDirty; void CNode::ClearBanned() { LOCK(cs_setBanned); setBanned.clear(); + setBannedIsDirty = true; } bool CNode::IsBanned(CNetAddr ip) @@ -498,6 +500,8 @@ void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoc LOCK(cs_setBanned); if (setBanned[subNet] < banTime) setBanned[subNet] = banTime; + + setBannedIsDirty = true; } bool CNode::Unban(const CNetAddr &addr) { @@ -508,7 +512,10 @@ bool CNode::Unban(const CNetAddr &addr) { bool CNode::Unban(const CSubNet &subNet) { LOCK(cs_setBanned); if (setBanned.erase(subNet)) + { + setBannedIsDirty = true; return true; + } return false; } @@ -518,6 +525,43 @@ void CNode::GetBanned(std::map &banMap) banMap = setBanned; //create a thread safe copy } +void CNode::SetBanned(const std::map &banMap) +{ + LOCK(cs_setBanned); + setBanned = banMap; + setBannedIsDirty = true; +} + +void CNode::SweepBanned() +{ + int64_t now = GetTime(); + + LOCK(cs_setBanned); + std::map::iterator it = setBanned.begin(); + while(it != setBanned.end()) + { + if(now > (*it).second) + { + setBanned.erase(it++); + setBannedIsDirty = true; + } + else + ++it; + } +} + +bool CNode::BannedSetIsDirty() +{ + LOCK(cs_setBanned); + return setBannedIsDirty; +} + +void CNode::SetBannedSetDirty(bool dirty) +{ + LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag + setBannedIsDirty = dirty; +} + std::vector CNode::vWhitelistedRange; CCriticalSection CNode::cs_vWhitelistedRange; @@ -1212,6 +1256,17 @@ void DumpAddresses() addrman.size(), GetTimeMillis() - nStart); } +void DumpData() +{ + DumpAddresses(); + + if (CNode::BannedSetIsDirty()) + { + DumpBanlist(); + CNode::SetBannedSetDirty(false); + } +} + void static ProcessOneShot() { string strDest; @@ -1650,6 +1705,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) if (!adb.Read(addrman)) LogPrintf("Invalid or missing peers.dat; recreating\n"); } + + //try to read stored banlist + CBanDB bandb; + std::map banmap; + if (!bandb.Read(banmap)) + LogPrintf("Invalid or missing banlist.dat; recreating\n"); + + CNode::SetBanned(banmap); //thread save setter + CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data + CNode::SweepBanned(); //sweap out unused entries + LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); fAddressesInitialized = true; @@ -1690,7 +1756,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) threadGroup.create_thread(boost::bind(&TraceThread, "msghand", &ThreadMessageHandler)); // Dump network addresses - scheduler.scheduleEvery(&DumpAddresses, DUMP_ADDRESSES_INTERVAL); + scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL); } bool StopNode() @@ -1703,7 +1769,7 @@ bool StopNode() if (fAddressesInitialized) { - DumpAddresses(); + DumpData(); fAddressesInitialized = false; } @@ -2107,3 +2173,119 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) LEAVE_CRITICAL_SECTION(cs_vSend); } + +// +// CBanDB +// + +CBanDB::CBanDB() +{ + pathBanlist = GetDataDir() / "banlist.dat"; +} + +bool CBanDB::Write(const std::map& banSet) +{ + // Generate random temporary filename + unsigned short randv = 0; + GetRandBytes((unsigned char*)&randv, sizeof(randv)); + std::string tmpfn = strprintf("banlist.dat.%04x", randv); + + // serialize banlist, checksum data up to that point, then append csum + CDataStream ssBanlist(SER_DISK, CLIENT_VERSION); + ssBanlist << FLATDATA(Params().MessageStart()); + ssBanlist << banSet; + uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end()); + ssBanlist << hash; + + // open temp output file, and associate with CAutoFile + boost::filesystem::path pathTmp = GetDataDir() / tmpfn; + FILE *file = fopen(pathTmp.string().c_str(), "wb"); + CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s: Failed to open file %s", __func__, pathTmp.string()); + + // Write and commit header, data + try { + fileout << ssBanlist; + } + catch (const std::exception& e) { + return error("%s: Serialize or I/O error - %s", __func__, e.what()); + } + FileCommit(fileout.Get()); + fileout.fclose(); + + // replace existing banlist.dat, if any, with new banlist.dat.XXXX + if (!RenameOver(pathTmp, pathBanlist)) + return error("%s: Rename-into-place failed", __func__); + + return true; +} + +bool CBanDB::Read(std::map& banSet) +{ + // open input file, and associate with CAutoFile + FILE *file = fopen(pathBanlist.string().c_str(), "rb"); + CAutoFile filein(file, SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s: Failed to open file %s", __func__, pathBanlist.string()); + + // use file size to size memory buffer + int fileSize = boost::filesystem::file_size(pathBanlist); + int dataSize = fileSize - sizeof(uint256); + // Don't try to resize to a negative number if file is small + if (dataSize < 0) + dataSize = 0; + vector vchData; + vchData.resize(dataSize); + uint256 hashIn; + + // read data and checksum from file + try { + filein.read((char *)&vchData[0], dataSize); + filein >> hashIn; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + filein.fclose(); + + CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION); + + // verify stored checksum matches input data + uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end()); + if (hashIn != hashTmp) + return error("%s: Checksum mismatch, data corrupted", __func__); + + unsigned char pchMsgTmp[4]; + try { + // de-serialize file header (network specific magic number) and .. + ssBanlist >> FLATDATA(pchMsgTmp); + + // ... verify the network matches ours + if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) + return error("%s: Invalid network magic number", __func__); + + // de-serialize address data into one CAddrMan object + ssBanlist >> banSet; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + + return true; +} + +void DumpBanlist() +{ + int64_t nStart = GetTimeMillis(); + + CNode::SweepBanned(); //clean unused entires (if bantime has expired) + + CBanDB bandb; + std::map banmap; + CNode::GetBanned(banmap); + bandb.Write(banmap); + + LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - nStart); +} \ No newline at end of file -- cgit v1.2.3 From dfa174c2957f2600f05bf0ee9dd17fe18fb54fd7 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 26 Jun 2015 15:21:59 +0200 Subject: CAddrDB/CBanDB: change filesize variables from int to uint64_t --- src/net.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3a549d65c..03db1f06a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1973,11 +1973,11 @@ bool CAddrDB::Read(CAddrMan& addr) return error("%s: Failed to open file %s", __func__, pathAddr.string()); // use file size to size memory buffer - int fileSize = boost::filesystem::file_size(pathAddr); - int dataSize = fileSize - sizeof(uint256); + uint64_t fileSize = boost::filesystem::file_size(pathAddr); + uint64_t dataSize = 0; // Don't try to resize to a negative number if file is small - if (dataSize < 0) - dataSize = 0; + if (fileSize >= sizeof(uint256)) + dataSize = fileSize - sizeof(uint256); vector vchData; vchData.resize(dataSize); uint256 hashIn; @@ -2230,11 +2230,11 @@ bool CBanDB::Read(std::map& banSet) return error("%s: Failed to open file %s", __func__, pathBanlist.string()); // use file size to size memory buffer - int fileSize = boost::filesystem::file_size(pathBanlist); - int dataSize = fileSize - sizeof(uint256); + uint64_t fileSize = boost::filesystem::file_size(pathBanlist); + uint64_t dataSize = 0; // Don't try to resize to a negative number if file is small - if (dataSize < 0) - dataSize = 0; + if (fileSize >= sizeof(uint256)) + dataSize = fileSize - sizeof(uint256); vector vchData; vchData.resize(dataSize); uint256 hashIn; -- cgit v1.2.3 From 409bccfbf52b531b2a9d60ac2308f56223931a2e Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 26 Jun 2015 21:38:33 +0200 Subject: use CBanEntry as object container for banned nodes - added a reason enum for a ban - added creation time for a ban Using CBanEntry as container will keep banlist.dat extenable. --- src/net.cpp | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 03db1f06a..ade34f575 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -443,7 +443,7 @@ void CNode::PushVersion() -std::map CNode::setBanned; +banmap_t CNode::setBanned; CCriticalSection CNode::cs_setBanned; bool CNode::setBannedIsDirty; @@ -459,12 +459,12 @@ bool CNode::IsBanned(CNetAddr ip) bool fResult = false; { LOCK(cs_setBanned); - for (std::map::iterator it = setBanned.begin(); it != setBanned.end(); it++) + for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++) { CSubNet subNet = (*it).first; - int64_t t = (*it).second; + CBanEntry banEntry = (*it).second; - if(subNet.Match(ip) && GetTime() < t) + if(subNet.Match(ip) && GetTime() < banEntry.nBanUntil) fResult = true; } } @@ -476,30 +476,36 @@ bool CNode::IsBanned(CSubNet subnet) bool fResult = false; { LOCK(cs_setBanned); - std::map::iterator i = setBanned.find(subnet); + banmap_t::iterator i = setBanned.find(subnet); if (i != setBanned.end()) { - int64_t t = (*i).second; - if (GetTime() < t) + CBanEntry banEntry = (*i).second; + if (GetTime() < banEntry.nBanUntil) fResult = true; } } return fResult; } -void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset, bool sinceUnixEpoch) { +void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); - Ban(subNet, bantimeoffset, sinceUnixEpoch); + Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch); } -void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoch) { - int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban - if (bantimeoffset > 0) - banTime = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; +void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { + CBanEntry banEntry(GetTime()); + banEntry.banReason = banReason; + if (bantimeoffset <= 0) + { + bantimeoffset = GetArg("-bantime", 60*60*24); // Default 24-hour ban + sinceUnixEpoch = false; + } + banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; + LOCK(cs_setBanned); - if (setBanned[subNet] < banTime) - setBanned[subNet] = banTime; + if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) + setBanned[subNet] = banEntry; setBannedIsDirty = true; } @@ -519,13 +525,13 @@ bool CNode::Unban(const CSubNet &subNet) { return false; } -void CNode::GetBanned(std::map &banMap) +void CNode::GetBanned(banmap_t &banMap) { LOCK(cs_setBanned); banMap = setBanned; //create a thread safe copy } -void CNode::SetBanned(const std::map &banMap) +void CNode::SetBanned(const banmap_t &banMap) { LOCK(cs_setBanned); setBanned = banMap; @@ -537,10 +543,11 @@ void CNode::SweepBanned() int64_t now = GetTime(); LOCK(cs_setBanned); - std::map::iterator it = setBanned.begin(); + banmap_t::iterator it = setBanned.begin(); while(it != setBanned.end()) { - if(now > (*it).second) + CBanEntry banEntry = (*it).second; + if(now > banEntry.nBanUntil) { setBanned.erase(it++); setBannedIsDirty = true; @@ -1708,7 +1715,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) //try to read stored banlist CBanDB bandb; - std::map banmap; + banmap_t banmap; if (!bandb.Read(banmap)) LogPrintf("Invalid or missing banlist.dat; recreating\n"); @@ -2183,7 +2190,7 @@ CBanDB::CBanDB() pathBanlist = GetDataDir() / "banlist.dat"; } -bool CBanDB::Write(const std::map& banSet) +bool CBanDB::Write(const banmap_t& banSet) { // Generate random temporary filename unsigned short randv = 0; @@ -2221,7 +2228,7 @@ bool CBanDB::Write(const std::map& banSet) return true; } -bool CBanDB::Read(std::map& banSet) +bool CBanDB::Read(banmap_t& banSet) { // open input file, and associate with CAutoFile FILE *file = fopen(pathBanlist.string().c_str(), "rb"); @@ -2282,7 +2289,7 @@ void DumpBanlist() CNode::SweepBanned(); //clean unused entires (if bantime has expired) CBanDB bandb; - std::map banmap; + banmap_t banmap; CNode::GetBanned(banmap); bandb.Write(banmap); -- cgit v1.2.3 From 177a0e491449b9accfa0cf17c138147539071358 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 29 Jun 2015 20:37:22 +0200 Subject: Adding CSubNet constructor over a single CNetAddr --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index ade34f575..950311ee3 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -488,7 +488,7 @@ bool CNode::IsBanned(CSubNet subnet) } void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { - CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); + CSubNet subNet(addr); Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch); } @@ -511,7 +511,7 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti } bool CNode::Unban(const CNetAddr &addr) { - CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); + CSubNet subNet(addr); return Unban(subNet); } -- cgit v1.2.3 From d422f9b1fdb42a51aadaa1bbc157542dca2feb17 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 9 Jul 2015 18:23:27 -0400 Subject: Test whether created sockets are select()able --- src/net.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 2c7ba0ca7..3d369c7dd 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -386,6 +386,12 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) 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; + } + addrman.Attempt(addrConnect); // Add node @@ -949,6 +955,11 @@ void ThreadSocketHandler() if (nErr != WSAEWOULDBLOCK) LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); } + else if (!IsSelectableSocket(hSocket)) + { + LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString()); + CloseSocket(hSocket); + } else if (nInbound >= nMaxInbound) { LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); @@ -1597,6 +1608,13 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste LogPrintf("%s\n", strError); return false; } + if (!IsSelectableSocket(hListenSocket)) + { + strError = "Error: Couldn't create a listenable socket for incoming connections"; + LogPrintf("%s\n", strError); + return false; + } + #ifndef WIN32 #ifdef SO_NOSIGPIPE -- cgit v1.2.3 From 60c8bac77c6612b84e3496b2227a01058d720ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Sun, 5 Jul 2015 14:30:07 +0200 Subject: Includes: Cleanup around net main and wallet -Move from .h to .cpp: in main, net and wallet -Remove unnecessary #include "main.h" -Cleanup some wallet files includes --- src/net.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3d369c7dd..e9fd74db4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -12,10 +12,12 @@ #include "addrman.h" #include "chainparams.h" #include "clientversion.h" +#include "crypto/common.h" +#include "hash.h" #include "primitives/transaction.h" #include "scheduler.h" #include "ui_interface.h" -#include "crypto/common.h" +#include "utilstrencodings.h" #ifdef WIN32 #include -- cgit v1.2.3 From d2d7ee0e863b286e1c9f9c54659d494fb0a7712d Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 20 Jul 2015 04:43:34 +0900 Subject: Make CRollingBloomFilter set nTweak for you While CBloomFilter is usually used with an explicitly set nTweak, CRollingBloomFilter is only used internally. Requiring every caller to set nTweak is error-prone and redundant; better to have the class handle that for you with a high-quality randomness source. Additionally when clearing the filter it makes sense to change nTweak as well to recover from a bad setting, e.g. due to insufficient randomness at initialization, so the clear() method is replaced by a reset() method that sets a new, random, nTweak value. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3cece520d..176fd7195 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2060,7 +2060,7 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), - addrKnown(5000, 0.001, insecure_rand()), + addrKnown(5000, 0.001), setInventoryKnown(SendBufferSize() / 1000) { nServices = 0; -- cgit v1.2.3 From 557f8eac7aa96059270a36358642fbce93ac0478 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Jul 2015 01:58:25 +0200 Subject: implement uacomment config parameter which can add comments to user agent as per BIP-0014 --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3cece520d..42ca69e09 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -445,7 +445,7 @@ void CNode::PushVersion() else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), nBestHeight, true); + nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, mapMultiArgs.count("-uacomment") ? mapMultiArgs["-uacomment"] : std::vector()), nBestHeight, true); } -- cgit v1.2.3 From 19dd40a25f061fb8b16b9332826293f5d0b58a56 Mon Sep 17 00:00:00 2001 From: Matt Quinn Date: Sat, 1 Aug 2015 10:41:21 -0700 Subject: Consolidate individual references to the current maximum peer connection value of 125 into a single constant declaration. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 176fd7195..5d413697b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -80,7 +80,7 @@ static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; static std::vector vhListenSocket; CAddrMan addrman; -int nMaxConnections = 125; +int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; int nWhiteConnections = 0; bool fAddressesInitialized = false; -- cgit v1.2.3 From 7b79cbd722d35b8113d5136b06d4a8e5fd569fc6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 31 Jul 2015 18:05:42 +0200 Subject: limit total length of user agent comments Reworked-By: Wladimir J. van der Laan --- src/net.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 42ca69e09..080d9bb34 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -83,6 +83,7 @@ CAddrMan addrman; int nMaxConnections = 125; int nWhiteConnections = 0; bool fAddressesInitialized = false; +std::string strSubVersion; vector vNodes; CCriticalSection cs_vNodes; @@ -445,7 +446,7 @@ void CNode::PushVersion() else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, mapMultiArgs.count("-uacomment") ? mapMultiArgs["-uacomment"] : std::vector()), nBestHeight, true); + nLocalHostNonce, strSubVersion, nBestHeight, true); } -- cgit v1.2.3 From 9f68ed6b6d1a9c6436ce37913666165f2b180ee3 Mon Sep 17 00:00:00 2001 From: Veres Lajos Date: Sun, 9 Aug 2015 00:17:27 +0100 Subject: typofixes (found by misspell_fixer) --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e4ead3c92..fb5726a2b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2319,7 +2319,7 @@ void DumpBanlist() { int64_t nStart = GetTimeMillis(); - CNode::SweepBanned(); //clean unused entires (if bantime has expired) + CNode::SweepBanned(); //clean unused entries (if bantime has expired) CBanDB bandb; banmap_t banmap; -- cgit v1.2.3 From 541a1dd9e664ac0b3929abeac42190ac8e88fc21 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Thu, 13 Aug 2015 02:00:10 -0700 Subject: Refactor: AcceptConnection --- src/net.cpp | 120 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 62 insertions(+), 58 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index fb5726a2b..8f1db2695 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -776,6 +776,67 @@ void SocketSendData(CNode *pnode) static list vNodesDisconnected; +static void AcceptConnection(const ListenSocket& hListenSocket) { + struct sockaddr_storage sockaddr; + socklen_t len = sizeof(sockaddr); + SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); + CAddress addr; + int nInbound = 0; + int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS; + + if (hSocket != INVALID_SOCKET) + if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) + LogPrintf("Warning: Unknown socket family\n"); + + bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->fInbound) + nInbound++; + } + + if (hSocket == INVALID_SOCKET) + { + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK) + LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); + } + else if (!IsSelectableSocket(hSocket)) + { + LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString()); + CloseSocket(hSocket); + } + else if (nInbound >= nMaxInbound) + { + LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); + CloseSocket(hSocket); + } + else if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) + { + LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString()); + CloseSocket(hSocket); + } + else if (CNode::IsBanned(addr) && !whitelisted) + { + LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); + CloseSocket(hSocket); + } + else + { + CNode* pnode = new CNode(hSocket, addr, "", true); + pnode->AddRef(); + pnode->fWhitelisted = whitelisted; + + LogPrint("net", "connection from %s accepted\n", addr.ToString()); + + { + LOCK(cs_vNodes); + vNodes.push_back(pnode); + } + } +} + void ThreadSocketHandler() { unsigned int nPrevNodeCount = 0; @@ -933,64 +994,7 @@ void ThreadSocketHandler() { if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv)) { - struct sockaddr_storage sockaddr; - socklen_t len = sizeof(sockaddr); - SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); - CAddress addr; - int nInbound = 0; - int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS; - - if (hSocket != INVALID_SOCKET) - if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) - LogPrintf("Warning: Unknown socket family\n"); - - bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->fInbound) - nInbound++; - } - - if (hSocket == INVALID_SOCKET) - { - int nErr = WSAGetLastError(); - if (nErr != WSAEWOULDBLOCK) - LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); - } - else if (!IsSelectableSocket(hSocket)) - { - LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString()); - CloseSocket(hSocket); - } - else if (nInbound >= nMaxInbound) - { - LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); - CloseSocket(hSocket); - } - else if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) - { - LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString()); - CloseSocket(hSocket); - } - else if (CNode::IsBanned(addr) && !whitelisted) - { - LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); - CloseSocket(hSocket); - } - else - { - CNode* pnode = new CNode(hSocket, addr, "", true); - pnode->AddRef(); - pnode->fWhitelisted = whitelisted; - - LogPrint("net", "connection from %s accepted\n", addr.ToString()); - - { - LOCK(cs_vNodes); - vNodes.push_back(pnode); - } - } + AcceptConnection(hListenSocket); } } -- cgit v1.2.3 From 1ef481761477e26651dc56b4378b146cd5c416db Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Thu, 13 Aug 2015 02:16:46 -0700 Subject: Refactor: Bail early in AcceptConnection --- src/net.cpp | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8f1db2695..6214c754c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -801,39 +801,46 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { int nErr = WSAGetLastError(); if (nErr != WSAEWOULDBLOCK) LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); + return; } - else if (!IsSelectableSocket(hSocket)) + + if (!IsSelectableSocket(hSocket)) { LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString()); CloseSocket(hSocket); + return; } - else if (nInbound >= nMaxInbound) + + if (nInbound >= nMaxInbound) { LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); CloseSocket(hSocket); + return; } - else if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) + + if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) { LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString()); CloseSocket(hSocket); + return; } - else if (CNode::IsBanned(addr) && !whitelisted) + + if (CNode::IsBanned(addr) && !whitelisted) { LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); CloseSocket(hSocket); + return; } - else - { - CNode* pnode = new CNode(hSocket, addr, "", true); - pnode->AddRef(); - pnode->fWhitelisted = whitelisted; - LogPrint("net", "connection from %s accepted\n", addr.ToString()); + CNode* pnode = new CNode(hSocket, addr, "", true); + pnode->AddRef(); + pnode->fWhitelisted = whitelisted; - { - LOCK(cs_vNodes); - vNodes.push_back(pnode); - } + LogPrint("net", "connection from %s accepted\n", addr.ToString()); + + { + LOCK(cs_vNodes); + vNodes.push_back(pnode); } } -- cgit v1.2.3 From ae037b707ce164087790f149c048871c66e14cfd Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Thu, 13 Aug 2015 02:19:17 -0700 Subject: Refactor: Move failure conditions to the top of AcceptConnection --- src/net.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6214c754c..248aedfa1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -811,23 +811,23 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { return; } - if (nInbound >= nMaxInbound) + if (CNode::IsBanned(addr) && !whitelisted) { - LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); + LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); CloseSocket(hSocket); return; } - if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) + if (nInbound >= nMaxInbound) { - LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString()); + LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); CloseSocket(hSocket); return; } - if (CNode::IsBanned(addr) && !whitelisted) + if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) { - LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); + LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString()); CloseSocket(hSocket); return; } -- cgit v1.2.3 From 2c701537c8fc7f4cfb0163ec1f49662120e61eb7 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Thu, 13 Aug 2015 02:58:58 -0700 Subject: AttemptToEvictConnection --- src/net.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 10 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 248aedfa1..0fab0f82a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -776,6 +776,106 @@ void SocketSendData(CNode *pnode) static list vNodesDisconnected; +static bool ReverseCompareNodeMinPingTime(CNode *a, CNode *b) +{ + return a->nMinPingUsecTime > b->nMinPingUsecTime; +} + +static bool ReverseCompareNodeTimeConnected(CNode *a, CNode *b) +{ + return a->nTimeConnected > b->nTimeConnected; +} + +class CompareNetGroupKeyed +{ + std::vector vchSecretKey; +public: + CompareNetGroupKeyed() + { + vchSecretKey.resize(32, 0); + GetRandBytes(vchSecretKey.data(), vchSecretKey.size()); + } + + bool operator()(CNode *a, CNode *b) + { + std::vector vchGroupA, vchGroupB; + CSHA256 hashA, hashB; + std::vector vchA(32), vchB(32); + + vchGroupA = a->addr.GetGroup(); + vchGroupB = b->addr.GetGroup(); + + hashA.Write(begin_ptr(vchGroupA), vchGroupA.size()); + hashB.Write(begin_ptr(vchGroupB), vchGroupB.size()); + + hashA.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); + hashB.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); + + hashA.Finalize(begin_ptr(vchA)); + hashB.Finalize(begin_ptr(vchB)); + + return vchA < vchB; + } +}; + +static bool AttemptToEvictConnection() { + std::vector vEvictionCandidates; + { + LOCK(cs_vNodes); + + BOOST_FOREACH(CNode *node, vNodes) { + if (node->fWhitelisted) + continue; + if (!node->fInbound) + continue; + if (node->fDisconnect) + continue; + if (node->addr.IsLocal()) + continue; + vEvictionCandidates.push_back(node); + } + } + + // Protect connections with certain characteristics + static CompareNetGroupKeyed comparerNetGroupKeyed; + std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed); + vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); + + std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime); + vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); + + std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); + vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(64, static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); + + if (vEvictionCandidates.empty()) + return false; + + // Identify CNetAddr with the most connections + CNetAddr naMostConnections; + unsigned int nMostConnections = 0; + std::map > mapAddrCounts; + BOOST_FOREACH(CNode *node, vEvictionCandidates) { + mapAddrCounts[node->addr].push_back(node); + + if (mapAddrCounts[node->addr].size() > nMostConnections) { + nMostConnections = mapAddrCounts[node->addr].size(); + naMostConnections = node->addr; + } + } + + // Reduce to the CNetAddr with the most connections + vEvictionCandidates = mapAddrCounts[naMostConnections]; + + if (vEvictionCandidates.size() <= 1) + return false; + + // Disconnect the most recent connection from the CNetAddr with the most connections + std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); + vEvictionCandidates[0]->fDisconnect = true; + + return true; +} + static void AcceptConnection(const ListenSocket& hListenSocket) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); @@ -820,16 +920,12 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { if (nInbound >= nMaxInbound) { - LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); - CloseSocket(hSocket); - return; - } - - if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) - { - LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString()); - CloseSocket(hSocket); - return; + if (!AttemptToEvictConnection()) { + // No connection to evict, disconnect the new connection + LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n"); + CloseSocket(hSocket); + return; + } } CNode* pnode = new CNode(hSocket, addr, "", true); -- cgit v1.2.3 From b105ba398b20789eb482e45f26ae1761800b81be Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Thu, 13 Aug 2015 17:22:35 -0700 Subject: Prefer to disconnect peers in favor of whitelisted peers --- src/net.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 0fab0f82a..77dde9944 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -818,7 +818,7 @@ public: } }; -static bool AttemptToEvictConnection() { +static bool AttemptToEvictConnection(bool fPreferNewConnection) { std::vector vEvictionCandidates; { LOCK(cs_vNodes); @@ -866,8 +866,11 @@ static bool AttemptToEvictConnection() { // Reduce to the CNetAddr with the most connections vEvictionCandidates = mapAddrCounts[naMostConnections]; + // Do not disconnect peers who have only 1 evictable connection if (vEvictionCandidates.size() <= 1) - return false; + // unless we prefer the new connection (for whitelisted peers) + if (!fPreferNewConnection) + return false; // Disconnect the most recent connection from the CNetAddr with the most connections std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); @@ -920,7 +923,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { if (nInbound >= nMaxInbound) { - if (!AttemptToEvictConnection()) { + if (!AttemptToEvictConnection(whitelisted)) { // No connection to evict, disconnect the new connection LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n"); CloseSocket(hSocket); -- cgit v1.2.3 From a8f6e45249e815414cc99e7b594a8a7ab7ab9247 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Thu, 13 Aug 2015 17:32:57 -0700 Subject: Remove redundant whiteconnections option --- src/net.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 77dde9944..9cfb9d71d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -81,7 +81,6 @@ uint64_t nLocalHostNonce = 0; static std::vector vhListenSocket; CAddrMan addrman; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; -int nWhiteConnections = 0; bool fAddressesInitialized = false; std::string strSubVersion; -- cgit v1.2.3 From df239374224e6585d5b6ba37a39282d0fc647173 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Thu, 20 Aug 2015 16:47:49 -0700 Subject: Add comments to AttemptToEvictConnection --- src/net.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 9cfb9d71d..d8d2783c4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -836,13 +836,20 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { } // Protect connections with certain characteristics + + // Deterministically select 4 peers to protect by netgroup. + // An attacker cannot predict which netgroups will be protected. static CompareNetGroupKeyed comparerNetGroupKeyed; std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed); vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); + // Protect the 8 nodes with the best ping times. + // 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(vEvictionCandidates.size())), vEvictionCandidates.end()); + // Protect the 64 nodes which have been connected the longest. + // This replicates the existing implicit behavior. std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(64, static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); -- cgit v1.2.3 From 1317cd1928afbae14fedb39c8d23589a32fe2951 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Thu, 20 Aug 2015 17:29:04 -0700 Subject: RAII wrapper for CNode* --- src/net.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index d8d2783c4..709c65243 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -775,12 +775,23 @@ void SocketSendData(CNode *pnode) static list vNodesDisconnected; -static bool ReverseCompareNodeMinPingTime(CNode *a, CNode *b) +class CNodeRef { +public: + CNodeRef(CNode *pnode) : _pnode(pnode) {_pnode->AddRef();} + ~CNodeRef() {_pnode->Release();} + + CNode& operator *() const {return *_pnode;}; + CNode* operator ->() const {return _pnode;}; +private: + CNode *_pnode; +}; + +static bool ReverseCompareNodeMinPingTime(const CNodeRef &a, const CNodeRef &b) { return a->nMinPingUsecTime > b->nMinPingUsecTime; } -static bool ReverseCompareNodeTimeConnected(CNode *a, CNode *b) +static bool ReverseCompareNodeTimeConnected(const CNodeRef &a, const CNodeRef &b) { return a->nTimeConnected > b->nTimeConnected; } @@ -795,7 +806,7 @@ public: GetRandBytes(vchSecretKey.data(), vchSecretKey.size()); } - bool operator()(CNode *a, CNode *b) + bool operator()(const CNodeRef &a, const CNodeRef &b) { std::vector vchGroupA, vchGroupB; CSHA256 hashA, hashB; @@ -818,7 +829,7 @@ public: }; static bool AttemptToEvictConnection(bool fPreferNewConnection) { - std::vector vEvictionCandidates; + std::vector vEvictionCandidates; { LOCK(cs_vNodes); @@ -831,7 +842,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->addr.IsLocal()) continue; - vEvictionCandidates.push_back(node); + vEvictionCandidates.push_back(CNodeRef(node)); } } @@ -859,8 +870,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Identify CNetAddr with the most connections CNetAddr naMostConnections; unsigned int nMostConnections = 0; - std::map > mapAddrCounts; - BOOST_FOREACH(CNode *node, vEvictionCandidates) { + std::map > mapAddrCounts; + BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) { mapAddrCounts[node->addr].push_back(node); if (mapAddrCounts[node->addr].size() > nMostConnections) { -- cgit v1.2.3 From 17f3533c8484f02732fff5cf004d251c0df50eb8 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Fri, 21 Aug 2015 18:42:05 -0700 Subject: Better support for nodes with non-standard nMaxConnections --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 709c65243..4d08f63e3 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -862,7 +862,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Protect the 64 nodes which have been connected the longest. // This replicates the existing implicit behavior. std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); - vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(64, static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); + vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(static_cast(vEvictionCandidates.size() / 2), static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); if (vEvictionCandidates.empty()) return false; -- cgit v1.2.3 From dc81dd02a1d5f47ca45f74577e0696dfba6fa15c Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Sat, 22 Aug 2015 15:15:39 -0700 Subject: Return false early if vEvictionCandidates is empty --- src/net.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4d08f63e3..4f4c7b81c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -846,6 +846,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { } } + if (vEvictionCandidates.empty()) return false; + // Protect connections with certain characteristics // Deterministically select 4 peers to protect by netgroup. @@ -854,18 +856,21 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed); vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); + if (vEvictionCandidates.empty()) return false; + // Protect the 8 nodes with the best ping times. // 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(vEvictionCandidates.size())), vEvictionCandidates.end()); + if (vEvictionCandidates.empty()) return false; + // Protect the 64 nodes which have been connected the longest. // This replicates the existing implicit behavior. std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); - vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(static_cast(vEvictionCandidates.size() / 2), static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); + vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast(vEvictionCandidates.size() / 2), vEvictionCandidates.end()); - if (vEvictionCandidates.empty()) - return false; + if (vEvictionCandidates.empty()) return false; // Identify CNetAddr with the most connections CNetAddr naMostConnections; -- cgit v1.2.3 From 9f3e48e5219a09b5ddfd6883d1f0498910eff4b6 Mon Sep 17 00:00:00 2001 From: Pavel Vasin Date: Sun, 23 Aug 2015 23:53:49 +0300 Subject: add support for miniupnpc api version 14 The value of new arg ttl is set to 2 as it's recommended default. --- src/net.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index fb5726a2b..4c6331f8d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1120,10 +1120,14 @@ void ThreadMapPort() #ifndef UPNPDISCOVER_SUCCESS /* miniupnpc 1.5 */ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0); -#else +#elif MINIUPNPC_API_VERSION < 14 /* miniupnpc 1.6 */ int error = 0; devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); +#else + /* miniupnpc 1.9.20150730 */ + int error = 0; + devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error); #endif struct UPNPUrls urls; -- cgit v1.2.3 From a19338723d662e6fc0571833d2b9983e1914f282 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 20 Aug 2015 15:50:13 -0400 Subject: net: Set SO_REUSEADDR for Windows too When running the rpc tests in Wine, nodes often fail to listen on localhost due to a stale socket from a previous run. This aligns the behavior with other platforms. --- src/net.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index fb5726a2b..8fda5140c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1625,8 +1625,10 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)); #endif // Allow binding if the port is still in TIME_WAIT state after - // the program was closed and restarted. Not an issue on windows! + // the program was closed and restarted. setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); +#else + setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int)); #endif // Set to non-blocking, incoming connections will also inherit this -- cgit v1.2.3 From 69ee1aab00b9189865dfca6fb5c33c61a3c3ea67 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Tue, 25 Aug 2015 15:33:29 -0700 Subject: CNodeRef copy constructor and assignment operator --- src/net.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4f4c7b81c..cb5a24f0a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -782,6 +782,22 @@ public: CNode& operator *() const {return *_pnode;}; CNode* operator ->() const {return _pnode;}; + + CNodeRef& operator =(const CNodeRef& other) + { + if (this != &other) { + _pnode->Release(); + _pnode = other._pnode; + _pnode->AddRef(); + } + return *this; + } + + CNodeRef(const CNodeRef& other): + _pnode(other._pnode) + { + _pnode->AddRef(); + } private: CNode *_pnode; }; -- cgit v1.2.3 From fed30940ef22f242b9dada2dc4f7c5348faf8922 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Tue, 25 Aug 2015 16:30:02 -0700 Subject: Acquire cs_vNodes before changing refrence counts --- src/net.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cb5a24f0a..e1b0e83e9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -777,8 +777,15 @@ static list vNodesDisconnected; class CNodeRef { public: - CNodeRef(CNode *pnode) : _pnode(pnode) {_pnode->AddRef();} - ~CNodeRef() {_pnode->Release();} + CNodeRef(CNode *pnode) : _pnode(pnode) { + LOCK(cs_vNodes); + _pnode->AddRef(); + } + + ~CNodeRef() { + LOCK(cs_vNodes); + _pnode->Release(); + } CNode& operator *() const {return *_pnode;}; CNode* operator ->() const {return _pnode;}; @@ -786,6 +793,8 @@ public: CNodeRef& operator =(const CNodeRef& other) { if (this != &other) { + LOCK(cs_vNodes); + _pnode->Release(); _pnode = other._pnode; _pnode->AddRef(); @@ -796,6 +805,7 @@ public: CNodeRef(const CNodeRef& other): _pnode(other._pnode) { + LOCK(cs_vNodes); _pnode->AddRef(); } private: -- cgit v1.2.3 From 000c18aaceeebdcaf65508fcdc3d00397971dcae Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Tue, 25 Aug 2015 16:31:13 -0700 Subject: Fix comment --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e1b0e83e9..d266b2f21 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -891,7 +891,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { if (vEvictionCandidates.empty()) return false; - // Protect the 64 nodes which have been connected the longest. + // Protect the half of the remaining nodes which have been connected the longest. // This replicates the existing implicit behavior. std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast(vEvictionCandidates.size() / 2), vEvictionCandidates.end()); -- cgit v1.2.3 From 9bebf60698c34502319d6a8218f2ee0c4fa72ef6 Mon Sep 17 00:00:00 2001 From: J Ross Nicoll Date: Sat, 29 Aug 2015 17:40:13 +0100 Subject: Make sure LogPrint strings are line-terminated --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8fda5140c..b61f7325a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -659,7 +659,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) return false; if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) { - LogPrint("net", "Oversized message from peer=%i, disconnecting", GetId()); + LogPrint("net", "Oversized message from peer=%i, disconnecting\n", GetId()); return false; } -- cgit v1.2.3 From 027de94e1fba5484aed2393afd89edbaaffdb0eb Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Tue, 25 Aug 2015 17:06:15 -0700 Subject: Use network group instead of CNetAddr in final pass to select node to disconnect --- src/net.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index d266b2f21..9264d6865 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -898,29 +898,29 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { if (vEvictionCandidates.empty()) return false; - // Identify CNetAddr with the most connections - CNetAddr naMostConnections; + // Identify the network group with the most connections + std::vector naMostConnections; unsigned int nMostConnections = 0; - std::map > mapAddrCounts; + std::map, std::vector > mapAddrCounts; BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) { - mapAddrCounts[node->addr].push_back(node); + mapAddrCounts[node->addr.GetGroup()].push_back(node); - if (mapAddrCounts[node->addr].size() > nMostConnections) { - nMostConnections = mapAddrCounts[node->addr].size(); - naMostConnections = node->addr; + if (mapAddrCounts[node->addr.GetGroup()].size() > nMostConnections) { + nMostConnections = mapAddrCounts[node->addr.GetGroup()].size(); + naMostConnections = node->addr.GetGroup(); } } - // Reduce to the CNetAddr with the most connections + // Reduce to the network group with the most connections vEvictionCandidates = mapAddrCounts[naMostConnections]; - // Do not disconnect peers who have only 1 evictable connection + // Do not disconnect peers if there is only 1 connection from their network group if (vEvictionCandidates.size() <= 1) // unless we prefer the new connection (for whitelisted peers) if (!fPreferNewConnection) return false; - // Disconnect the most recent connection from the CNetAddr with the most connections + // Disconnect the most recent connection from the network group with the most connections std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); vEvictionCandidates[0]->fDisconnect = true; -- cgit v1.2.3 From a6eb4ba38bdb2f12089faf7469b54ea2a5146516 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 3 Sep 2015 13:06:13 -0700 Subject: Report minimum ping time in getpeerinfo --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4909d5fd4..526e2049a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -628,6 +628,7 @@ void CNode::copyStats(CNodeStats &stats) // Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :) stats.dPingTime = (((double)nPingUsecTime) / 1e6); + stats.dPingMin = (((double)nMinPingUsecTime) / 1e6); stats.dPingWait = (((double)nPingUsecWait) / 1e6); // Leave string empty if addrLocal invalid (not filled in yet) -- cgit v1.2.3 From 93ff1b9041a8282cd0785d22edbc1fd67b29533b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 4 Sep 2015 15:43:21 +0200 Subject: net: correctly initialize nMinPingUsecTime `nMinPingUsecTime` was left uninitialized in CNode. The correct initialization for a minimum-until-now is int64_t's max value, so initialize it to that. Thanks @MarcoFalke for noticing. --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 526e2049a..87c4f0af0 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2261,6 +2261,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nPingUsecStart = 0; nPingUsecTime = 0; fPingQueued = false; + nMinPingUsecTime = std::numeric_limits::max(); { LOCK(cs_nLastNodeId); -- cgit v1.2.3 From 57c77fe4d318a156d98606ee74f0064b22c31631 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 3 Jul 2015 09:26:51 +0200 Subject: banlist: update set dirty to be more fine grained - move the SetBannedSetDirty(false) call from DumpData() into DumpBanlist() - ensure we only set false, if the write succeeded --- src/net.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 87c4f0af0..b13177fe2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1455,10 +1455,7 @@ void DumpData() DumpAddresses(); if (CNode::BannedSetIsDirty()) - { DumpBanlist(); - CNode::SetBannedSetDirty(false); - } } void static ProcessOneShot() @@ -2484,14 +2481,14 @@ bool CBanDB::Read(banmap_t& banSet) void DumpBanlist() { int64_t nStart = GetTimeMillis(); - - CNode::SweepBanned(); //clean unused entries (if bantime has expired) + CNode::SweepBanned(); // clean unused entries (if bantime has expired) CBanDB bandb; banmap_t banmap; CNode::GetBanned(banmap); - bandb.Write(banmap); + if (bandb.Write(banmap)) + CNode::SetBannedSetDirty(false); LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", - banmap.size(), GetTimeMillis() - nStart); + banmap.size(), GetTimeMillis() - nStart); } -- cgit v1.2.3 From ce479aaadaab296f0d06808fe230c4b13523cc28 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 3 Jul 2015 09:44:49 +0200 Subject: banlist: better handling of banlist in StartNode() - only start working on/with banlist data, if reading in the banlist from disk didn't fail - as CNode::setBannedIsDirty is false (default) when reading fails, we don't need to explicitly set it to false to prevent writing banlist.dat in that case either --- src/net.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b13177fe2..6d39ccecd 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1909,15 +1909,16 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) //try to read stored banlist CBanDB bandb; banmap_t banmap; - if (!bandb.Read(banmap)) + if (bandb.Read(banmap)) { + CNode::SetBanned(banmap); // thread save setter + CNode::SetBannedSetDirty(false); // no need to write down, just read data + CNode::SweepBanned(); // sweep out unused entries + + LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - nStart); + } else LogPrintf("Invalid or missing banlist.dat; recreating\n"); - CNode::SetBanned(banmap); //thread save setter - CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data - CNode::SweepBanned(); //sweap out unused entries - - LogPrintf("Loaded %i addresses from peers.dat %dms\n", - addrman.size(), GetTimeMillis() - nStart); fAddressesInitialized = true; if (semOutbound == NULL) { -- cgit v1.2.3 From 2977c243efc9f122328de1bcfe12364498e0e2b6 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 3 Jul 2015 09:46:17 +0200 Subject: banlist: add more banlist infos to log / add GUI signal - to match the peers.dat handling also supply a debug.log entry for how many entries were loaded from banlist.dat and how long it took - add a GUI init message for loading the banlist (same as with peers.dat) - move the same message for peers.dat upwards in the code, to be able to reuse the timing variable nStart and also just log, if our read from peers.dat didn't fail --- src/net.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6d39ccecd..88a8edebc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -35,7 +35,7 @@ #include #include -// Dump addresses to peers.dat every 15 minutes (900s) +// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) @@ -555,11 +555,13 @@ void CNode::SweepBanned() banmap_t::iterator it = setBanned.begin(); while(it != setBanned.end()) { + CSubNet subNet = (*it).first; CBanEntry banEntry = (*it).second; if(now > banEntry.nBanUntil) { setBanned.erase(it++); setBannedIsDirty = true; + LogPrint("net", "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString()); } else ++it; @@ -1898,15 +1900,19 @@ void static Discover(boost::thread_group& threadGroup) void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) { uiInterface.InitMessage(_("Loading addresses...")); - // Load addresses for peers.dat + // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); { CAddrDB adb; - if (!adb.Read(addrman)) + if (adb.Read(addrman)) + LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); + else LogPrintf("Invalid or missing peers.dat; recreating\n"); } - //try to read stored banlist + uiInterface.InitMessage(_("Loading banlist...")); + // Load addresses from banlist.dat + nStart = GetTimeMillis(); CBanDB bandb; banmap_t banmap; if (bandb.Read(banmap)) { @@ -1923,7 +1929,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); + int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); semOutbound = new CSemaphore(nMaxOutbound); } -- cgit v1.2.3 From e8600c924d58f3ef0450fc269998452e5b17aecb Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 3 Jul 2015 10:46:08 +0200 Subject: banlist (bugfix): allow CNode::SweepBanned() to run on interval - allows CNode::SweepBanned() to run, even if !CNode::BannedSetIsDirty(), because if nBanUntil is over we want the ban to be disabled for these nodes --- src/net.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 88a8edebc..15ddaac63 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1455,9 +1455,7 @@ void DumpAddresses() void DumpData() { DumpAddresses(); - - if (CNode::BannedSetIsDirty()) - DumpBanlist(); + DumpBanlist(); } void static ProcessOneShot() @@ -2474,22 +2472,26 @@ bool CBanDB::Read(banmap_t& banSet) // ... verify the network matches ours if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) return error("%s: Invalid network magic number", __func__); - + // de-serialize address data into one CAddrMan object ssBanlist >> banSet; } catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } - + return true; } void DumpBanlist() { - int64_t nStart = GetTimeMillis(); CNode::SweepBanned(); // clean unused entries (if bantime has expired) + if (!CNode::BannedSetIsDirty()) + return; + + int64_t nStart = GetTimeMillis(); + CBanDB bandb; banmap_t banmap; CNode::GetBanned(banmap); -- cgit v1.2.3 From a4e28b3d1e5c95eb0c87f144851cd65048c3e0bc Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Wed, 21 Oct 2015 23:52:29 +0000 Subject: Set TCP_NODELAY on P2P sockets. Nagle appears to be a significant contributor to latency now that the static sleeps are gone. Most of our messages are relatively large compared to IP + TCP so I do not expect this to create enormous overhead. This may also reduce traffic burstyness somewhat. --- src/net.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 87c4f0af0..58b946f4a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -963,6 +963,15 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { return; } + // According to the internet TCP_NODELAY is not carried into accepted sockets + // on all platforms. Set it again here just to be sure. + int set = 1; +#ifdef WIN32 + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int)); +#else + setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int)); +#endif + if (CNode::IsBanned(addr) && !whitelisted) { LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); @@ -1790,8 +1799,11 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste // Allow binding if the port is still in TIME_WAIT state after // the program was closed and restarted. setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); + // Disable Nagle's algorithm + setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int)); #else setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int)); + setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int)); #endif // Set to non-blocking, incoming connections will also inherit this -- cgit v1.2.3 From 872fee3fccc8b33b9af0a401b5f85ac5504b57eb Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Wed, 2 Sep 2015 17:03:27 +0200 Subject: Introduce -maxuploadtarget * -maxuploadtarget can be set in MiB * if - ( time-left-in-24h-cycle / 600 * MAX_BLOCK_SIZE ) has reach, stop serve blocks older than one week and filtered blocks * no action if limit has reached, no guarantee that the target will not be surpassed * add outbound limit informations to rpc getnettotals --- src/net.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 58b946f4a..e18e8d0e2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -12,6 +12,7 @@ #include "addrman.h" #include "chainparams.h" #include "clientversion.h" +#include "consensus/consensus.h" #include "crypto/common.h" #include "hash.h" #include "primitives/transaction.h" @@ -326,6 +327,11 @@ uint64_t CNode::nTotalBytesSent = 0; CCriticalSection CNode::cs_totalBytesRecv; CCriticalSection CNode::cs_totalBytesSent; +uint64_t CNode::nMaxOutboundLimit = 0; +uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0; +uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day +uint64_t CNode::nMaxOutboundCycleStartTime = 0; + CNode* FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); @@ -2083,6 +2089,94 @@ void CNode::RecordBytesSent(uint64_t bytes) { LOCK(cs_totalBytesSent); nTotalBytesSent += bytes; + + uint64_t now = GetTime(); + if (nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now) + { + // timeframe expired, reset cycle + nMaxOutboundCycleStartTime = now; + nMaxOutboundTotalBytesSentInCycle = 0; + } + + // TODO, exclude whitebind peers + nMaxOutboundTotalBytesSentInCycle += bytes; +} + +void CNode::SetMaxOutboundTarget(uint64_t limit) +{ + LOCK(cs_totalBytesSent); + uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SIZE; + nMaxOutboundLimit = limit; + + if (limit < recommendedMinimum) + LogPrintf("Max outbound target is very small (%s) and will be overshot. Recommended minimum is %s\n.", nMaxOutboundLimit, recommendedMinimum); +} + +uint64_t CNode::GetMaxOutboundTarget() +{ + LOCK(cs_totalBytesSent); + return nMaxOutboundLimit; +} + +uint64_t CNode::GetMaxOutboundTimeframe() +{ + LOCK(cs_totalBytesSent); + return nMaxOutboundTimeframe; +} + +uint64_t CNode::GetMaxOutboundTimeLeftInCycle() +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return 0; + + if (nMaxOutboundCycleStartTime == 0) + return nMaxOutboundTimeframe; + + uint64_t cycleEndTime = nMaxOutboundCycleStartTime + nMaxOutboundTimeframe; + uint64_t now = GetTime(); + return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime(); +} + +void CNode::SetMaxOutboundTimeframe(uint64_t timeframe) +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundTimeframe != timeframe) + { + // reset measure-cycle in case of changing + // the timeframe + nMaxOutboundCycleStartTime = GetTime(); + } + nMaxOutboundTimeframe = timeframe; +} + +bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return false; + + if (historicalBlockServingLimit) + { + // keep a large enought buffer to at least relay each block once + uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle(); + uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SIZE; + if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer) + return true; + } + else if (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) + return true; + + return false; +} + +uint64_t CNode::GetOutboundTargetBytesLeft() +{ + LOCK(cs_totalBytesSent); + if (nMaxOutboundLimit == 0) + return 0; + + return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle; } uint64_t CNode::GetTotalBytesRecv() -- cgit v1.2.3 From 8f4e67f152a9625a1c66c20de00679286b2c187c Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 25 Aug 2015 20:12:08 +0200 Subject: net: Automatically create hidden service, listen on Tor Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket API, to create and destroy 'ephemeral' hidden services programmatically. https://stem.torproject.org/api/control.html#stem.control.Controller.create_ephemeral_hidden_service This means that if Tor is running (and proper authorization is available), bitcoin automatically creates a hidden service to listen on, without user manual configuration. This will positively affect the number of available .onion nodes. - When the node is started, connect to Tor through control socket - Send `ADD_ONION` command - First time: - Make it create a hidden service key - Save the key in the data directory for later usage - Make it redirect port 8333 to the local port 8333 (or whatever port we're listening on). - Keep control socket connection open for as long node is running. The hidden service will (by default) automatically go away when the connection is closed. --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e18e8d0e2..9d01f2557 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -216,6 +216,7 @@ void AdvertizeLocal(CNode *pnode) } if (addrLocal.IsRoutable()) { + LogPrintf("AdvertizeLocal: advertizing address %s\n", addrLocal.ToString()); pnode->PushAddress(addrLocal); } } -- cgit v1.2.3 From 09c1ae1c01076f64fe0654f371200668306e5e18 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 8 Sep 2015 17:48:45 +0200 Subject: torcontrol improvements and fixes - Force AUTHCOOKIE size to be 32 bytes: This provides protection against an attack where a process pretends to be Tor and uses the cookie authentication method to nab arbitrary files such as the wallet - torcontrol logging - fix cookie auth - add HASHEDPASSWORD auth, fix fd leak when fwrite() fails - better error reporting when cookie file is not ok - better init/shutdown flow - stop advertizing service when disconnected from tor control port - COOKIE->SAFECOOKIE auth --- src/net.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 9d01f2557..ada4a1bb6 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -263,6 +263,14 @@ bool AddLocal(const CNetAddr &addr, int nScore) return AddLocal(CService(addr, GetListenPort()), nScore); } +bool RemoveLocal(const CService& addr) +{ + LOCK(cs_mapLocalHost); + LogPrintf("RemoveLocal(%s)\n", addr.ToString()); + mapLocalHost.erase(addr); + return true; +} + /** Make a particular network entirely off-limits (no automatic connects to it) */ void SetLimited(enum Network net, bool fLimited) { -- cgit v1.2.3 From b27e81f115e67bffee2c35c1c96082879160f6e1 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 6 Nov 2015 00:05:06 +0100 Subject: [net] Cleanup maxuploadtarget * log: nMaxOutboundLimit is in bytes * log: Hide misleading -maxuploadtarget=0 warning * qa : Minor cleanup to maxuploadtarget rpc tests * net: Use DEFAULT_MAX_UPLOAD_TARGET = 0 --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index ada4a1bb6..1ea50b249 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2117,8 +2117,8 @@ void CNode::SetMaxOutboundTarget(uint64_t limit) uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SIZE; nMaxOutboundLimit = limit; - if (limit < recommendedMinimum) - LogPrintf("Max outbound target is very small (%s) and will be overshot. Recommended minimum is %s\n.", nMaxOutboundLimit, recommendedMinimum); + if (limit > 0 && limit < recommendedMinimum) + LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum); } uint64_t CNode::GetMaxOutboundTarget() -- cgit v1.2.3 From 4044f07d1c5eacb0ec732f1232489aa77fb7bb3b Mon Sep 17 00:00:00 2001 From: Patick Strateman Date: Sat, 14 Nov 2015 04:44:15 -0800 Subject: Add blocksonly mode --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 1ea50b249..a62e875f8 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -460,7 +460,7 @@ void CNode::PushVersion() else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nBestHeight, true); + nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", false)); } -- cgit v1.2.3 From 71a2683f4b526b17adf317733b0aa18ffacecfdc Mon Sep 17 00:00:00 2001 From: Patick Strateman Date: Sat, 14 Nov 2015 05:10:59 -0800 Subject: Use DEFAULT_BLOCKSONLY and DEFAULT_WHITELISTALWAYSRELAY constants --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a62e875f8..000eefc85 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -460,7 +460,7 @@ void CNode::PushVersion() else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", false)); + nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)); } -- cgit v1.2.3 From 08843ed99843078acb10eecda2045d5f0f1c2b4f Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Fri, 20 Nov 2015 18:51:44 -0500 Subject: Add relaytxes status to getpeerinfo --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 000eefc85..cff4c5450 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -617,6 +617,7 @@ void CNode::copyStats(CNodeStats &stats) { stats.nodeid = this->GetId(); X(nServices); + X(fRelayTxes); X(nLastSend); X(nLastRecv); X(nTimeConnected); -- cgit v1.2.3 From 5029698186445bf3cd69d0e720f019c472661bff Mon Sep 17 00:00:00 2001 From: kazcw Date: Wed, 16 Jul 2014 14:31:41 -0700 Subject: prevent peer flooding request queue for an inv mapAlreadyAskedFor does not keep track of which peer has a request queued for a particular tx. As a result, a peer can blind a node to a tx indefinitely by sending many invs for the same tx, and then never replying to getdatas for it. Each inv received will be placed 2 minutes farther back in mapAlreadyAskedFor, so a short message containing 10 invs would render that tx unavailable for 20 minutes. This is fixed by disallowing a peer from having more than one entry for a particular inv in mapAlreadyAskedFor at a time. --- src/net.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cff4c5450..04119e9dd 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2410,6 +2410,10 @@ void CNode::AskFor(const CInv& inv) { if (mapAskFor.size() > MAPASKFOR_MAX_SZ) return; + // a peer may not occupy multiple positions in an inv's request queue + if (!setAskFor.insert(inv.hash).second) + return; + // We're using mapAskFor as a priority queue, // the key is the earliest time the request can be sent int64_t nRequestTime; -- cgit v1.2.3 From ebb25f4c23adbcb55796c402bafd6064a136f16f Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 23 Nov 2015 01:54:23 +0000 Subject: Limit setAskFor and retire requested entries only when a getdata returns. The setAskFor duplicate elimination was too eager and removed entries when we still had no getdata response, allowing the peer to keep INVing and not responding. --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 04119e9dd..a8b6ca9c5 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2408,9 +2408,9 @@ CNode::~CNode() void CNode::AskFor(const CInv& inv) { - if (mapAskFor.size() > MAPASKFOR_MAX_SZ) + if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ) return; - // a peer may not occupy multiple positions in an inv's request queue + // a peer may not have multiple non-responded queue positions for a single inv item if (!setAskFor.insert(inv.hash).second) return; -- cgit v1.2.3 From b966aa836a3bc5bfa1314248258308f0026d41bb Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 27 Jun 2015 19:21:41 +0000 Subject: Constrain constant values to a single location in code --- src/net.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cff4c5450..abc7cbb8f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -521,12 +521,11 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti banEntry.banReason = banReason; if (bantimeoffset <= 0) { - bantimeoffset = GetArg("-bantime", 60*60*24); // Default 24-hour ban + bantimeoffset = GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME); sinceUnixEpoch = false; } banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; - LOCK(cs_setBanned); if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) setBanned[subNet] = banEntry; @@ -1414,7 +1413,7 @@ void ThreadDNSAddressSeed() { // goal: only query DNS seeds if address need is acute if ((addrman.size() > 0) && - (!GetBoolArg("-forcednsseed", false))) { + (!GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) { MilliSleep(11 * 1000); LOCK(cs_vNodes); @@ -2337,8 +2336,8 @@ bool CAddrDB::Read(CAddrMan& addr) return true; } -unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } -unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } +unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); } +unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); } CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), -- cgit v1.2.3 From ec73ef37eccfeda76de55c4ff93ea54d4e69e1ec Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Thu, 26 Nov 2015 05:25:30 +0000 Subject: Replace setInventoryKnown with a rolling bloom filter. Mruset setInventoryKnown was reduced to a remarkably small 1000 entries as a side effect of sendbuffer size reductions in 2012. This removes setInventoryKnown filtering from merkleBlock responses because false positives there are especially unattractive and also because I'm not sure if there aren't race conditions around the relay pool that would cause some transactions there to be suppressed. (Also, ProcessGetData was accessing setInventoryKnown without taking the required lock.) --- src/net.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index abc7cbb8f..fc8fa30ee 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2342,7 +2342,7 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addrKnown(5000, 0.001), - setInventoryKnown(SendBufferSize() / 1000) + setInventoryKnown(50000, 0.000001) { nServices = 0; hSocket = hSocketIn; @@ -2369,6 +2369,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nSendOffset = 0; hashContinue = uint256(); nStartingHeight = -1; + setInventoryKnown.reset(); fGetAddr = false; fRelayTxes = false; pfilter = new CBloomFilter(); -- cgit v1.2.3 From 6b849350ab074a7ccb80ecbef387f59e1271ded6 Mon Sep 17 00:00:00 2001 From: Patick Strateman Date: Sun, 29 Nov 2015 01:52:51 -0800 Subject: Rename setInventoryKnown filterInventoryKnown --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index fc8fa30ee..59c0faac2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2342,7 +2342,7 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addrKnown(5000, 0.001), - setInventoryKnown(50000, 0.000001) + filterInventoryKnown(50000, 0.000001) { nServices = 0; hSocket = hSocketIn; @@ -2369,7 +2369,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nSendOffset = 0; hashContinue = uint256(); nStartingHeight = -1; - setInventoryKnown.reset(); + filterInventoryKnown.reset(); fGetAddr = false; fRelayTxes = false; pfilter = new CBloomFilter(); -- cgit v1.2.3 From ca188c629e90fd90b533f43d769348d6a42d24b9 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 25 Aug 2015 16:30:31 +0200 Subject: log bytes recv/sent per command --- src/net.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a8aa97fee..649c6134d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -67,6 +67,15 @@ namespace { }; } +//immutable thread safe array of allowed commands for logging inbound traffic +const static std::string logAllowIncomingMsgCmds[] = { + "version", "addr", "inv", "getdata", "merkleblock", + "getblocks", "getheaders", "tx", "headers", "block", + "getaddr", "mempool", "ping", "pong", "alert", "notfound", + "filterload", "filteradd", "filterclear", "reject"}; + +const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; + // // Global state variables // @@ -627,7 +636,9 @@ void CNode::copyStats(CNodeStats &stats) X(fInbound); X(nStartingHeight); X(nSendBytes); + X(mapSendBytesPerMsgCmd); X(nRecvBytes); + X(mapRecvBytesPerMsgCmd); X(fWhitelisted); // It is common for nodes with good ping times to suddenly become lagged, @@ -682,6 +693,15 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) nBytes -= handled; if (msg.complete()) { + + //store received bytes per message command + //to prevent a memory DOS, only allow valid commands + mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand); + if (i == mapRecvBytesPerMsgCmd.end()) + i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER); + assert(i != mapRecvBytesPerMsgCmd.end()); + i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE; + msg.nTime = GetTimeMicros(); messageHandlerCondition.notify_one(); } @@ -2378,6 +2398,9 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nPingUsecTime = 0; fPingQueued = false; nMinPingUsecTime = std::numeric_limits::max(); + for (unsigned int i = 0; i < sizeof(logAllowIncomingMsgCmds)/sizeof(logAllowIncomingMsgCmds[0]); i++) + mapRecvBytesPerMsgCmd[logAllowIncomingMsgCmds[i]] = 0; + mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; { LOCK(cs_nLastNodeId); @@ -2457,7 +2480,7 @@ void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend) LogPrint("net", "(aborted)\n"); } -void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) +void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) { // The -*messagestest options are intentionally not documented in the help message, // since they are only used during development to debug the networking code and are @@ -2480,6 +2503,9 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); + //log total amount of bytes per command + mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE; + // Set the checksum uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); unsigned int nChecksum = 0; -- cgit v1.2.3 From e3bc5e0e927af14bd34cc30cfdf11cacbb346262 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 7 Dec 2015 15:15:12 +0100 Subject: net: Account for `sendheaders` `verack` messages Looks like these were forgotten in #6589. --- src/net.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 649c6134d..159d44cba 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -72,7 +72,8 @@ const static std::string logAllowIncomingMsgCmds[] = { "version", "addr", "inv", "getdata", "merkleblock", "getblocks", "getheaders", "tx", "headers", "block", "getaddr", "mempool", "ping", "pong", "alert", "notfound", - "filterload", "filteradd", "filterclear", "reject"}; + "filterload", "filteradd", "filterclear", "reject", + "sendheaders", "verack"}; const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; -- cgit v1.2.3 From 9bbe71b641e2fc985daf127988a14a67c99da50a Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 7 Dec 2015 15:31:32 +0100 Subject: net: Add and document network messages in protocol.h - Avoids string typos (by making the compiler check) - Makes it easier to grep for handling/generation of a certain message type - Refer directly to documentation by following the symbol in IDE - Move list of valid message types to protocol.cpp: protocol.cpp is a more appropriate place for this, and having the array there makes it easier to keep things consistent. --- src/net.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 159d44cba..c5e7ece79 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -67,14 +67,6 @@ namespace { }; } -//immutable thread safe array of allowed commands for logging inbound traffic -const static std::string logAllowIncomingMsgCmds[] = { - "version", "addr", "inv", "getdata", "merkleblock", - "getblocks", "getheaders", "tx", "headers", "block", - "getaddr", "mempool", "ping", "pong", "alert", "notfound", - "filterload", "filteradd", "filterclear", "reject", - "sendheaders", "verack"}; - const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; // @@ -469,7 +461,7 @@ void CNode::PushVersion() LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); - PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, + PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)); } @@ -2399,8 +2391,8 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nPingUsecTime = 0; fPingQueued = false; nMinPingUsecTime = std::numeric_limits::max(); - for (unsigned int i = 0; i < sizeof(logAllowIncomingMsgCmds)/sizeof(logAllowIncomingMsgCmds[0]); i++) - mapRecvBytesPerMsgCmd[logAllowIncomingMsgCmds[i]] = 0; + BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) + mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; { -- cgit v1.2.3 From 5400ef6bcb9d243b2b21697775aa6491115420f3 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 8 Apr 2015 11:20:00 -0700 Subject: Replace trickle nodes with per-node/message Poisson delays We used to have a trickle node, a node which was chosen in each iteration of the send loop that was privileged and allowed to send out queued up non-time critical messages. Since the removal of the fixed sleeps in the network code, this resulted in fast and attackable treatment of such broadcasts. This pull request changes the 3 remaining trickle use cases by random delays: * Local address broadcast (while also removing the the wiping of the seen filter) * Address relay * Inv relay (for transactions; blocks are always relayed immediately) The code is based on older commits by Patrick Strateman. --- src/net.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index c5e7ece79..e0d96a2dc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -36,6 +36,8 @@ #include #include +#include + // Dump addresses to peers.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 @@ -1733,11 +1735,6 @@ void ThreadMessageHandler() } } - // Poll the connected nodes for messages - CNode* pnodeTrickle = NULL; - if (!vNodesCopy.empty()) - pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())]; - bool fSleep = true; BOOST_FOREACH(CNode* pnode, vNodesCopy) @@ -1768,7 +1765,7 @@ void ThreadMessageHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) - g_signals.SendMessages(pnode, pnode == pnodeTrickle || pnode->fWhitelisted); + g_signals.SendMessages(pnode); } boost::this_thread::interruption_point(); } @@ -2384,6 +2381,9 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nStartingHeight = -1; filterInventoryKnown.reset(); fGetAddr = false; + nNextLocalAddrSend = 0; + nNextAddrSend = 0; + nNextInvSend = 0; fRelayTxes = false; pfilter = new CBloomFilter(); nPingNonceSent = 0; @@ -2634,3 +2634,7 @@ void DumpBanlist() LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); } + +int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { + return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); +} -- cgit v1.2.3 From fa24439ff3d8ab5b9efaf66ef4dae6713b88cb35 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 13 Dec 2015 17:58:29 +0100 Subject: Bump copyright headers to 2015 --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e5659efc0..48a181dee 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -- cgit v1.2.3 From d5f46832de900cee0801ca40bba743c9564cccb8 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 9 Dec 2015 10:53:12 +0000 Subject: Unify package name to as few places as possible without major changes --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cff4c5450..2b804b0b4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1849,7 +1849,7 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste { int nErr = WSAGetLastError(); if (nErr == WSAEADDRINUSE) - strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString()); + strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), _(PACKAGE_NAME)); else strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr)); LogPrintf("%s\n", strError); -- cgit v1.2.3 From a5a0831458d8290c1e7591cf32a529669b613d86 Mon Sep 17 00:00:00 2001 From: 21E14 <21xe14@gmail.com> Date: Tue, 29 Dec 2015 22:42:27 -0500 Subject: Double semicolon cleanup. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e0d96a2dc..2ad20ac22 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1370,7 +1370,7 @@ void ThreadMapPort() LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r)); else - LogPrintf("UPnP Port Mapping successful.\n");; + LogPrintf("UPnP Port Mapping successful.\n"); MilliSleep(20*60*1000); // Refresh every 20 minutes } -- cgit v1.2.3 From 9d263bd17c2bdd5ba9e31bd5fb110c332eb80691 Mon Sep 17 00:00:00 2001 From: Chris Wheeler Date: Sun, 17 Jan 2016 11:03:56 +0000 Subject: Typo fixes in comments --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 84582484e..db8f97abc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2177,7 +2177,7 @@ bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) if (historicalBlockServingLimit) { - // keep a large enought buffer to at least relay each block once + // keep a large enough buffer to at least relay each block once uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle(); uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SIZE; if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer) -- cgit v1.2.3 From 1e9613ac090ee82f52e1d02a622358b2a1085249 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Thu, 28 Jan 2016 22:44:14 +0000 Subject: Do not absolutely protect local peers from eviction. With automatic tor HS support in place we should probably not be providing absolute protection for local peers, since HS inbound could be used to attack pretty easily. Instead, this counts on the latency metric inside AttemptToEvictConnection to privilege actually local peers. (cherry picked from commit 46dbcd4833115401fecbb052365b4c7725874414) --- src/net.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 48e9e1015..84c5644cc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -899,8 +899,6 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - if (node->addr.IsLocal()) - continue; vEvictionCandidates.push_back(CNodeRef(node)); } } -- cgit v1.2.3 From 1e05727072a58d3538dc654c5a3de83ed58874b8 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 23 Nov 2015 03:48:54 +0000 Subject: Decide eviction group ties based on time. This corrects a bug the case of tying group size where the code may fail to select the group with the newest member. Since newest time is the final selection criteria, failing to break ties on it on the step before can undermine the final selection. Tied netgroups are very common. (cherry picked from commit 8e09f914f8ec66301257358b250e9a61befadd95) --- src/net.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 84c5644cc..14e22f6cb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -929,15 +929,20 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { if (vEvictionCandidates.empty()) return false; - // Identify the network group with the most connections + // Identify the network group with the most connections and youngest member. + // (vEvictionCandidates is already sorted by reverse connect time) std::vector naMostConnections; unsigned int nMostConnections = 0; + int64_t nMostConnectionsTime = 0; std::map, std::vector > mapAddrCounts; BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) { mapAddrCounts[node->addr.GetGroup()].push_back(node); + int64_t grouptime = mapAddrCounts[node->addr.GetGroup()][0]->nTimeConnected; + size_t groupsize = mapAddrCounts[node->addr.GetGroup()].size(); - if (mapAddrCounts[node->addr.GetGroup()].size() > nMostConnections) { - nMostConnections = mapAddrCounts[node->addr.GetGroup()].size(); + if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { + nMostConnections = groupsize; + nMostConnectionsTime = grouptime; naMostConnections = node->addr.GetGroup(); } } @@ -945,14 +950,13 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Reduce to the network group with the most connections vEvictionCandidates = mapAddrCounts[naMostConnections]; - // Do not disconnect peers if there is only 1 connection from their network group + // Do not disconnect peers if there is only one unprotected connection from their network group. if (vEvictionCandidates.size() <= 1) // unless we prefer the new connection (for whitelisted peers) if (!fPreferNewConnection) return false; - // Disconnect the most recent connection from the network group with the most connections - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); + // Disconnect from the network group with the most connections vEvictionCandidates[0]->fDisconnect = true; return true; -- cgit v1.2.3 From c77c6625f3fc88e461a9ec11672edb6a9d4cfd98 Mon Sep 17 00:00:00 2001 From: kirkalx Date: Tue, 2 Feb 2016 22:45:11 +1300 Subject: peers.dat, banlist.dat recreated when missing --- src/net.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 48e9e1015..be00b2d3d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1941,8 +1941,10 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) CAddrDB adb; if (adb.Read(addrman)) LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); - else + else { LogPrintf("Invalid or missing peers.dat; recreating\n"); + DumpAddresses(); + } } uiInterface.InitMessage(_("Loading banlist...")); @@ -1957,8 +1959,11 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); - } else + } else { LogPrintf("Invalid or missing banlist.dat; recreating\n"); + CNode::SetBannedSetDirty(true); // force write + DumpBanlist(); + } fAddressesInitialized = true; -- cgit v1.2.3 From 37767fd46f673a06864df6e14d3030622b1cb2c9 Mon Sep 17 00:00:00 2001 From: jloughry Date: Fri, 12 Feb 2016 11:35:32 -0700 Subject: fix spelling of advertise in src and doc --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index d9c4c1173..e06e5255d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -205,7 +205,7 @@ bool IsPeerAddrLocalGood(CNode *pnode) } // pushes our own address to a peer -void AdvertizeLocal(CNode *pnode) +void AdvertiseLocal(CNode *pnode) { if (fListen && pnode->fSuccessfullyConnected) { @@ -220,7 +220,7 @@ void AdvertizeLocal(CNode *pnode) } if (addrLocal.IsRoutable()) { - LogPrintf("AdvertizeLocal: advertizing address %s\n", addrLocal.ToString()); + LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); pnode->PushAddress(addrLocal); } } -- cgit v1.2.3 From 110b62f06992d0fb989153afff2dc3aea62a674f Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Wed, 17 Feb 2016 22:44:32 -0800 Subject: Remove vfReachable and modify IsReachable to only use vfLimited. We do not know that a class of Network is reachable, only that it is not. --- src/net.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e06e5255d..b589692d1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -79,7 +79,6 @@ bool fListen = true; uint64_t nLocalServices = NODE_NETWORK; CCriticalSection cs_mapLocalHost; map mapLocalHost; -static bool vfReachable[NET_MAX] = {}; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; @@ -226,14 +225,6 @@ void AdvertiseLocal(CNode *pnode) } } -void SetReachable(enum Network net, bool fFlag) -{ - LOCK(cs_mapLocalHost); - vfReachable[net] = fFlag; - if (net == NET_IPV6 && fFlag) - vfReachable[NET_IPV4] = true; -} - // learn a new local address bool AddLocal(const CService& addr, int nScore) { @@ -256,7 +247,6 @@ bool AddLocal(const CService& addr, int nScore) info.nScore = nScore + (fAlready ? 1 : 0); info.nPort = addr.GetPort(); } - SetReachable(addr.GetNetwork()); } return true; @@ -319,7 +309,7 @@ bool IsLocal(const CService& addr) bool IsReachable(enum Network net) { LOCK(cs_mapLocalHost); - return vfReachable[net] && !vfLimited[net]; + return !vfLimited[net]; } /** check whether a given address is in a network we can probably connect to */ -- cgit v1.2.3 From 9e072a6e66efbda7d39bf61eded21d2b324323be Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Fri, 12 Feb 2016 15:57:15 -0500 Subject: Implement "feefilter" P2P message. The "feefilter" p2p message is used to inform other nodes of your mempool min fee which is the feerate that any new transaction must meet to be accepted to your mempool. This will allow them to filter invs to you according to this feerate. --- src/net.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b589692d1..e8cc753a4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2053,20 +2053,15 @@ public: instance_of_cnetcleanup; - - - - - -void RelayTransaction(const CTransaction& tx) +void RelayTransaction(const CTransaction& tx, CFeeRate feerate) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(10000); ss << tx; - RelayTransaction(tx, ss); + RelayTransaction(tx, feerate, ss); } -void RelayTransaction(const CTransaction& tx, const CDataStream& ss) +void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss) { CInv inv(MSG_TX, tx.GetHash()); { @@ -2087,6 +2082,11 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss) { if(!pnode->fRelayTxes) continue; + { + LOCK(pnode->cs_feeFilter); + if (feerate.GetFeePerK() < pnode->minFeeFilter) + continue; + } LOCK(pnode->cs_filter); if (pnode->pfilter) { @@ -2390,6 +2390,10 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nPingUsecTime = 0; fPingQueued = false; nMinPingUsecTime = std::numeric_limits::max(); + minFeeFilter = 0; + lastSentFeeFilter = 0; + nextSendTimeFeeFilter = 0; + BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; -- cgit v1.2.3 From 66b07247a7a9e48e082502338176cc06edf61474 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 11 Apr 2016 01:09:34 +0000 Subject: Only send one GetAddr response per connection. This conserves resources from abusive peers that just send getaddr in a loop. Also makes correlating addr messages against INVs less effective. --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e8cc753a4..77310fb16 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2384,6 +2384,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nNextAddrSend = 0; nNextInvSend = 0; fRelayTxes = false; + fSentAddr = false; pfilter = new CBloomFilter(); nPingNonceSent = 0; nPingUsecStart = 0; -- cgit v1.2.3 From 7e91f632c70ff1848a152f24ee67a06796803943 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 11 Apr 2016 12:52:29 -0400 Subject: Use txid as key in mapAlreadyAskedFor Previously we used the CInv that would be sent to the peer announcing the transaction as the key, but using the txid instead allows us to decouple the p2p layer from the application logic (which relies on this map to avoid duplicate tx requests). --- src/net.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e8cc753a4..3bf8c165d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -93,7 +93,7 @@ CCriticalSection cs_vNodes; map mapRelay; deque > vRelayExpiration; CCriticalSection cs_mapRelay; -limitedmap mapAlreadyAskedFor(MAX_INV_SZ); +limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static deque vOneShots; CCriticalSection cs_vOneShots; @@ -2436,7 +2436,7 @@ void CNode::AskFor(const CInv& inv) // We're using mapAskFor as a priority queue, // the key is the earliest time the request can be sent int64_t nRequestTime; - limitedmap::const_iterator it = mapAlreadyAskedFor.find(inv); + limitedmap::const_iterator it = mapAlreadyAskedFor.find(inv.hash); if (it != mapAlreadyAskedFor.end()) nRequestTime = it->second; else @@ -2455,7 +2455,7 @@ void CNode::AskFor(const CInv& inv) if (it != mapAlreadyAskedFor.end()) mapAlreadyAskedFor.update(it, nRequestTime); else - mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); + mapAlreadyAskedFor.insert(std::make_pair(inv.hash, nRequestTime)); mapAskFor.insert(std::make_pair(nRequestTime, inv)); } -- cgit v1.2.3 From 38c310299cfef419d42744362b90c1700b598953 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 14 Apr 2016 16:04:50 +0200 Subject: Change mapRelay to store CTransactions --- src/net.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3bf8c165d..e64cb4ef9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -90,8 +90,8 @@ std::string strSubVersion; vector vNodes; CCriticalSection cs_vNodes; -map mapRelay; -deque > vRelayExpiration; +map mapRelay; +deque > vRelayExpiration; CCriticalSection cs_mapRelay; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); @@ -2054,14 +2054,6 @@ instance_of_cnetcleanup; void RelayTransaction(const CTransaction& tx, CFeeRate feerate) -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(10000); - ss << tx; - RelayTransaction(tx, feerate, ss); -} - -void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss) { CInv inv(MSG_TX, tx.GetHash()); { @@ -2073,9 +2065,8 @@ void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStrea vRelayExpiration.pop_front(); } - // Save original serialized message so newer versions are preserved - mapRelay.insert(std::make_pair(inv, ss)); - vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); + mapRelay.insert(std::make_pair(inv.hash, tx)); + vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv.hash)); } LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) -- cgit v1.2.3 From e9fc71e5fa6f0d7991bac616b9fed6a80e77a8d7 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 12 Apr 2016 20:23:16 -0400 Subject: net: require lookup functions to specify all arguments To make it clear where DNS resolves are happening --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index f294e4c66..6ab6ef819 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1443,7 +1443,7 @@ void ThreadDNSAddressSeed() } else { vector vIPs; vector vAdd; - if (LookupHost(seed.host.c_str(), vIPs)) + if (LookupHost(seed.host.c_str(), vIPs, 0, true)) { BOOST_FOREACH(const CNetAddr& ip, vIPs) { @@ -1884,7 +1884,7 @@ void static Discover(boost::thread_group& threadGroup) if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { vector vaddr; - if (LookupHost(pszHostName, vaddr)) + if (LookupHost(pszHostName, vaddr, 0, true)) { BOOST_FOREACH (const CNetAddr &addr, vaddr) { -- cgit v1.2.3 From a98cd1fc86eac1e5e5a09830028233dbce1dae70 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 12 Apr 2016 20:38:06 -0400 Subject: net: manually resolve dns seed sources Note: Some seeds aren't actually returning an IP for their name entries, so they're being added to addrman with a source of [::]. This commit shouldn't change that behavior, for better or worse. --- src/net.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6ab6ef819..7dec8fc1c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1454,7 +1454,15 @@ void ThreadDNSAddressSeed() found++; } } - addrman.Add(vAdd, CNetAddr(seed.name, true)); + // TODO: The seed name resolve may fail, yielding an IP of [::], which results in + // addrman assigning the same source to results from different seeds. + // This should switch to a hard-coded stable dummy IP for each seed name, so that the + // resolve is not required at all. + if (!vIPs.empty()) { + CService seedSource; + Lookup(seed.name.c_str(), seedSource, 0, true); + addrman.Add(vAdd, seedSource); + } } } -- cgit v1.2.3 From ed7068302c7490e8061cb3a558a0f83a465beeea Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 8 Apr 2016 16:26:41 +0200 Subject: Handle mempool requests in send loop, subject to trickle By eliminating queued entries from the mempool response and responding only at trickle time, this makes the mempool no longer leak transaction arrival order information (as the mempool itself is also sorted)-- at least no more than relay itself leaks it. --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index f294e4c66..6b305ebae 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2370,6 +2370,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa hashContinue = uint256(); nStartingHeight = -1; filterInventoryKnown.reset(); + fSendMempool = false; fGetAddr = false; nNextLocalAddrSend = 0; nNextAddrSend = 0; -- cgit v1.2.3 From b5599147533103efea896a1fc4ff51f2d3ad5808 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Wed, 20 Apr 2016 07:05:23 +0000 Subject: Move bloom and feerate filtering to just prior to tx sending. This will avoid sending more pointless INVs around updates, and prevents using filter updates to timetag transactions. Also adds locking for fRelayTxes. --- src/net.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6b305ebae..ccc430f5c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2071,20 +2071,7 @@ void RelayTransaction(const CTransaction& tx, CFeeRate feerate) LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - if(!pnode->fRelayTxes) - continue; - { - LOCK(pnode->cs_feeFilter); - if (feerate.GetFeePerK() < pnode->minFeeFilter) - continue; - } - LOCK(pnode->cs_filter); - if (pnode->pfilter) - { - if (pnode->pfilter->IsRelevantAndUpdate(tx)) - pnode->PushInventory(inv); - } else - pnode->PushInventory(inv); + pnode->PushInventory(inv); } } -- cgit v1.2.3 From f4ac02ee7c6530c273503d8575a492e9b2ac1f13 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Wed, 27 Apr 2016 09:26:33 -0700 Subject: fix race that could fail to persist a ban DumpBanList currently does this: - with lock: take a copy of the banmap - perform I/O (write out the banmap) - with lock: mark the banmap non-dirty If a new ban is added during the I/O operation, it may never be persisted to disk. Reorder operations so that the data to be persisted cannot be older than the time at which the banmap was marked non-dirty. --- src/net.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 7dec8fc1c..f566af24c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2634,9 +2634,10 @@ void DumpBanlist() CBanDB bandb; banmap_t banmap; + CNode::SetBannedSetDirty(false); CNode::GetBanned(banmap); - if (bandb.Write(banmap)) - CNode::SetBannedSetDirty(false); + if (!bandb.Write(banmap)) + CNode::SetBannedSetDirty(true); LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); -- cgit v1.2.3 From d90351f0504c5d4057e560d64107a2f36d7bf3d4 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Fri, 29 Apr 2016 14:23:51 +0000 Subject: More comments on the design of AttemptToEvictConnection. Some developers clearly don't get this and have been posting "improvements" that create clear vulnerabilities. It should have been better explained in the code, since the design is somewhat subtle and getting it right is important. --- src/net.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 7dec8fc1c..ced371164 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -877,6 +877,14 @@ public: } }; +/** 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. + * The strategy used here is to protect a small number of peers + * for each of several distinct characteristics which are difficult + * to forge. In order to partition a node the attacker must be + * simultaneously better at all of them than honest peers. + */ static bool AttemptToEvictConnection(bool fPreferNewConnection) { std::vector vEvictionCandidates; { @@ -905,7 +913,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { if (vEvictionCandidates.empty()) return false; - // Protect the 8 nodes with the best ping times. + // 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(vEvictionCandidates.size())), vEvictionCandidates.end()); @@ -913,7 +921,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { if (vEvictionCandidates.empty()) return false; // Protect the half of the remaining nodes which have been connected the longest. - // This replicates the existing implicit behavior. + // 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(vEvictionCandidates.size() / 2), vEvictionCandidates.end()); @@ -941,6 +949,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { vEvictionCandidates = mapAddrCounts[naMostConnections]; // Do not disconnect peers if there is only one unprotected connection from their network group. + // This step excessively favors netgroup diversity, and should be removed once more protective criteria are established. if (vEvictionCandidates.size() <= 1) // unless we prefer the new connection (for whitelisted peers) if (!fPreferNewConnection) -- cgit v1.2.3 From 1475ecf61141e03f63a79d59831c411e0e8a5c0a Mon Sep 17 00:00:00 2001 From: EthanHeilman Date: Wed, 16 Mar 2016 12:54:30 -0400 Subject: Fix de-serialization bug where AddrMan is corrupted after exception * CAddrDB modified so that when de-serialization code throws an exception Addrman is reset to a clean state * CAddrDB modified to make unit tests possible * Regression test created to ensure bug is fixed * StartNode modifed to clear adrman if CAddrDB::Read returns an error code. --- src/net.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index d9c4c1173..cf5381603 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1944,6 +1944,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) if (adb.Read(addrman)) LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); else { + addrman.Clear(); // Addrman can be in an inconsistent state after failure, reset it LogPrintf("Invalid or missing peers.dat; recreating\n"); DumpAddresses(); } @@ -2336,6 +2337,11 @@ bool CAddrDB::Read(CAddrMan& addr) if (hashIn != hashTmp) return error("%s: Checksum mismatch, data corrupted", __func__); + return Read(addr, ssPeers); +} + +bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) +{ unsigned char pchMsgTmp[4]; try { // de-serialize file header (network specific magic number) and .. @@ -2349,6 +2355,8 @@ bool CAddrDB::Read(CAddrMan& addr) ssPeers >> addr; } catch (const std::exception& e) { + // de-serialization has failed, ensure addrman is left in a clean state + addr.Clear(); return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } -- cgit v1.2.3 From 52cbce287a0d9b3184fd3aee9d4f1186fd2dd7da Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 15 Apr 2016 19:53:45 -0400 Subject: net: don't import std namespace This file is about to be broken up into chunks and moved around. Drop the namespace now rather than requiring other files to use it. --- src/net.cpp | 63 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6642ef651..8ae31e715 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -56,7 +56,6 @@ #endif #endif -using namespace std; namespace { const int MAX_OUTBOUND_CONNECTIONS = 8; @@ -78,7 +77,7 @@ bool fDiscover = true; bool fListen = true; uint64_t nLocalServices = NODE_NETWORK; CCriticalSection cs_mapLocalHost; -map mapLocalHost; +std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; @@ -88,20 +87,20 @@ int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; bool fAddressesInitialized = false; std::string strSubVersion; -vector vNodes; +std::vector vNodes; CCriticalSection cs_vNodes; -map mapRelay; -deque > vRelayExpiration; +std::map mapRelay; +std::deque > vRelayExpiration; CCriticalSection cs_mapRelay; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -static deque vOneShots; +static std::deque vOneShots; CCriticalSection cs_vOneShots; -set setservAddNodeAddresses; +std::set setservAddNodeAddresses; CCriticalSection cs_setservAddNodeAddresses; -vector vAddedNodes; +std::vector vAddedNodes; CCriticalSection cs_vAddedNodes; NodeId nLastNodeId = 0; @@ -135,7 +134,7 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer) int nBestReachability = -1; { LOCK(cs_mapLocalHost); - for (map::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) + for (std::map::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) { int nScore = (*it).second.nScore; int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); @@ -796,7 +795,7 @@ void SocketSendData(CNode *pnode) pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it); } -static list vNodesDisconnected; +static std::list vNodesDisconnected; class CNodeRef { public: @@ -1045,7 +1044,7 @@ void ThreadSocketHandler() { LOCK(cs_vNodes); // Disconnect unused nodes - vector vNodesCopy = vNodes; + std::vector vNodesCopy = vNodes; BOOST_FOREACH(CNode* pnode, vNodesCopy) { if (pnode->fDisconnect || @@ -1069,7 +1068,7 @@ void ThreadSocketHandler() } { // Delete disconnected nodes - list vNodesDisconnectedCopy = vNodesDisconnected; + std::list vNodesDisconnectedCopy = vNodesDisconnected; BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy) { // wait until threads are done using it @@ -1120,7 +1119,7 @@ void ThreadSocketHandler() BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) { FD_SET(hListenSocket.socket, &fdsetRecv); - hSocketMax = max(hSocketMax, hListenSocket.socket); + hSocketMax = std::max(hSocketMax, hListenSocket.socket); have_fds = true; } @@ -1131,7 +1130,7 @@ void ThreadSocketHandler() if (pnode->hSocket == INVALID_SOCKET) continue; FD_SET(pnode->hSocket, &fdsetError); - hSocketMax = max(hSocketMax, pnode->hSocket); + hSocketMax = std::max(hSocketMax, pnode->hSocket); have_fds = true; // Implement the following logic: @@ -1198,7 +1197,7 @@ void ThreadSocketHandler() // // Service each socket // - vector vNodesCopy; + std::vector vNodesCopy; { LOCK(cs_vNodes); vNodesCopy = vNodes; @@ -1355,7 +1354,7 @@ void ThreadMapPort() } } - string strDesc = "Bitcoin " + FormatFullVersion(); + std::string strDesc = "Bitcoin " + FormatFullVersion(); try { while (true) { @@ -1441,7 +1440,7 @@ void ThreadDNSAddressSeed() } } - const vector &vSeeds = Params().DNSSeeds(); + const std::vector &vSeeds = Params().DNSSeeds(); int found = 0; LogPrintf("Loading addresses from DNS seeds (could take a while)\n"); @@ -1450,8 +1449,8 @@ void ThreadDNSAddressSeed() if (HaveNameProxy()) { AddOneShot(seed.host); } else { - vector vIPs; - vector vAdd; + std::vector vIPs; + std::vector vAdd; if (LookupHost(seed.host.c_str(), vIPs, 0, true)) { BOOST_FOREACH(const CNetAddr& ip, vIPs) @@ -1508,7 +1507,7 @@ void DumpData() void static ProcessOneShot() { - string strDest; + std::string strDest; { LOCK(cs_vOneShots); if (vOneShots.empty()) @@ -1574,7 +1573,7 @@ void 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; - set > setConnected; + std::set > setConnected; { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { @@ -1632,7 +1631,7 @@ void ThreadOpenAddedConnections() if (HaveNameProxy()) { while(true) { - list lAddresses(0); + std::list lAddresses(0); { LOCK(cs_vAddedNodes); BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) @@ -1650,16 +1649,16 @@ void ThreadOpenAddedConnections() for (unsigned int i = 0; true; i++) { - list lAddresses(0); + std::list lAddresses(0); { LOCK(cs_vAddedNodes); BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) lAddresses.push_back(strAddNode); } - list > lservAddressesToAdd(0); + std::list > lservAddressesToAdd(0); BOOST_FOREACH(const std::string& strAddNode, lAddresses) { - vector vservNode(0); + std::vector vservNode(0); if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) { lservAddressesToAdd.push_back(vservNode); @@ -1675,7 +1674,7 @@ void ThreadOpenAddedConnections() { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) - for (list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) + for (std::list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) BOOST_FOREACH(const CService& addrNode, *(it)) if (pnode->addr == addrNode) { @@ -1684,7 +1683,7 @@ void ThreadOpenAddedConnections() break; } } - BOOST_FOREACH(vector& vserv, lservAddressesToAdd) + BOOST_FOREACH(std::vector& vserv, lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); @@ -1732,7 +1731,7 @@ void ThreadMessageHandler() SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); while (true) { - vector vNodesCopy; + std::vector vNodesCopy; { LOCK(cs_vNodes); vNodesCopy = vNodes; @@ -1792,7 +1791,7 @@ void ThreadMessageHandler() -bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted) +bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted) { strError = ""; int nOne = 1; @@ -1900,7 +1899,7 @@ void static Discover(boost::thread_group& threadGroup) char pszHostName[256] = ""; if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { - vector vaddr; + std::vector vaddr; if (LookupHost(pszHostName, vaddr, 0, true)) { BOOST_FOREACH (const CNetAddr &addr, vaddr) @@ -2300,7 +2299,7 @@ bool CAddrDB::Read(CAddrMan& addr) // Don't try to resize to a negative number if file is small if (fileSize >= sizeof(uint256)) dataSize = fileSize - sizeof(uint256); - vector vchData; + std::vector vchData; vchData.resize(dataSize); uint256 hashIn; @@ -2580,7 +2579,7 @@ bool CBanDB::Read(banmap_t& banSet) // Don't try to resize to a negative number if file is small if (fileSize >= sizeof(uint256)) dataSize = fileSize - sizeof(uint256); - vector vchData; + std::vector vchData; vchData.resize(dataSize); uint256 hashIn; -- cgit v1.2.3 From 9faa4902cd32af9742b7ffcc163725bff226da1f Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 15 Apr 2016 20:01:40 -0400 Subject: net: remove unused set --- src/net.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8ae31e715..771d9e862 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -97,9 +97,6 @@ limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static std::deque vOneShots; CCriticalSection cs_vOneShots; -std::set setservAddNodeAddresses; -CCriticalSection cs_setservAddNodeAddresses; - std::vector vAddedNodes; CCriticalSection cs_vAddedNodes; @@ -1660,14 +1657,7 @@ void ThreadOpenAddedConnections() BOOST_FOREACH(const std::string& strAddNode, lAddresses) { std::vector vservNode(0); if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) - { lservAddressesToAdd.push_back(vservNode); - { - LOCK(cs_setservAddNodeAddresses); - BOOST_FOREACH(const CService& serv, vservNode) - setservAddNodeAddresses.insert(serv); - } - } } // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry // (keeping in mind that addnode entries can have many IPs if fNameLookup) -- cgit v1.2.3 From 563f375cdeae3e67a57d8a7187362a4706c33748 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 15 Apr 2016 20:03:18 -0400 Subject: net: use the exposed GetNodeSignals() rather than g_signals directly --- src/net.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 771d9e862..d6034953c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -439,7 +439,7 @@ void CNode::CloseSocketDisconnect() void CNode::PushVersion() { - int nBestHeight = g_signals.GetHeight().get_value_or(0); + int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0); int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0))); @@ -1742,7 +1742,7 @@ void ThreadMessageHandler() TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) { - if (!g_signals.ProcessMessages(pnode)) + if (!GetNodeSignals().ProcessMessages(pnode)) pnode->CloseSocketDisconnect(); if (pnode->nSendSize < SendBufferSize()) @@ -1760,7 +1760,7 @@ void ThreadMessageHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) - g_signals.SendMessages(pnode); + GetNodeSignals().SendMessages(pnode); } boost::this_thread::interruption_point(); } -- cgit v1.2.3 From cca221fd211f63b338bd90afc505bd4a22a01d5d Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 18 Apr 2016 15:58:19 -0400 Subject: net: Drop CNodeRef for AttemptToEvictConnection Locking for each operation here is unnecessary, and solves the wrong problem. Additionally, it introduces a problem when cs_vNodes is held in an owning class, to which invididual CNodeRefs won't have access. These should be weak pointers anyway, once vNodes contain shared pointers. Rather than using a refcounting class, use a 3-step process instead. 1. Lock vNodes long enough to snapshot the fields necessary for comparing 2. Unlock and do the comparison 3. Re-lock and mark the resulting node for disconnection if it still exists --- src/net.cpp | 84 +++++++++++++++++++++++-------------------------------------- 1 file changed, 31 insertions(+), 53 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index d6034953c..41e657fba 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -794,51 +794,22 @@ void SocketSendData(CNode *pnode) static std::list vNodesDisconnected; -class CNodeRef { -public: - CNodeRef(CNode *pnode) : _pnode(pnode) { - LOCK(cs_vNodes); - _pnode->AddRef(); - } - - ~CNodeRef() { - LOCK(cs_vNodes); - _pnode->Release(); - } - - CNode& operator *() const {return *_pnode;}; - CNode* operator ->() const {return _pnode;}; - - CNodeRef& operator =(const CNodeRef& other) - { - if (this != &other) { - LOCK(cs_vNodes); - - _pnode->Release(); - _pnode = other._pnode; - _pnode->AddRef(); - } - return *this; - } - - CNodeRef(const CNodeRef& other): - _pnode(other._pnode) - { - LOCK(cs_vNodes); - _pnode->AddRef(); - } -private: - CNode *_pnode; +struct NodeEvictionCandidate +{ + NodeId id; + int64_t nTimeConnected; + int64_t nMinPingUsecTime; + CAddress addr; }; -static bool ReverseCompareNodeMinPingTime(const CNodeRef &a, const CNodeRef &b) +static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { - return a->nMinPingUsecTime > b->nMinPingUsecTime; + return a.nMinPingUsecTime > b.nMinPingUsecTime; } -static bool ReverseCompareNodeTimeConnected(const CNodeRef &a, const CNodeRef &b) +static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { - return a->nTimeConnected > b->nTimeConnected; + return a.nTimeConnected > b.nTimeConnected; } class CompareNetGroupKeyed @@ -851,14 +822,14 @@ public: GetRandBytes(vchSecretKey.data(), vchSecretKey.size()); } - bool operator()(const CNodeRef &a, const CNodeRef &b) + bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { std::vector vchGroupA, vchGroupB; CSHA256 hashA, hashB; std::vector vchA(32), vchB(32); - vchGroupA = a->addr.GetGroup(); - vchGroupB = b->addr.GetGroup(); + vchGroupA = a.addr.GetGroup(); + vchGroupB = b.addr.GetGroup(); hashA.Write(begin_ptr(vchGroupA), vchGroupA.size()); hashB.Write(begin_ptr(vchGroupB), vchGroupB.size()); @@ -882,7 +853,7 @@ public: * simultaneously better at all of them than honest peers. */ static bool AttemptToEvictConnection(bool fPreferNewConnection) { - std::vector vEvictionCandidates; + std::vector vEvictionCandidates; { LOCK(cs_vNodes); @@ -893,7 +864,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - vEvictionCandidates.push_back(CNodeRef(node)); + NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr}; + vEvictionCandidates.push_back(candidate); } } @@ -928,16 +900,16 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { std::vector naMostConnections; unsigned int nMostConnections = 0; int64_t nMostConnectionsTime = 0; - std::map, std::vector > mapAddrCounts; - BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) { - mapAddrCounts[node->addr.GetGroup()].push_back(node); - int64_t grouptime = mapAddrCounts[node->addr.GetGroup()][0]->nTimeConnected; - size_t groupsize = mapAddrCounts[node->addr.GetGroup()].size(); + std::map, std::vector > mapAddrCounts; + BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) { + mapAddrCounts[node.addr.GetGroup()].push_back(node); + int64_t grouptime = mapAddrCounts[node.addr.GetGroup()][0].nTimeConnected; + size_t groupsize = mapAddrCounts[node.addr.GetGroup()].size(); if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { nMostConnections = groupsize; nMostConnectionsTime = grouptime; - naMostConnections = node->addr.GetGroup(); + naMostConnections = node.addr.GetGroup(); } } @@ -952,9 +924,15 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { return false; // Disconnect from the network group with the most connections - vEvictionCandidates[0]->fDisconnect = true; - - return true; + NodeId evicted = vEvictionCandidates.front().id; + LOCK(cs_vNodes); + for(std::vector::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) { + if ((*it)->GetId() == evicted) { + (*it)->fDisconnect = true; + return true; + } + } + return false; } static void AcceptConnection(const ListenSocket& hListenSocket) { -- cgit v1.2.3 From e53e7c54736b98098553ba1a5191e093684f9114 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Thu, 5 May 2016 11:55:46 -0700 Subject: don't run ThreadMessageHandler at lowered priority There's no clear reason ThreadMessageHandler should be low priority. Fixes #8010 (priority inversion). --- src/net.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6642ef651..5e810a0f1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1729,7 +1729,6 @@ void ThreadMessageHandler() boost::mutex condition_mutex; boost::unique_lock lock(condition_mutex); - SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); while (true) { vector vNodesCopy; -- cgit v1.2.3 From 8b8f87714df8c1e0868e6411c8f09c838ea736ab Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 18 Apr 2016 17:02:43 -0400 Subject: net: make Ban/Unban/ClearBan functionality consistent - Ban/Unban/ClearBan call uiInterface.BannedListChanged() as necessary - Ban/Unban/ClearBan sync to disk if the operation is user-invoked - Mark node for disconnection automatically when banning - Lock cs_vNodes while setting disconnected - Don't spin in a tight loop while setting disconnected --- src/net.cpp | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 41e657fba..3f953a72d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -463,9 +463,13 @@ bool CNode::setBannedIsDirty; void CNode::ClearBanned() { - LOCK(cs_setBanned); - setBanned.clear(); - setBannedIsDirty = true; + { + LOCK(cs_setBanned); + setBanned.clear(); + setBannedIsDirty = true; + } + DumpBanlist(); //store banlist to disk + uiInterface.BannedListChanged(); } bool CNode::IsBanned(CNetAddr ip) @@ -516,11 +520,25 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti } banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; - LOCK(cs_setBanned); - if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) - setBanned[subNet] = banEntry; - - setBannedIsDirty = true; + { + LOCK(cs_setBanned); + if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) { + setBanned[subNet] = banEntry; + setBannedIsDirty = true; + } + else + return; + } + uiInterface.BannedListChanged(); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { + if (subNet.Match((CNetAddr)pnode->addr)) + pnode->fDisconnect = true; + } + } + if(banReason == BanReasonManuallyAdded) + DumpBanlist(); //store banlist to disk immediately if user requested ban } bool CNode::Unban(const CNetAddr &addr) { @@ -529,13 +547,15 @@ bool CNode::Unban(const CNetAddr &addr) { } bool CNode::Unban(const CSubNet &subNet) { - LOCK(cs_setBanned); - if (setBanned.erase(subNet)) { + LOCK(cs_setBanned); + if (!setBanned.erase(subNet)) + return false; setBannedIsDirty = true; - return true; } - return false; + uiInterface.BannedListChanged(); + DumpBanlist(); //store banlist to disk immediately + return true; } void CNode::GetBanned(banmap_t &banMap) -- cgit v1.2.3 From e9ed6206b32a05547dfa4bfa1e090044ddad7c82 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 18 Apr 2016 17:59:31 -0400 Subject: net: No need to export DumpBanlist --- src/net.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3f953a72d..f5aa6abde 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -422,6 +422,26 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) return NULL; } +static void DumpBanlist() +{ + CNode::SweepBanned(); // clean unused entries (if bantime has expired) + + if (!CNode::BannedSetIsDirty()) + return; + + int64_t nStart = GetTimeMillis(); + + CBanDB bandb; + banmap_t banmap; + CNode::SetBannedSetDirty(false); + CNode::GetBanned(banmap); + if (!bandb.Write(banmap)) + CNode::SetBannedSetDirty(true); + + LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - nStart); +} + void CNode::CloseSocketDisconnect() { fDisconnect = true; @@ -2607,26 +2627,6 @@ bool CBanDB::Read(banmap_t& banSet) return true; } -void DumpBanlist() -{ - CNode::SweepBanned(); // clean unused entries (if bantime has expired) - - if (!CNode::BannedSetIsDirty()) - return; - - int64_t nStart = GetTimeMillis(); - - CBanDB bandb; - banmap_t banmap; - CNode::SetBannedSetDirty(false); - CNode::GetBanned(banmap); - if (!bandb.Write(banmap)) - CNode::SetBannedSetDirty(true); - - LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", - banmap.size(), GetTimeMillis() - nStart); -} - int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -- cgit v1.2.3 From 581ddff05c92eb835a20c2be9ccf5d2d37b94883 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 12 May 2016 14:00:22 +0200 Subject: net: Add fRelayTxes flag Add a fRelayTxes to keep track of the relay transaction flag we send to other peers. --- src/net.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 5e810a0f1..da5090dbc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -77,6 +77,7 @@ const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; bool fDiscover = true; bool fListen = true; uint64_t nLocalServices = NODE_NETWORK; +bool fRelayTxes = true; CCriticalSection cs_mapLocalHost; map mapLocalHost; static bool vfLimited[NET_MAX] = {}; @@ -454,7 +455,7 @@ void CNode::PushVersion() else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)); + nLocalHostNonce, strSubVersion, nBestHeight, fRelayTxes); } -- cgit v1.2.3 From d87b198b7334317952ca6a1377e25b5c859a1767 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Wed, 20 Apr 2016 19:38:19 +0000 Subject: Remove unneeded feerate param from RelayTransaction/AcceptToMemoryPool. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 5e810a0f1..aa5b47340 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2069,7 +2069,7 @@ public: instance_of_cnetcleanup; -void RelayTransaction(const CTransaction& tx, CFeeRate feerate) +void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); { -- cgit v1.2.3 From 2d83013dc54320b3f0c978475517da6156f7b50d Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sat, 21 May 2016 23:55:22 +0200 Subject: Add support for dnsseeds with option to filter by servicebits --- src/net.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index bbd23d292..54d14a723 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1466,12 +1466,13 @@ void ThreadDNSAddressSeed() } else { std::vector vIPs; std::vector vAdd; - if (LookupHost(seed.host.c_str(), vIPs, 0, true)) + uint64_t requiredServiceBits = NODE_NETWORK; + if (LookupHost(seed.getHost(requiredServiceBits).c_str(), vIPs, 0, true)) { BOOST_FOREACH(const CNetAddr& ip, vIPs) { int nOneDay = 24*3600; - CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); + CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits); addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old vAdd.push_back(addr); found++; -- cgit v1.2.3 From 7e908c7b826cedbf29560ce7a668af809ee71524 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Fri, 20 May 2016 16:19:26 +0000 Subject: Do not use mempool for GETDATA for tx accepted after the last mempool req. The ability to GETDATA a transaction which has not (yet) been relayed is a privacy loss vector. The use of the mempool for this was added as part of the mempool p2p message and is only needed to fetch transactions returned by it. --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index bbd23d292..df3221e84 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2396,6 +2396,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa fRelayTxes = false; fSentAddr = false; pfilter = new CBloomFilter(); + timeLastMempoolReq = 0; nPingNonceSent = 0; nPingUsecStart = 0; nPingUsecTime = 0; -- cgit v1.2.3 From c769c4af11fc58dd4813d328c7f71042bc577676 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 19 Apr 2015 12:34:43 -0700 Subject: Avoid counting failed connect attempts when probably offline. If a node is offline failed outbound connection attempts will crank up the addrman counter and effectively blow away our state. This change reduces the problem by only counting attempts made while the node believes it has outbound connections to at least two netgroups. Connect and addnode connections are also not counted, as there is no reason to unequally penalize them for their more frequent connections -- though there should be no real effect from this unless their addnode configureation is later removed. Wasteful repeated connection attempts while only a few connections are up are avoided via nLastTry. This is still somewhat incomplete protection because our outbound peers could be down but not timed out or might all be on 'local' networks (although the requirement for multiple netgroups helps). --- src/net.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index bbd23d292..f30321869 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -367,7 +367,7 @@ CNode* FindNode(const CService& addr) return NULL; } -CNode* ConnectNode(CAddress addrConnect, const char *pszDest) +CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { if (IsLocal(addrConnect)) @@ -399,7 +399,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) return NULL; } - addrman.Attempt(addrConnect); + addrman.Attempt(addrConnect, fCountFailure); // Add node CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); @@ -416,7 +416,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) } 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); + addrman.Attempt(addrConnect, fCountFailure); } return NULL; @@ -1533,7 +1533,7 @@ void static ProcessOneShot() CAddress addr; CSemaphoreGrant grant(*semOutbound, true); if (grant) { - if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true)) + if (!OpenNetworkConnection(addr, false, &grant, strDest.c_str(), true)) AddOneShot(strDest); } } @@ -1549,7 +1549,7 @@ void ThreadOpenConnections() BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"]) { CAddress addr; - OpenNetworkConnection(addr, NULL, strAddr.c_str()); + OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { MilliSleep(500); @@ -1633,7 +1633,7 @@ void ThreadOpenConnections() } if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect, &grant); + OpenNetworkConnection(addrConnect, (int)setConnected.size() >= min(nMaxConnections - 1, 2), &grant); } } @@ -1655,7 +1655,7 @@ void ThreadOpenAddedConnections() BOOST_FOREACH(const std::string& strAddNode, lAddresses) { CAddress addr; CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(addr, &grant, strAddNode.c_str()); + OpenNetworkConnection(addr, false, &grant, strAddNode.c_str()); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -1694,7 +1694,7 @@ void ThreadOpenAddedConnections() BOOST_FOREACH(std::vector& vserv, lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); + OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), false, &grant); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -1702,7 +1702,7 @@ void ThreadOpenAddedConnections() } // if successful, this moves the passed grant to the constructed node -bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot) +bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot) { // // Initiate outbound network connection @@ -1716,7 +1716,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu } else if (FindNode(std::string(pszDest))) return false; - CNode* pnode = ConnectNode(addrConnect, pszDest); + CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure); boost::this_thread::interruption_point(); if (!pnode) -- cgit v1.2.3 From 6182d10503ae3af222a7e4575724dce7ef563fec Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 19 Apr 2015 13:39:38 -0700 Subject: Do not increment nAttempts by more than one for every Good connection. This slows the increase of the nAttempts in addrman while partitioned, even if the node hasn't yet noticed the partitioning. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index f30321869..c15a4692e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1633,7 +1633,7 @@ void ThreadOpenConnections() } if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect, (int)setConnected.size() >= min(nMaxConnections - 1, 2), &grant); + OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant); } } -- cgit v1.2.3 From 52b02ecd6d7ce918676c76c725678cf0ae2561d2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 26 May 2016 18:44:14 +0200 Subject: Use global ::fRelayTxes instead of CNode one --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 44cdfd2ae..a0c670e59 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -471,7 +471,7 @@ void CNode::PushVersion() else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nBestHeight, fRelayTxes); + nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes); } -- cgit v1.2.3 From 4d8993b3469915d8c9ba4cd3b918f16782edf0de Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sat, 21 May 2016 09:45:32 +0000 Subject: Defer inserting into maprelay until just before relaying. This reduces the rate of not founds by better matching the far end expectations, it also improves privacy by removing the ability to use getdata to probe for a node having a txn before it has been relayed. --- src/net.cpp | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 78a914ebd..c09e3aedb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -90,9 +90,6 @@ std::string strSubVersion; std::vector vNodes; CCriticalSection cs_vNodes; -std::map mapRelay; -std::deque > vRelayExpiration; -CCriticalSection cs_mapRelay; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static std::deque vOneShots; @@ -2081,18 +2078,6 @@ instance_of_cnetcleanup; void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); - { - LOCK(cs_mapRelay); - // Expire old relay messages - while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) - { - mapRelay.erase(vRelayExpiration.front().second); - vRelayExpiration.pop_front(); - } - - mapRelay.insert(std::make_pair(inv.hash, tx)); - vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv.hash)); - } LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { -- cgit v1.2.3 From 053930ffc41ba33fe7ce26bde7097951fe0b8462 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Mon, 23 May 2016 00:21:05 -0700 Subject: Avoid recalculating vchKeyedNetGroup in eviction logic. Lazy calculate vchKeyedNetGroup in CNode::GetKeyedNetGroup. --- src/net.cpp | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index c09e3aedb..eb62ee8a0 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -14,6 +14,7 @@ #include "clientversion.h" #include "consensus/consensus.h" #include "crypto/common.h" +#include "crypto/sha256.h" #include "hash.h" #include "primitives/transaction.h" #include "scheduler.h" @@ -838,6 +839,7 @@ struct NodeEvictionCandidate int64_t nTimeConnected; int64_t nMinPingUsecTime; CAddress addr; + std::vector vchKeyedNetGroup; }; static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) @@ -850,36 +852,8 @@ static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, cons return a.nTimeConnected > b.nTimeConnected; } -class CompareNetGroupKeyed -{ - std::vector vchSecretKey; -public: - CompareNetGroupKeyed() - { - vchSecretKey.resize(32, 0); - GetRandBytes(vchSecretKey.data(), vchSecretKey.size()); - } - - bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) - { - std::vector vchGroupA, vchGroupB; - CSHA256 hashA, hashB; - std::vector vchA(32), vchB(32); - - vchGroupA = a.addr.GetGroup(); - vchGroupB = b.addr.GetGroup(); - - hashA.Write(begin_ptr(vchGroupA), vchGroupA.size()); - hashB.Write(begin_ptr(vchGroupB), vchGroupB.size()); - - hashA.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); - hashB.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); - - hashA.Finalize(begin_ptr(vchA)); - hashB.Finalize(begin_ptr(vchB)); - - return vchA < vchB; - } +static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { + return a.vchKeyedNetGroup < b.vchKeyedNetGroup; }; /** Try to find a connection to evict when the node is full. @@ -902,7 +876,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr}; + NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->vchKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } } @@ -912,9 +886,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Protect connections with certain characteristics // Deterministically select 4 peers to protect by netgroup. - // An attacker cannot predict which netgroups will be protected. - static CompareNetGroupKeyed comparerNetGroupKeyed; - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed); + // 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(vEvictionCandidates.size())), vEvictionCandidates.end()); if (vEvictionCandidates.empty()) return false; @@ -2392,6 +2365,8 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; + CalculateKeyedNetGroup(); + BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; -- cgit v1.2.3 From c31b24f745a84669f2af729052da7fd7ed2da868 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 25 May 2016 15:38:32 +0200 Subject: Use 64-bit SipHash of netgroups in eviction --- src/net.cpp | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index eb62ee8a0..0bc501601 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -839,7 +839,7 @@ struct NodeEvictionCandidate int64_t nTimeConnected; int64_t nMinPingUsecTime; CAddress addr; - std::vector vchKeyedNetGroup; + uint64_t nKeyedNetGroup; }; static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) @@ -853,7 +853,7 @@ static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, cons } static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { - return a.vchKeyedNetGroup < b.vchKeyedNetGroup; + return a.nKeyedNetGroup < b.nKeyedNetGroup; }; /** Try to find a connection to evict when the node is full. @@ -876,7 +876,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->vchKeyedNetGroup}; + NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->nKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } } @@ -908,24 +908,24 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Identify the network group with the most connections and youngest member. // (vEvictionCandidates is already sorted by reverse connect time) - std::vector naMostConnections; + uint64_t naMostConnections; unsigned int nMostConnections = 0; int64_t nMostConnectionsTime = 0; - std::map, std::vector > mapAddrCounts; + std::map > mapAddrCounts; BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) { - mapAddrCounts[node.addr.GetGroup()].push_back(node); - int64_t grouptime = mapAddrCounts[node.addr.GetGroup()][0].nTimeConnected; - size_t groupsize = mapAddrCounts[node.addr.GetGroup()].size(); + mapAddrCounts[node.nKeyedNetGroup].push_back(node); + int64_t grouptime = mapAddrCounts[node.nKeyedNetGroup][0].nTimeConnected; + size_t groupsize = mapAddrCounts[node.nKeyedNetGroup].size(); if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { nMostConnections = groupsize; nMostConnectionsTime = grouptime; - naMostConnections = node.addr.GetGroup(); + naMostConnections = node.nKeyedNetGroup; } } // Reduce to the network group with the most connections - vEvictionCandidates = mapAddrCounts[naMostConnections]; + vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]); // Do not disconnect peers if there is only one unprotected connection from their network group. // This step excessively favors netgroup diversity, and should be removed once more protective criteria are established. @@ -2318,6 +2318,8 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), + addr(addrIn), + nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), addrKnown(5000, 0.001), filterInventoryKnown(50000, 0.000001) { @@ -2330,7 +2332,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nRecvBytes = 0; nTimeConnected = GetTime(); nTimeOffset = 0; - addr = addrIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; strSubVer = ""; @@ -2365,8 +2366,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; - CalculateKeyedNetGroup(); - BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; @@ -2599,3 +2598,17 @@ bool CBanDB::Read(banmap_t& banSet) int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } + +/* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad) +{ + static uint64_t k0 = 0, k1 = 0; + while (k0 == 0 && k1 == 0) { + // Make sure this only runs on the first invocation. + GetRandBytes((unsigned char*)&k0, sizeof(k0)); + GetRandBytes((unsigned char*)&k1, sizeof(k1)); + } + + std::vector vchNetGroup(ad.GetGroup()); + + return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); +} -- cgit v1.2.3 From 888483098e60f2a944f1d246bbfec4d14a2975f8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 7 Jun 2016 16:29:03 +0200 Subject: Use C++11 thread-safe static initializers --- src/net.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 0bc501601..e29053cf5 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2601,12 +2601,8 @@ int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { /* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad) { - static uint64_t k0 = 0, k1 = 0; - while (k0 == 0 && k1 == 0) { - // Make sure this only runs on the first invocation. - GetRandBytes((unsigned char*)&k0, sizeof(k0)); - GetRandBytes((unsigned char*)&k1, sizeof(k1)); - } + static const uint64_t k0 = GetRand(std::numeric_limits::max()); + static const uint64_t k1 = GetRand(std::numeric_limits::max()); std::vector vchNetGroup(ad.GetGroup()); -- cgit v1.2.3 From 657fc19d6535b33748dafcf63cc0248c6fa0ee7a Mon Sep 17 00:00:00 2001 From: instagibbs Date: Fri, 10 Jun 2016 10:09:06 -0400 Subject: rename mapAddrCount to mapNetGroupNodes --- src/net.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 173eba57c..c29dc3032 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -911,11 +911,11 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { uint64_t naMostConnections; unsigned int nMostConnections = 0; int64_t nMostConnectionsTime = 0; - std::map > mapAddrCounts; + std::map > mapNetGroupNodes; BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) { - mapAddrCounts[node.nKeyedNetGroup].push_back(node); - int64_t grouptime = mapAddrCounts[node.nKeyedNetGroup][0].nTimeConnected; - size_t groupsize = mapAddrCounts[node.nKeyedNetGroup].size(); + mapNetGroupNodes[node.nKeyedNetGroup].push_back(node); + int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected; + size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size(); if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { nMostConnections = groupsize; @@ -925,7 +925,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { } // Reduce to the network group with the most connections - vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]); + vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]); // Do not disconnect peers if there is only one unprotected connection from their network group. // This step excessively favors netgroup diversity, and should be removed once more protective criteria are established. -- cgit v1.2.3 From fc83f181530fb566726e5f3f4197fc5586d77fd8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 26 Mar 2016 19:09:22 +0100 Subject: Verify that outbound connections have expected services --- src/net.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 173eba57c..a0c2bd509 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -71,6 +71,9 @@ namespace { const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; +/** Services this node implementation cares about */ +static const uint64_t nRelevantServices = NODE_NETWORK; + // // Global state variables // @@ -409,6 +412,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure vNodes.push_back(pnode); } + pnode->nServicesExpected = addrConnect.nServices & nRelevantServices; pnode->nTimeConnected = GetTime(); return pnode; @@ -2325,6 +2329,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa filterInventoryKnown(50000, 0.000001) { nServices = 0; + nServicesExpected = 0; hSocket = hSocketIn; nRecvVersion = INIT_PROTO_VERSION; nLastSend = 0; -- cgit v1.2.3 From 5e7ab16d29ac66a5a5753dd4f59b6fb12e60654e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 26 Mar 2016 13:31:25 +0100 Subject: Only store and connect to NODE_NETWORK nodes --- src/net.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a0c2bd509..395e1fe42 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1596,6 +1596,10 @@ void ThreadOpenConnections() if (IsLimited(addr)) continue; + // only connect to full nodes + if (!(addr.nServices & NODE_NETWORK)) + continue; + // only consider very recently tried nodes after 30 failed attempts if (nANow - addr.nLastTry < 600 && nTries < 30) continue; -- cgit v1.2.3 From 15bf863219abe968ebe9e59fed4806c9fd07a58b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 25 May 2016 17:18:37 +0200 Subject: Don't require services in -addnode --- src/net.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 395e1fe42..80ba7fce2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -162,7 +162,7 @@ static std::vector convertSeed6(const std::vector &vSeedsIn { struct in6_addr ip; memcpy(&ip, i->addr, sizeof(ip)); - CAddress addr(CService(ip, i->port)); + CAddress addr(CService(ip, i->port), NODE_NETWORK); addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek; vSeedsOut.push_back(addr); } @@ -179,9 +179,8 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer) CService addr; if (GetLocal(addr, paddrPeer)) { - ret = CAddress(addr); + ret = CAddress(addr, nLocalServices); } - ret.nServices = nLocalServices; ret.nTime = GetAdjustedTime(); return ret; } @@ -465,7 +464,7 @@ void CNode::PushVersion() int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0); int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); - CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0))); + CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0), addr.nServices)); CAddress addrMe = GetLocalAddress(&addr); GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); if (fLogIPs) @@ -1441,7 +1440,7 @@ void ThreadDNSAddressSeed() } else { std::vector vIPs; std::vector vAdd; - uint64_t requiredServiceBits = NODE_NETWORK; + uint64_t requiredServiceBits = nRelevantServices; if (LookupHost(seed.getHost(requiredServiceBits).c_str(), vIPs, 0, true)) { BOOST_FOREACH(const CNetAddr& ip, vIPs) @@ -1524,7 +1523,7 @@ void ThreadOpenConnections() ProcessOneShot(); BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"]) { - CAddress addr; + CAddress addr(CService(), 0); OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { @@ -1674,7 +1673,9 @@ void ThreadOpenAddedConnections() BOOST_FOREACH(std::vector& vserv, lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), false, &grant); + /* We want -addnode to work even for nodes that don't provide all + * wanted services, so pass in nServices=0 to CAddress. */ + OpenNetworkConnection(CAddress(vserv[i % vserv.size()], 0), false, &grant); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes -- cgit v1.2.3 From ee06e04369c37da21e048fda849cce2a1f066f84 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 8 Jun 2016 19:12:22 +0200 Subject: Introduce enum ServiceFlags for service flags --- src/net.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 80ba7fce2..4661974d2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -72,14 +72,14 @@ namespace { const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; /** Services this node implementation cares about */ -static const uint64_t nRelevantServices = NODE_NETWORK; +static const ServiceFlags nRelevantServices = NODE_NETWORK; // // Global state variables // bool fDiscover = true; bool fListen = true; -uint64_t nLocalServices = NODE_NETWORK; +ServiceFlags nLocalServices = NODE_NETWORK; bool fRelayTxes = true; CCriticalSection cs_mapLocalHost; std::map mapLocalHost; @@ -175,7 +175,7 @@ static std::vector convertSeed6(const std::vector &vSeedsIn // one by discovery. CAddress GetLocalAddress(const CNetAddr *paddrPeer) { - CAddress ret(CService("0.0.0.0",GetListenPort()),0); + CAddress ret(CService("0.0.0.0",GetListenPort()), NODE_NONE); CService addr; if (GetLocal(addr, paddrPeer)) { @@ -411,7 +411,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure vNodes.push_back(pnode); } - pnode->nServicesExpected = addrConnect.nServices & nRelevantServices; + pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); pnode->nTimeConnected = GetTime(); return pnode; @@ -464,14 +464,14 @@ void CNode::PushVersion() int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0); int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); - CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0), addr.nServices)); + CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0), addr.nServices)); CAddress addrMe = GetLocalAddress(&addr); GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); - PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, + PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes); } @@ -1440,7 +1440,7 @@ void ThreadDNSAddressSeed() } else { std::vector vIPs; std::vector vAdd; - uint64_t requiredServiceBits = nRelevantServices; + ServiceFlags requiredServiceBits = nRelevantServices; if (LookupHost(seed.getHost(requiredServiceBits).c_str(), vIPs, 0, true)) { BOOST_FOREACH(const CNetAddr& ip, vIPs) @@ -1523,7 +1523,7 @@ void ThreadOpenConnections() ProcessOneShot(); BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"]) { - CAddress addr(CService(), 0); + CAddress addr(CService(), NODE_NONE); OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { @@ -1674,8 +1674,8 @@ void ThreadOpenAddedConnections() { CSemaphoreGrant grant(*semOutbound); /* We want -addnode to work even for nodes that don't provide all - * wanted services, so pass in nServices=0 to CAddress. */ - OpenNetworkConnection(CAddress(vserv[i % vserv.size()], 0), false, &grant); + * wanted services, so pass in nServices=NODE_NONE to CAddress. */ + OpenNetworkConnection(CAddress(vserv[i % vserv.size()], NODE_NONE), false, &grant); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -2333,8 +2333,8 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa addrKnown(5000, 0.001), filterInventoryKnown(50000, 0.000001) { - nServices = 0; - nServicesExpected = 0; + nServices = NODE_NONE; + nServicesExpected = NODE_NONE; hSocket = hSocketIn; nRecvVersion = INIT_PROTO_VERSION; nLastSend = 0; -- cgit v1.2.3 From ecd7fd37c888f8ebc64cf3d92272975b37ae54ca Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 13 Jun 2016 16:01:21 +0200 Subject: Introduce REQUIRED_SERVICES constant --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4661974d2..a390eca77 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1596,7 +1596,7 @@ void ThreadOpenConnections() continue; // only connect to full nodes - if (!(addr.nServices & NODE_NETWORK)) + if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES) continue; // only consider very recently tried nodes after 30 failed attempts -- cgit v1.2.3 From 1111b80df84aa7bc72fbddcc7bafde43f0835d90 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 28 May 2016 15:32:30 +0200 Subject: Rework addnode behaviour * Use CNode::addeName to track whether a connection to a name is already open * A new connection to a previously-connected by-name addednode is only opened when the previous one closes (even if the name starts resolving to something else) * At most one connection is opened per addednode (even if the name resolves to multiple) * Unify the code between ThreadOpenAddedNodeConnections and getaddednodeinfo * Information about open connections is always returned, and the dns argument becomes a dummy * An IP address and inbound/outbound is only reported for the (at most 1) open connection --- src/net.cpp | 107 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 48 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a390eca77..4d27db760 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1616,68 +1616,79 @@ void ThreadOpenConnections() } } -void ThreadOpenAddedConnections() +std::vector GetAddedNodeInfo() { + std::vector ret; + + std::list lAddresses(0); { LOCK(cs_vAddedNodes); - vAddedNodes = mapMultiArgs["-addnode"]; + ret.reserve(vAddedNodes.size()); + BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) + lAddresses.push_back(strAddNode); } - if (HaveNameProxy()) { - while(true) { - std::list lAddresses(0); - { - LOCK(cs_vAddedNodes); - BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) - lAddresses.push_back(strAddNode); + + // Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService + std::map mapConnected; + std::map> mapConnectedByName; + { + LOCK(cs_vNodes); + for (const CNode* pnode : vNodes) { + if (pnode->addr.IsValid()) { + mapConnected[pnode->addr] = pnode->fInbound; } - BOOST_FOREACH(const std::string& strAddNode, lAddresses) { - CAddress addr; - CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(addr, false, &grant, strAddNode.c_str()); - MilliSleep(500); + if (!pnode->addrName.empty()) { + mapConnectedByName[pnode->addrName] = std::make_pair(pnode->fInbound, static_cast(pnode->addr)); } - MilliSleep(120000); // Retry every 2 minutes } } + BOOST_FOREACH(const std::string& strAddNode, lAddresses) { + CService service(strAddNode, Params().GetDefaultPort()); + if (service.IsValid()) { + // strAddNode is an IP:port + auto it = mapConnected.find(service); + if (it != mapConnected.end()) { + ret.push_back(AddedNodeInfo{strAddNode, service, true, it->second}); + } else { + ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false}); + } + } else { + // strAddNode is a name + auto it = mapConnectedByName.find(strAddNode); + if (it != mapConnectedByName.end()) { + ret.push_back(AddedNodeInfo{strAddNode, it->second.second, true, it->second.first}); + } else { + ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false}); + } + } + } + + return ret; +} + +void ThreadOpenAddedConnections() +{ + { + LOCK(cs_vAddedNodes); + vAddedNodes = mapMultiArgs["-addnode"]; + } + for (unsigned int i = 0; true; i++) { - std::list lAddresses(0); - { - LOCK(cs_vAddedNodes); - BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) - lAddresses.push_back(strAddNode); + std::vector vInfo = GetAddedNodeInfo(); + for (const AddedNodeInfo& info : vInfo) { + if (!info.fConnected) { + CSemaphoreGrant grant(*semOutbound); + // If strAddedNode is an IP/port, decode it immediately, so + // OpenNetworkConnection can detect existing connections to that IP/port. + CService service(info.strAddedNode, Params().GetDefaultPort()); + OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false); + MilliSleep(500); + } } - std::list > lservAddressesToAdd(0); - BOOST_FOREACH(const std::string& strAddNode, lAddresses) { - std::vector vservNode(0); - if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) - lservAddressesToAdd.push_back(vservNode); - } - // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry - // (keeping in mind that addnode entries can have many IPs if fNameLookup) - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - for (std::list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) - BOOST_FOREACH(const CService& addrNode, *(it)) - if (pnode->addr == addrNode) - { - it = lservAddressesToAdd.erase(it); - it--; - break; - } - } - BOOST_FOREACH(std::vector& vserv, lservAddressesToAdd) - { - CSemaphoreGrant grant(*semOutbound); - /* We want -addnode to work even for nodes that don't provide all - * wanted services, so pass in nServices=NODE_NONE to CAddress. */ - OpenNetworkConnection(CAddress(vserv[i % vserv.size()], NODE_NONE), false, &grant); - MilliSleep(500); - } MilliSleep(120000); // Retry every 2 minutes } } -- cgit v1.2.3 From f9f5cfc50637f2cd1540923caf337e2651ec1625 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 28 May 2016 16:22:02 +0200 Subject: Prevent duplicate connections where one is by name and another by ip --- src/net.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4d27db760..30a6bc896 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -400,6 +400,26 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure return NULL; } + if (pszDest && addrConnect.IsValid()) { + // 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 + // name catch this early. + CNode* pnode = FindNode((CService)addrConnect); + if (pnode) + { + pnode->AddRef(); + { + LOCK(cs_vNodes); + if (pnode->addrName.empty()) { + pnode->addrName = std::string(pszDest); + } + } + CloseSocket(hSocket); + return pnode; + } + } + addrman.Attempt(addrConnect, fCountFailure); // Add node -- cgit v1.2.3 From bc0a895d810107132651c8178e95a981b9f3ff74 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 15 Jun 2016 19:31:28 +0200 Subject: Do not set extra flags for unfiltered DNS seed results --- src/net.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a390eca77..5e791291c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1415,6 +1415,18 @@ void MapPort(bool) +static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredServiceBits) +{ + //use default host for non-filter-capable seeds or if we use the default service bits (NODE_NETWORK) + if (!data.supportsServiceBitsFiltering || *requiredServiceBits == NODE_NETWORK) { + *requiredServiceBits = NODE_NETWORK; + return data.host; + } + + return strprintf("x%x.%s", *requiredServiceBits, data.host); +} + + void ThreadDNSAddressSeed() { // goal: only query DNS seeds if address need is acute @@ -1441,7 +1453,7 @@ void ThreadDNSAddressSeed() std::vector vIPs; std::vector vAdd; ServiceFlags requiredServiceBits = nRelevantServices; - if (LookupHost(seed.getHost(requiredServiceBits).c_str(), vIPs, 0, true)) + if (LookupHost(GetDNSHost(seed, &requiredServiceBits).c_str(), vIPs, 0, true)) { BOOST_FOREACH(const CNetAddr& ip, vIPs) { -- cgit v1.2.3 From 5d0ca81f7422b7eac0a5129c6fbccad77e36b85d Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 22 May 2016 05:55:15 +0000 Subject: Add recently accepted blocks and txn to AttemptToEvictConnection. This protects any not-already-protected peers who were the most recent four to relay transactions and most recent four to send blocks to us. --- src/net.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 173eba57c..ec547e8c9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -838,6 +838,11 @@ struct NodeEvictionCandidate NodeId id; int64_t nTimeConnected; int64_t nMinPingUsecTime; + int64_t nLastBlockTime; + int64_t nLastTXTime; + bool fNetworkNode; + bool fRelayTxes; + bool fBloomFilter; CAddress addr; uint64_t nKeyedNetGroup; }; @@ -854,7 +859,24 @@ static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, cons static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { return a.nKeyedNetGroup < b.nKeyedNetGroup; -}; +} + +static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) +{ + // There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block. + if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime; + if (a.fNetworkNode != b.fNetworkNode) return b.fNetworkNode; + return a.nTimeConnected > b.nTimeConnected; +} + +static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) +{ + // There is a fall-through here because it is common for a node to have more than a few peers that have not yet relayed txn. + if (a.nLastTXTime != b.nLastTXTime) return a.nLastTXTime < b.nLastTXTime; + if (a.fRelayTxes != b.fRelayTxes) return b.fRelayTxes; + if (a.fBloomFilter != b.fBloomFilter) return a.fBloomFilter; + return a.nTimeConnected > b.nTimeConnected; +} /** Try to find a connection to evict when the node is full. * Extreme care must be taken to avoid opening the node to attacker @@ -864,7 +886,7 @@ static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvict * to forge. In order to partition a node the attacker must be * simultaneously better at all of them than honest peers. */ -static bool AttemptToEvictConnection(bool fPreferNewConnection) { +static bool AttemptToEvictConnection() { std::vector vEvictionCandidates; { LOCK(cs_vNodes); @@ -876,7 +898,9 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->nKeyedNetGroup}; + NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, + node->nLastBlockTime, node->nLastTXTime, node->fNetworkNode, + node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } } @@ -899,6 +923,20 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { if (vEvictionCandidates.empty()) return false; + // 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(vEvictionCandidates.size())), vEvictionCandidates.end()); + + if (vEvictionCandidates.empty()) return false; + + // 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(vEvictionCandidates.size())), vEvictionCandidates.end()); + + if (vEvictionCandidates.empty()) return false; + // 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); @@ -999,7 +1037,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { if (nInbound >= nMaxInbound) { - if (!AttemptToEvictConnection(whitelisted)) { + if (!AttemptToEvictConnection()) { // No connection to evict, disconnect the new connection LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n"); CloseSocket(hSocket); @@ -2358,6 +2396,8 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa fSentAddr = false; pfilter = new CBloomFilter(); timeLastMempoolReq = 0; + nLastBlockTime = 0; + nLastTXTime = 0; nPingNonceSent = 0; nPingUsecStart = 0; nPingUsecTime = 0; -- cgit v1.2.3 From 6ee7f05622c32431a9815a96b31a6a65a821fdcc Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Fri, 10 Jun 2016 03:02:01 +0000 Subject: Allow disconnecting a netgroup with only one member in eviction. With the latest additions there are enough protective measures that we can take the training wheels off. --- src/net.cpp | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index ec547e8c9..89eb55ae9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -965,13 +965,6 @@ static bool AttemptToEvictConnection() { // Reduce to the network group with the most connections vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]); - // Do not disconnect peers if there is only one unprotected connection from their network group. - // This step excessively favors netgroup diversity, and should be removed once more protective criteria are established. - if (vEvictionCandidates.size() <= 1) - // unless we prefer the new connection (for whitelisted peers) - if (!fPreferNewConnection) - return false; - // Disconnect from the network group with the most connections NodeId evicted = vEvictionCandidates.front().id; LOCK(cs_vNodes); -- cgit v1.2.3 From 927f8eede0c9e0ab9cc2b5e43e39cfe3e1340dd6 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 6 May 2016 11:50:24 -0700 Subject: Add ability to fetch CNode by NodeId --- src/net.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4eca3d75c..336163a89 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -368,6 +368,16 @@ CNode* FindNode(const CService& addr) return NULL; } +//TODO: This is used in only one place in main, and should be removed +CNode* FindNode(const NodeId nodeid) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->GetId() == nodeid) + return (pnode); + return NULL; +} + CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { -- cgit v1.2.3 From b8a97498df1e83f8dcc49bc3fa4344f9e9799242 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 17 Nov 2015 00:20:49 +0100 Subject: BIP144: Handshake and relay (receiver side) Service bit logic by Nicolas Dorier. Only download blocks from witness peers after fork. --- src/net.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 336163a89..dc83f19be 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -72,7 +72,7 @@ namespace { const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; /** Services this node implementation cares about */ -static const ServiceFlags nRelevantServices = NODE_NETWORK; +ServiceFlags nRelevantServices = NODE_NETWORK; // // Global state variables @@ -1676,6 +1676,10 @@ void ThreadOpenConnections() if (nANow - addr.nLastTry < 600 && nTries < 30) continue; + // only consider nodes missing relevant services after 40 failed attemps + if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40) + continue; + // do not allow non-default ports, unless after 50 invalid addresses selected already if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50) continue; -- cgit v1.2.3 From 2b1f6f9ccf36f1e0a2c9d99154e1642f796d7c2b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 3 Jan 2016 18:54:50 +0100 Subject: BIP141: Other consensus critical limits, and BIP145 Includes changes by Suhas Daftuar, Luke-jr, and mruddy. --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index dc83f19be..4cbc43e4d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2182,7 +2182,7 @@ void CNode::RecordBytesSent(uint64_t bytes) void CNode::SetMaxOutboundTarget(uint64_t limit) { LOCK(cs_totalBytesSent); - uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SIZE; + uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SERIALIZED_SIZE; nMaxOutboundLimit = limit; if (limit > 0 && limit < recommendedMinimum) @@ -2237,7 +2237,7 @@ bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) { // keep a large enough buffer to at least relay each block once uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle(); - uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SIZE; + uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SERIALIZED_SIZE; if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer) return true; } -- cgit v1.2.3 From aa59f2ed3f378c02159e41ff3ae2df76ef850577 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 22 Jul 2016 16:01:12 +0200 Subject: Add extra message to avoid a long 'Loading banlist' --- src/net.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4cbc43e4d..6a1ba4161 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2050,6 +2050,8 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) DumpBanlist(); } + uiInterface.InitMessage(_("Starting network threads...")); + fAddressesInitialized = true; if (semOutbound == NULL) { -- cgit v1.2.3 From 31d6b1d5f0414d8b356d8cb9c99961d8a04d6c0a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 31 May 2016 13:05:52 -0400 Subject: net: Split resolving out of CNetAddr --- src/net.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4cbc43e4d..8725346fe 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1396,8 +1396,11 @@ void ThreadMapPort() { if(externalIPAddress[0]) { - LogPrintf("UPnP: ExternalIPAddress = %s\n", externalIPAddress); - AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP); + CNetAddr resolved; + if(LookupHost(externalIPAddress, resolved, false)) { + LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString().c_str()); + AddLocal(resolved, LOCAL_UPNP); + } } else LogPrintf("UPnP: GetExternalIPAddress failed.\n"); @@ -1623,7 +1626,9 @@ void ThreadOpenConnections() static bool done = false; if (!done) { LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); - addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1")); + CNetAddr local; + LookupHost("127.0.0.1", local, false); + addrman.Add(convertSeed6(Params().FixedSeeds()), local); done = true; } } -- cgit v1.2.3 From f96c7c4d91f3c09d26658bc9c15aa561689fa2d4 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 31 May 2016 13:51:11 -0400 Subject: net: Split resolving out of CService --- src/net.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8725346fe..e44bdafc7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -175,7 +175,7 @@ static std::vector convertSeed6(const std::vector &vSeedsIn // one by discovery. CAddress GetLocalAddress(const CNetAddr *paddrPeer) { - CAddress ret(CService("0.0.0.0",GetListenPort()), NODE_NONE); + CAddress ret(CService(CNetAddr(),GetListenPort()), NODE_NONE); CService addr; if (GetLocal(addr, paddrPeer)) { @@ -494,7 +494,7 @@ void CNode::PushVersion() int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0); int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); - CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0), addr.nServices)); + CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = GetLocalAddress(&addr); GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); if (fLogIPs) @@ -1727,7 +1727,8 @@ std::vector GetAddedNodeInfo() } BOOST_FOREACH(const std::string& strAddNode, lAddresses) { - CService service(strAddNode, Params().GetDefaultPort()); + CService service; + LookupNumeric(strAddNode.c_str(), service, Params().GetDefaultPort()); if (service.IsValid()) { // strAddNode is an IP:port auto it = mapConnected.find(service); @@ -1765,7 +1766,8 @@ void ThreadOpenAddedConnections() CSemaphoreGrant grant(*semOutbound); // If strAddedNode is an IP/port, decode it immediately, so // OpenNetworkConnection can detect existing connections to that IP/port. - CService service(info.strAddedNode, Params().GetDefaultPort()); + CService service; + LookupNumeric(info.strAddedNode.c_str(), service, Params().GetDefaultPort()); OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false); MilliSleep(500); } @@ -2063,8 +2065,11 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) semOutbound = new CSemaphore(nMaxOutbound); } - if (pnodeLocalHost == NULL) - pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); + if (pnodeLocalHost == NULL) { + CNetAddr local; + LookupHost("127.0.0.1", local, false); + pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + } Discover(threadGroup); -- cgit v1.2.3 From 21ba407a7369a0229b8a8554dee0da63a64e6639 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 31 May 2016 17:42:38 -0400 Subject: net: narrow include scope after moving to netaddress Net functionality is no longer needed for CAddress/CAddrman/etc. now that CNetAddr/CService/CSubNet are dumb storage classes. --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e44bdafc7..e9bb406e9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -17,6 +17,7 @@ #include "crypto/sha256.h" #include "hash.h" #include "primitives/transaction.h" +#include "netbase.h" #include "scheduler.h" #include "ui_interface.h" #include "utilstrencodings.h" -- cgit v1.2.3 From 8945384bca00f74ba85c98a52925c254c49025a5 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 4 Aug 2016 16:37:49 -0400 Subject: net: Have LookupNumeric return a CService directly Also fix up a few small issues: - Lookup with "badip:port" now sets the port to 0 - Don't allow assert to have side-effects --- src/net.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e9bb406e9..fc44a0f17 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1728,8 +1728,7 @@ std::vector GetAddedNodeInfo() } BOOST_FOREACH(const std::string& strAddNode, lAddresses) { - CService service; - LookupNumeric(strAddNode.c_str(), service, Params().GetDefaultPort()); + CService service(LookupNumeric(strAddNode.c_str(), Params().GetDefaultPort())); if (service.IsValid()) { // strAddNode is an IP:port auto it = mapConnected.find(service); @@ -1767,8 +1766,7 @@ void ThreadOpenAddedConnections() CSemaphoreGrant grant(*semOutbound); // If strAddedNode is an IP/port, decode it immediately, so // OpenNetworkConnection can detect existing connections to that IP/port. - CService service; - LookupNumeric(info.strAddedNode.c_str(), service, Params().GetDefaultPort()); + CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort())); OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false); MilliSleep(500); } -- cgit v1.2.3 From f13c1bae529cd6e45b4e4b1768a6ab953870fd29 Mon Sep 17 00:00:00 2001 From: Michael Rotarius Date: Fri, 5 Aug 2016 18:34:32 +0200 Subject: Move AdvertiseLocal debug output to net category --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4bbe5059d..c159198ac 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -216,7 +216,7 @@ void AdvertiseLocal(CNode *pnode) } if (addrLocal.IsRoutable()) { - LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); + LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); pnode->PushAddress(addrLocal); } } -- cgit v1.2.3 From 1aacfc2da521a8e0d718e9ac561d9b2d7916eb0b Mon Sep 17 00:00:00 2001 From: leijurv Date: Sat, 13 Aug 2016 11:21:13 -0600 Subject: various typos --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4bbe5059d..4f669f338 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1676,7 +1676,7 @@ void ThreadOpenConnections() if (nANow - addr.nLastTry < 600 && nTries < 30) continue; - // only consider nodes missing relevant services after 40 failed attemps + // only consider nodes missing relevant services after 40 failed attempts if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40) continue; -- cgit v1.2.3 From b7c349d5e7c207bb7a2e7469c3e5522c9909c17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jan=C3=ADk?= Date: Mon, 15 Aug 2016 14:10:07 +0200 Subject: Do not shadow variables in networking code --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a0773b2e0..8fbd8fd19 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -66,7 +66,7 @@ namespace { SOCKET socket; bool whitelisted; - ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {} + ListenSocket(SOCKET _socket, bool _whitelisted) : socket(_socket), whitelisted(_whitelisted) {} }; } -- cgit v1.2.3 From dbb1f640e67da25f0a41b9d2e696b789d2fd4e0d Mon Sep 17 00:00:00 2001 From: Ethan Heilman Date: Fri, 17 Jun 2016 00:10:07 -0400 Subject: Added feeler connections increasing good addrs in the tried table. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests if addresses are online or offline by briefly connecting to them. These short lived connections are referred to as feeler connections. Feeler connections are designed to increase the number of fresh online addresses in tried by selecting and connecting to addresses in new. One feeler connection is attempted on average once every two minutes. This change was suggested as Countermeasure 4 in Eclipse Attacks on Bitcoin’s Peer-to-Peer Network, Ethan Heilman, Alison Kendler, Aviv Zohar, Sharon Goldberg. ePrint Archive Report 2015/263. March 2015. --- src/net.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 8 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 39c8d12e2..33dc10cbc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -43,6 +43,9 @@ // Dump addresses to peers.dat and banlist.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 +// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization. +#define FEELER_SLEEP_WINDOW 1 + #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 #endif @@ -61,6 +64,7 @@ namespace { const int MAX_OUTBOUND_CONNECTIONS = 8; + const int MAX_FEELER_CONNECTIONS = 1; struct ListenSocket { SOCKET socket; @@ -1017,7 +1021,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; - int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS; + int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); + assert(nMaxInbound > 0); if (hSocket != INVALID_SOCKET) if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) @@ -1613,6 +1618,9 @@ void ThreadOpenConnections() // Initiate network connections int64_t nStart = GetTime(); + + // Minimum time before next feeler connection (in microseconds). + int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL); while (true) { ProcessOneShot(); @@ -1652,13 +1660,36 @@ void ThreadOpenConnections() } } } + assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS)); - int64_t nANow = GetAdjustedTime(); + // Feeler Connections + // + // Design goals: + // * Increase the number of connectable addresses in the tried table. + // + // Method: + // * Choose a random address from new and attempt to connect to it if we can connect + // successfully it is added to tried. + // * Start attempting feeler connections only after node finishes making outbound + // connections. + // * Only make a feeler connection once every few minutes. + // + bool fFeeler = false; + if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) { + int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds). + if (nTime > nNextFeeler) { + nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL); + fFeeler = true; + } else { + continue; + } + } + int64_t nANow = GetAdjustedTime(); int nTries = 0; while (true) { - CAddrInfo addr = addrman.Select(); + CAddrInfo addr = addrman.Select(fFeeler); // if we selected an invalid address, restart if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) @@ -1694,8 +1725,17 @@ void ThreadOpenConnections() break; } - if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant); + if (addrConnect.IsValid()) { + + if (fFeeler) { + // Add small amount of random noise before connection to avoid synchronization. + int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000); + MilliSleep(randsleep); + LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString()); + } + + OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, NULL, false, fFeeler); + } } } @@ -1777,7 +1817,7 @@ void ThreadOpenAddedConnections() } // if successful, this moves the passed grant to the constructed node -bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot) +bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler) { // // Initiate outbound network connection @@ -1801,6 +1841,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem pnode->fNetworkNode = true; if (fOneShot) pnode->fOneShot = true; + if (fFeeler) + pnode->fFeeler = true; return true; } @@ -2062,7 +2104,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); + int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections); semOutbound = new CSemaphore(nMaxOutbound); } @@ -2107,7 +2149,7 @@ bool StopNode() LogPrintf("StopNode()\n"); MapPort(false); if (semOutbound) - for (int i=0; ipost(); if (fAddressesInitialized) @@ -2448,6 +2490,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa fWhitelisted = false; fOneShot = false; fClient = false; // set by version message + fFeeler = false; fInbound = fInboundIn; fNetworkNode = false; fSuccessfullyConnected = false; -- cgit v1.2.3 From d93b14dc5ddfb937b0cc18be425b9d048cefb66b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 00:13:15 -0400 Subject: net: move CBanDB and CAddrDB out of net.h/cpp This will eventually solve a circular dependency --- src/net.cpp | 209 ------------------------------------------------------------ 1 file changed, 209 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index c5b080f79..cee149ee7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2356,114 +2356,6 @@ void CNode::Fuzz(int nChance) Fuzz(2); } -// -// CAddrDB -// - -CAddrDB::CAddrDB() -{ - pathAddr = GetDataDir() / "peers.dat"; -} - -bool CAddrDB::Write(const CAddrMan& addr) -{ - // Generate random temporary filename - unsigned short randv = 0; - GetRandBytes((unsigned char*)&randv, sizeof(randv)); - std::string tmpfn = strprintf("peers.dat.%04x", randv); - - // serialize addresses, checksum data up to that point, then append csum - CDataStream ssPeers(SER_DISK, CLIENT_VERSION); - ssPeers << FLATDATA(Params().MessageStart()); - ssPeers << addr; - uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); - ssPeers << hash; - - // open temp output file, and associate with CAutoFile - boost::filesystem::path pathTmp = GetDataDir() / tmpfn; - FILE *file = fopen(pathTmp.string().c_str(), "wb"); - CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("%s: Failed to open file %s", __func__, pathTmp.string()); - - // Write and commit header, data - try { - fileout << ssPeers; - } - catch (const std::exception& e) { - return error("%s: Serialize or I/O error - %s", __func__, e.what()); - } - FileCommit(fileout.Get()); - fileout.fclose(); - - // replace existing peers.dat, if any, with new peers.dat.XXXX - if (!RenameOver(pathTmp, pathAddr)) - return error("%s: Rename-into-place failed", __func__); - - return true; -} - -bool CAddrDB::Read(CAddrMan& addr) -{ - // open input file, and associate with CAutoFile - FILE *file = fopen(pathAddr.string().c_str(), "rb"); - CAutoFile filein(file, SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("%s: Failed to open file %s", __func__, pathAddr.string()); - - // use file size to size memory buffer - uint64_t fileSize = boost::filesystem::file_size(pathAddr); - uint64_t dataSize = 0; - // Don't try to resize to a negative number if file is small - if (fileSize >= sizeof(uint256)) - dataSize = fileSize - sizeof(uint256); - std::vector vchData; - vchData.resize(dataSize); - uint256 hashIn; - - // read data and checksum from file - try { - filein.read((char *)&vchData[0], dataSize); - filein >> hashIn; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - filein.fclose(); - - CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION); - - // verify stored checksum matches input data - uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end()); - if (hashIn != hashTmp) - return error("%s: Checksum mismatch, data corrupted", __func__); - - return Read(addr, ssPeers); -} - -bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) -{ - unsigned char pchMsgTmp[4]; - try { - // de-serialize file header (network specific magic number) and .. - ssPeers >> FLATDATA(pchMsgTmp); - - // ... verify the network matches ours - if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) - return error("%s: Invalid network magic number", __func__); - - // de-serialize address data into one CAddrMan object - ssPeers >> addr; - } - catch (const std::exception& e) { - // de-serialization has failed, ensure addrman is left in a clean state - addr.Clear(); - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - - return true; -} - unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); } unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); } @@ -2649,107 +2541,6 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) LEAVE_CRITICAL_SECTION(cs_vSend); } -// -// CBanDB -// - -CBanDB::CBanDB() -{ - pathBanlist = GetDataDir() / "banlist.dat"; -} - -bool CBanDB::Write(const banmap_t& banSet) -{ - // Generate random temporary filename - unsigned short randv = 0; - GetRandBytes((unsigned char*)&randv, sizeof(randv)); - std::string tmpfn = strprintf("banlist.dat.%04x", randv); - - // serialize banlist, checksum data up to that point, then append csum - CDataStream ssBanlist(SER_DISK, CLIENT_VERSION); - ssBanlist << FLATDATA(Params().MessageStart()); - ssBanlist << banSet; - uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end()); - ssBanlist << hash; - - // open temp output file, and associate with CAutoFile - boost::filesystem::path pathTmp = GetDataDir() / tmpfn; - FILE *file = fopen(pathTmp.string().c_str(), "wb"); - CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("%s: Failed to open file %s", __func__, pathTmp.string()); - - // Write and commit header, data - try { - fileout << ssBanlist; - } - catch (const std::exception& e) { - return error("%s: Serialize or I/O error - %s", __func__, e.what()); - } - FileCommit(fileout.Get()); - fileout.fclose(); - - // replace existing banlist.dat, if any, with new banlist.dat.XXXX - if (!RenameOver(pathTmp, pathBanlist)) - return error("%s: Rename-into-place failed", __func__); - - return true; -} - -bool CBanDB::Read(banmap_t& banSet) -{ - // open input file, and associate with CAutoFile - FILE *file = fopen(pathBanlist.string().c_str(), "rb"); - CAutoFile filein(file, SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("%s: Failed to open file %s", __func__, pathBanlist.string()); - - // use file size to size memory buffer - uint64_t fileSize = boost::filesystem::file_size(pathBanlist); - uint64_t dataSize = 0; - // Don't try to resize to a negative number if file is small - if (fileSize >= sizeof(uint256)) - dataSize = fileSize - sizeof(uint256); - std::vector vchData; - vchData.resize(dataSize); - uint256 hashIn; - - // read data and checksum from file - try { - filein.read((char *)&vchData[0], dataSize); - filein >> hashIn; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - filein.fclose(); - - CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION); - - // verify stored checksum matches input data - uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end()); - if (hashIn != hashTmp) - return error("%s: Checksum mismatch, data corrupted", __func__); - - unsigned char pchMsgTmp[4]; - try { - // de-serialize file header (network specific magic number) and .. - ssBanlist >> FLATDATA(pchMsgTmp); - - // ... verify the network matches ours - if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) - return error("%s: Invalid network magic number", __func__); - - // de-serialize address data into one CAddrMan object - ssBanlist >> banSet; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - - return true; -} - int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -- cgit v1.2.3 From cd16f48028f54327d4afba9c1f91f25d0b072aa5 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 14:47:18 -0400 Subject: net: Create CConnman to encapsulate p2p connections --- src/net.cpp | 113 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 50 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cee149ee7..6177dc04f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -65,13 +65,6 @@ namespace { const int MAX_OUTBOUND_CONNECTIONS = 8; const int MAX_FEELER_CONNECTIONS = 1; - - struct ListenSocket { - SOCKET socket; - bool whitelisted; - - ListenSocket(SOCKET _socket, bool _whitelisted) : socket(_socket), whitelisted(_whitelisted) {} - }; } const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; @@ -1015,7 +1008,7 @@ static bool AttemptToEvictConnection() { return false; } -static void AcceptConnection(const ListenSocket& hListenSocket) { +void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); @@ -1089,7 +1082,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { } } -void ThreadSocketHandler() +void CConnman::ThreadSocketHandler() { unsigned int nPrevNodeCount = 0; while (true) @@ -1497,7 +1490,7 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe } -void ThreadDNSAddressSeed() +void CConnman::ThreadDNSAddressSeed() { // goal: only query DNS seeds if address need is acute if ((addrman.size() > 0) && @@ -1577,7 +1570,7 @@ void DumpData() DumpBanlist(); } -void static ProcessOneShot() +void CConnman::ProcessOneShot() { std::string strDest; { @@ -1595,7 +1588,7 @@ void static ProcessOneShot() } } -void ThreadOpenConnections() +void CConnman::ThreadOpenConnections() { // Connect to specific addresses if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) @@ -1791,7 +1784,7 @@ std::vector GetAddedNodeInfo() return ret; } -void ThreadOpenAddedConnections() +void CConnman::ThreadOpenAddedConnections() { { LOCK(cs_vAddedNodes); @@ -1848,7 +1841,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem } -void ThreadMessageHandler() +void CConnman::ThreadMessageHandler() { boost::mutex condition_mutex; boost::unique_lock lock(condition_mutex); @@ -2064,7 +2057,11 @@ void static Discover(boost::thread_group& threadGroup) #endif } -void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) +CConnman::CConnman() +{ +} + +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) { uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat @@ -2102,6 +2099,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) fAddressesInitialized = true; + Discover(threadGroup); + + bool ret = connman.Start(threadGroup, strNodeError); + + // Dump network addresses + scheduler.scheduleEvery(DumpData, DUMP_ADDRESSES_INTERVAL); + return ret; +} + +bool CConnman::Start(boost::thread_group& threadGroup, std::string& strNodeError) +{ if (semOutbound == NULL) { // initialize semaphore int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections); @@ -2114,8 +2122,6 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); } - Discover(threadGroup); - // // Start threads // @@ -2123,34 +2129,30 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) if (!GetBoolArg("-dnsseed", true)) LogPrintf("DNS seeding disabled\n"); else - threadGroup.create_thread(boost::bind(&TraceThread, "dnsseed", &ThreadDNSAddressSeed)); + threadGroup.create_thread(boost::bind(&TraceThread >, "dnsseed", boost::function(boost::bind(&CConnman::ThreadDNSAddressSeed, this)))); // Map ports with UPnP MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); // Send and receive from sockets, accept connections - threadGroup.create_thread(boost::bind(&TraceThread, "net", &ThreadSocketHandler)); + threadGroup.create_thread(boost::bind(&TraceThread >, "net", boost::function(boost::bind(&CConnman::ThreadSocketHandler, this)))); // Initiate outbound connections from -addnode - threadGroup.create_thread(boost::bind(&TraceThread, "addcon", &ThreadOpenAddedConnections)); + threadGroup.create_thread(boost::bind(&TraceThread >, "addcon", boost::function(boost::bind(&CConnman::ThreadOpenAddedConnections, this)))); // Initiate outbound connections - threadGroup.create_thread(boost::bind(&TraceThread, "opencon", &ThreadOpenConnections)); + threadGroup.create_thread(boost::bind(&TraceThread >, "opencon", boost::function(boost::bind(&CConnman::ThreadOpenConnections, this)))); // Process messages - threadGroup.create_thread(boost::bind(&TraceThread, "msghand", &ThreadMessageHandler)); + threadGroup.create_thread(boost::bind(&TraceThread >, "msghand", boost::function(boost::bind(&CConnman::ThreadMessageHandler, this)))); - // Dump network addresses - scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL); + return true; } -bool StopNode() +bool StopNode(CConnman& connman) { LogPrintf("StopNode()\n"); MapPort(false); - if (semOutbound) - for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) - semOutbound->post(); if (fAddressesInitialized) { @@ -2158,6 +2160,7 @@ bool StopNode() fAddressesInitialized = false; } + connman.Stop(); return true; } @@ -2168,28 +2171,6 @@ public: ~CNetCleanup() { - // Close sockets - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->hSocket != INVALID_SOCKET) - CloseSocket(pnode->hSocket); - BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket) - if (hListenSocket.socket != INVALID_SOCKET) - if (!CloseSocket(hListenSocket.socket)) - LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); - - // clean up some globals (to help leak detection) - BOOST_FOREACH(CNode *pnode, vNodes) - delete pnode; - BOOST_FOREACH(CNode *pnode, vNodesDisconnected) - delete pnode; - vNodes.clear(); - vNodesDisconnected.clear(); - vhListenSocket.clear(); - delete semOutbound; - semOutbound = NULL; - delete pnodeLocalHost; - pnodeLocalHost = NULL; - #ifdef WIN32 // Shutdown Windows Sockets WSACleanup(); @@ -2198,6 +2179,38 @@ public: } instance_of_cnetcleanup; +void CConnman::Stop() +{ + if (semOutbound) + for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) + semOutbound->post(); + + // Close sockets + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->hSocket != INVALID_SOCKET) + CloseSocket(pnode->hSocket); + BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket) + if (hListenSocket.socket != INVALID_SOCKET) + if (!CloseSocket(hListenSocket.socket)) + LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); + + // clean up some globals (to help leak detection) + BOOST_FOREACH(CNode *pnode, vNodes) + delete pnode; + BOOST_FOREACH(CNode *pnode, vNodesDisconnected) + delete pnode; + vNodes.clear(); + vNodesDisconnected.clear(); + vhListenSocket.clear(); + delete semOutbound; + semOutbound = NULL; + delete pnodeLocalHost; + pnodeLocalHost = NULL; +} + +CConnman::~CConnman() +{ +} void RelayTransaction(const CTransaction& tx) { -- cgit v1.2.3 From 8d58c4d81f18e9a51d11ee354434cf55d03a4add Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 26 May 2016 14:26:01 -0400 Subject: net: Pass CConnman around as needed --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6177dc04f..b99989b28 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1869,7 +1869,7 @@ void CConnman::ThreadMessageHandler() TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) { - if (!GetNodeSignals().ProcessMessages(pnode)) + if (!GetNodeSignals().ProcessMessages(pnode, *this)) pnode->CloseSocketDisconnect(); if (pnode->nSendSize < SendBufferSize()) @@ -1887,7 +1887,7 @@ void CConnman::ThreadMessageHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) - GetNodeSignals().SendMessages(pnode); + GetNodeSignals().SendMessages(pnode, *this); } boost::this_thread::interruption_point(); } -- cgit v1.2.3 From 02137f11e2ea5d153f433493639730587836a1e3 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 15:46:00 -0400 Subject: net: Move socket binding into CConnman --- src/net.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b99989b28..006982000 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -84,7 +84,6 @@ std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; -static std::vector vhListenSocket; CAddrMan addrman; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; bool fAddressesInitialized = false; @@ -1908,7 +1907,7 @@ void CConnman::ThreadMessageHandler() -bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted) +bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted) { strError = ""; int nOne = 1; -- cgit v1.2.3 From b1a5f4320878e34eb998737dce333270dd83e436 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 15:59:10 -0400 Subject: net: move OpenNetworkConnection into CConnman --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 006982000..83a96205a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -375,7 +375,7 @@ CNode* FindNode(const NodeId nodeid) return NULL; } -CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) +CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { if (IsLocal(addrConnect)) @@ -1809,7 +1809,7 @@ void CConnman::ThreadOpenAddedConnections() } // if successful, this moves the passed grant to the constructed node -bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler) +bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler) { // // Initiate outbound network connection -- cgit v1.2.3 From aaf018e3b79417ecfd39291a8c100df77969d77a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 24 May 2016 18:59:16 -0400 Subject: net: handle nodesignals in CConnman --- src/net.cpp | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 83a96205a..26bf477e9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -313,12 +313,6 @@ bool IsReachable(const CNetAddr& addr) return IsReachable(net); } -void AddressCurrentlyConnected(const CService& addr) -{ - addrman.Connected(addr); -} - - uint64_t CNode::nTotalBytesRecv = 0; uint64_t CNode::nTotalBytesSent = 0; CCriticalSection CNode::cs_totalBytesRecv; @@ -431,6 +425,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo // Add node CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); + GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); { @@ -1070,6 +1065,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } CNode* pnode = new CNode(hSocket, addr, "", true); + GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -1139,7 +1135,7 @@ void CConnman::ThreadSocketHandler() if (fDelete) { vNodesDisconnected.remove(pnode); - delete pnode; + DeleteNode(pnode); } } } @@ -2119,6 +2115,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, std::string& strNodeError CNetAddr local; LookupHost("127.0.0.1", local, false); pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } // @@ -2194,19 +2191,32 @@ void CConnman::Stop() LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); // clean up some globals (to help leak detection) - BOOST_FOREACH(CNode *pnode, vNodes) - delete pnode; - BOOST_FOREACH(CNode *pnode, vNodesDisconnected) - delete pnode; + BOOST_FOREACH(CNode *pnode, vNodes) { + DeleteNode(pnode); + } + BOOST_FOREACH(CNode *pnode, vNodesDisconnected) { + DeleteNode(pnode); + } vNodes.clear(); vNodesDisconnected.clear(); vhListenSocket.clear(); delete semOutbound; semOutbound = NULL; - delete pnodeLocalHost; + if(pnodeLocalHost) + DeleteNode(pnodeLocalHost); pnodeLocalHost = NULL; } +void CConnman::DeleteNode(CNode* pnode) +{ + assert(pnode); + bool fUpdateConnectionTime = false; + GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime); + if(fUpdateConnectionTime) + addrman.Connected(pnode->addr); + delete pnode; +} + CConnman::~CConnman() { } @@ -2442,8 +2452,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa // Be shy and don't send version until we hear if (hSocket != INVALID_SOCKET && !fInbound) PushVersion(); - - GetNodeSignals().InitializeNode(GetId(), this); } CNode::~CNode() @@ -2452,8 +2460,6 @@ CNode::~CNode() if (pfilter) delete pfilter; - - GetNodeSignals().FinalizeNode(GetId()); } void CNode::AskFor(const CInv& inv) -- cgit v1.2.3 From a0f3d3cdad630103d919a4ec802c413b87fa1f1a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 17:43:11 -0400 Subject: net: move ban and addrman functions into CConnman --- src/net.cpp | 126 +++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 49 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 26bf477e9..eeb84fca7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -84,9 +84,7 @@ std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; -CAddrMan addrman; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; -bool fAddressesInitialized = false; std::string strSubVersion; std::vector vNodes; @@ -446,21 +444,21 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo return NULL; } -static void DumpBanlist() +void CConnman::DumpBanlist() { - CNode::SweepBanned(); // clean unused entries (if bantime has expired) + SweepBanned(); // clean unused entries (if bantime has expired) - if (!CNode::BannedSetIsDirty()) + if (!BannedSetIsDirty()) return; int64_t nStart = GetTimeMillis(); CBanDB bandb; banmap_t banmap; - CNode::SetBannedSetDirty(false); - CNode::GetBanned(banmap); + SetBannedSetDirty(false); + GetBanned(banmap); if (!bandb.Write(banmap)) - CNode::SetBannedSetDirty(true); + SetBannedSetDirty(true); LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); @@ -501,11 +499,7 @@ void CNode::PushVersion() -banmap_t CNode::setBanned; -CCriticalSection CNode::cs_setBanned; -bool CNode::setBannedIsDirty; - -void CNode::ClearBanned() +void CConnman::ClearBanned() { { LOCK(cs_setBanned); @@ -516,7 +510,7 @@ void CNode::ClearBanned() uiInterface.BannedListChanged(); } -bool CNode::IsBanned(CNetAddr ip) +bool CConnman::IsBanned(CNetAddr ip) { bool fResult = false; { @@ -533,7 +527,7 @@ bool CNode::IsBanned(CNetAddr ip) return fResult; } -bool CNode::IsBanned(CSubNet subnet) +bool CConnman::IsBanned(CSubNet subnet) { bool fResult = false; { @@ -549,12 +543,12 @@ bool CNode::IsBanned(CSubNet subnet) return fResult; } -void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { +void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { CSubNet subNet(addr); Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch); } -void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { +void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { CBanEntry banEntry(GetTime()); banEntry.banReason = banReason; if (bantimeoffset <= 0) @@ -585,12 +579,12 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti DumpBanlist(); //store banlist to disk immediately if user requested ban } -bool CNode::Unban(const CNetAddr &addr) { +bool CConnman::Unban(const CNetAddr &addr) { CSubNet subNet(addr); return Unban(subNet); } -bool CNode::Unban(const CSubNet &subNet) { +bool CConnman::Unban(const CSubNet &subNet) { { LOCK(cs_setBanned); if (!setBanned.erase(subNet)) @@ -602,20 +596,20 @@ bool CNode::Unban(const CSubNet &subNet) { return true; } -void CNode::GetBanned(banmap_t &banMap) +void CConnman::GetBanned(banmap_t &banMap) { LOCK(cs_setBanned); banMap = setBanned; //create a thread safe copy } -void CNode::SetBanned(const banmap_t &banMap) +void CConnman::SetBanned(const banmap_t &banMap) { LOCK(cs_setBanned); setBanned = banMap; setBannedIsDirty = true; } -void CNode::SweepBanned() +void CConnman::SweepBanned() { int64_t now = GetTime(); @@ -636,13 +630,13 @@ void CNode::SweepBanned() } } -bool CNode::BannedSetIsDirty() +bool CConnman::BannedSetIsDirty() { LOCK(cs_setBanned); return setBannedIsDirty; } -void CNode::SetBannedSetDirty(bool dirty) +void CConnman::SetBannedSetDirty(bool dirty) { LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag setBannedIsDirty = dirty; @@ -1047,7 +1041,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int)); #endif - if (CNode::IsBanned(addr) && !whitelisted) + if (IsBanned(addr) && !whitelisted) { LogPrintf("connection from %s dropped (banned)\n", addr.ToString()); CloseSocket(hSocket); @@ -1548,7 +1542,7 @@ void CConnman::ThreadDNSAddressSeed() -void DumpAddresses() +void CConnman::DumpAddresses() { int64_t nStart = GetTimeMillis(); @@ -1559,7 +1553,7 @@ void DumpAddresses() addrman.size(), GetTimeMillis() - nStart); } -void DumpData() +void CConnman::DumpData() { DumpAddresses(); DumpBanlist(); @@ -1813,7 +1807,7 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai boost::this_thread::interruption_point(); if (!pszDest) { if (IsLocal(addrConnect) || - FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) || + FindNode((CNetAddr)addrConnect) || IsBanned(addrConnect) || FindNode(addrConnect.ToStringIPPort())) return false; } else if (FindNode(std::string(pszDest))) @@ -2054,10 +2048,22 @@ void static Discover(boost::thread_group& threadGroup) CConnman::CConnman() { + setBannedIsDirty = false; + fAddressesInitialized = false; } bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) { + Discover(threadGroup); + + bool ret = connman.Start(threadGroup, scheduler, strNodeError); + + return ret; +} + +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +{ + uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2078,15 +2084,15 @@ bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& CBanDB bandb; banmap_t banmap; if (bandb.Read(banmap)) { - CNode::SetBanned(banmap); // thread save setter - CNode::SetBannedSetDirty(false); // no need to write down, just read data - CNode::SweepBanned(); // sweep out unused entries + SetBanned(banmap); // thread save setter + SetBannedSetDirty(false); // no need to write down, just read data + SweepBanned(); // sweep out unused entries LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); } else { LogPrintf("Invalid or missing banlist.dat; recreating\n"); - CNode::SetBannedSetDirty(true); // force write + SetBannedSetDirty(true); // force write DumpBanlist(); } @@ -2094,17 +2100,6 @@ bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& fAddressesInitialized = true; - Discover(threadGroup); - - bool ret = connman.Start(threadGroup, strNodeError); - - // Dump network addresses - scheduler.scheduleEvery(DumpData, DUMP_ADDRESSES_INTERVAL); - return ret; -} - -bool CConnman::Start(boost::thread_group& threadGroup, std::string& strNodeError) -{ if (semOutbound == NULL) { // initialize semaphore int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections); @@ -2142,6 +2137,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, std::string& strNodeError // Process messages threadGroup.create_thread(boost::bind(&TraceThread >, "msghand", boost::function(boost::bind(&CConnman::ThreadMessageHandler, this)))); + // Dump network addresses + scheduler.scheduleEvery(boost::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL); + return true; } @@ -2150,12 +2148,6 @@ bool StopNode(CConnman& connman) LogPrintf("StopNode()\n"); MapPort(false); - if (fAddressesInitialized) - { - DumpData(); - fAddressesInitialized = false; - } - connman.Stop(); return true; } @@ -2181,6 +2173,12 @@ void CConnman::Stop() for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) semOutbound->post(); + if (fAddressesInitialized) + { + DumpData(); + fAddressesInitialized = false; + } + // Close sockets BOOST_FOREACH(CNode* pnode, vNodes) if (pnode->hSocket != INVALID_SOCKET) @@ -2221,6 +2219,36 @@ CConnman::~CConnman() { } +size_t CConnman::GetAddressCount() const +{ + return addrman.size(); +} + +void CConnman::SetServices(const CService &addr, ServiceFlags nServices) +{ + addrman.SetServices(addr, nServices); +} + +void CConnman::MarkAddressGood(const CAddress& addr) +{ + addrman.Good(addr); +} + +void CConnman::AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty) +{ + addrman.Add(addr, addrFrom, nTimePenalty); +} + +void CConnman::AddNewAddresses(const std::vector& vAddr, const CAddress& addrFrom, int64_t nTimePenalty) +{ + addrman.Add(vAddr, addrFrom, nTimePenalty); +} + +std::vector CConnman::GetAddresses() +{ + return addrman.GetAddr(); +} + void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); -- cgit v1.2.3 From 502dd3a8a0bc0d12744e75f84a22cc12074c5683 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 17:51:01 -0400 Subject: net: Add oneshot functions to CConnman --- src/net.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index eeb84fca7..045939c2e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -91,9 +91,6 @@ std::vector vNodes; CCriticalSection cs_vNodes; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -static std::deque vOneShots; -CCriticalSection cs_vOneShots; - std::vector vAddedNodes; CCriticalSection cs_vAddedNodes; @@ -107,7 +104,7 @@ boost::condition_variable messageHandlerCondition; static CNodeSignals g_signals; CNodeSignals& GetNodeSignals() { return g_signals; } -void AddOneShot(const std::string& strDest) +void CConnman::AddOneShot(const std::string& strDest) { LOCK(cs_vOneShots); vOneShots.push_back(strDest); -- cgit v1.2.3 From 8ae2dac1c65349e4620422a43b7fa9d49af52c11 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 18:12:58 -0400 Subject: net: move added node functions to CConnman --- src/net.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 045939c2e..8ca6df0f9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -91,9 +91,6 @@ std::vector vNodes; CCriticalSection cs_vNodes; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -std::vector vAddedNodes; -CCriticalSection cs_vAddedNodes; - NodeId nLastNodeId = 0; CCriticalSection cs_nLastNodeId; @@ -1718,7 +1715,7 @@ void CConnman::ThreadOpenConnections() } } -std::vector GetAddedNodeInfo() +std::vector CConnman::GetAddedNodeInfo() { std::vector ret; @@ -2246,6 +2243,30 @@ std::vector CConnman::GetAddresses() return addrman.GetAddr(); } +bool CConnman::AddNode(const std::string& strNode) +{ + LOCK(cs_vAddedNodes); + for(std::vector::const_iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) { + if (strNode == *it) + return false; + } + + vAddedNodes.push_back(strNode); + return true; +} + +bool CConnman::RemoveAddedNode(const std::string& strNode) +{ + LOCK(cs_vAddedNodes); + for(std::vector::iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) { + if (strNode == *it) { + vAddedNodes.erase(it); + return true; + } + } + return false; +} + void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); -- cgit v1.2.3 From c0569c7fa1e25599b3f1d6a16b15ec23052021da Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 18:30:03 -0400 Subject: net: Add most functions needed for vNodes to CConnman --- src/net.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8ca6df0f9..e1cfc565d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2267,6 +2267,72 @@ bool CConnman::RemoveAddedNode(const std::string& strNode) return false; } +size_t CConnman::GetNodeCount(NumConnections flags) +{ + LOCK(cs_vNodes); + if (flags == CConnman::CONNECTIONS_ALL) // Shortcut if we want total + return vNodes.size(); + + int nNum = 0; + for(std::vector::const_iterator it = vNodes.begin(); it != vNodes.end(); ++it) + if (flags & ((*it)->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) + nNum++; + + return nNum; +} + +void CConnman::GetNodeStats(std::vector& vstats) +{ + vstats.clear(); + LOCK(cs_vNodes); + vstats.reserve(vNodes.size()); + for(std::vector::iterator it = vNodes.begin(); it != vNodes.end(); ++it) { + CNode* pnode = *it; + CNodeStats stats; + pnode->copyStats(stats); + vstats.push_back(stats); + } +} + +bool CConnman::DisconnectAddress(const CNetAddr& netAddr) +{ + if (CNode* pnode = FindNode(netAddr)) { + pnode->fDisconnect = true; + return true; + } + return false; +} + +bool CConnman::DisconnectSubnet(const CSubNet& subNet) +{ + if (CNode* pnode = FindNode(subNet)) { + pnode->fDisconnect = true; + return true; + } + return false; +} + +bool CConnman::DisconnectNode(const std::string& strNode) +{ + if (CNode* pnode = FindNode(strNode)) { + pnode->fDisconnect = true; + return true; + } + return false; +} + +bool CConnman::DisconnectNode(NodeId id) +{ + LOCK(cs_vNodes); + for(CNode* pnode : vNodes) { + if (id == pnode->id) { + pnode->fDisconnect = true; + return true; + } + } + return false; +} + void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); -- cgit v1.2.3 From 53347f0cb99e514815e44a56439a4a10012238f8 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 16 Apr 2016 19:13:12 -0400 Subject: net: create generic functor accessors and move vNodes to CConnman --- src/net.cpp | 83 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 19 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e1cfc565d..f20f63e04 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -87,8 +87,6 @@ uint64_t nLocalHostNonce = 0; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; std::string strSubVersion; -std::vector vNodes; -CCriticalSection cs_vNodes; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); NodeId nLastNodeId = 0; @@ -315,7 +313,7 @@ uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0; uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day uint64_t CNode::nMaxOutboundCycleStartTime = 0; -CNode* FindNode(const CNetAddr& ip) +CNode* CConnman::FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -324,7 +322,7 @@ CNode* FindNode(const CNetAddr& ip) return NULL; } -CNode* FindNode(const CSubNet& subNet) +CNode* CConnman::FindNode(const CSubNet& subNet) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -333,7 +331,7 @@ CNode* FindNode(const CSubNet& subNet) return NULL; } -CNode* FindNode(const std::string& addrName) +CNode* CConnman::FindNode(const std::string& addrName) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -342,7 +340,7 @@ CNode* FindNode(const std::string& addrName) return NULL; } -CNode* FindNode(const CService& addr) +CNode* CConnman::FindNode(const CService& addr) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -351,16 +349,6 @@ CNode* FindNode(const CService& addr) return NULL; } -//TODO: This is used in only one place in main, and should be removed -CNode* FindNode(const NodeId nodeid) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->GetId() == nodeid) - return (pnode); - return NULL; -} - CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { @@ -899,7 +887,8 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction * to forge. In order to partition a node the attacker must be * simultaneously better at all of them than honest peers. */ -static bool AttemptToEvictConnection() { +bool CConnman::AttemptToEvictConnection() +{ std::vector vEvictionCandidates; { LOCK(cs_vNodes); @@ -2320,7 +2309,6 @@ bool CConnman::DisconnectNode(const std::string& strNode) } return false; } - bool CConnman::DisconnectNode(NodeId id) { LOCK(cs_vNodes); @@ -2333,7 +2321,7 @@ bool CConnman::DisconnectNode(NodeId id) return false; } -void RelayTransaction(const CTransaction& tx) +void CConnman::RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); LOCK(cs_vNodes); @@ -2671,6 +2659,63 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) LEAVE_CRITICAL_SECTION(cs_vSend); } +bool CConnman::ForNode(NodeId id, std::function func) +{ + CNode* found = nullptr; + LOCK(cs_vNodes); + for (auto&& pnode : vNodes) { + if(pnode->id == id) { + found = pnode; + break; + } + } + return found != nullptr && func(found); +} + +bool CConnman::ForEachNode(std::function func) +{ + LOCK(cs_vNodes); + for (auto&& node : vNodes) + if(!func(node)) + return false; + return true; +} + +bool CConnman::ForEachNode(std::function func) const +{ + LOCK(cs_vNodes); + for (const auto& node : vNodes) + if(!func(node)) + return false; + return true; +} + +bool CConnman::ForEachNodeThen(std::function pre, std::function post) +{ + bool ret = true; + LOCK(cs_vNodes); + for (auto&& node : vNodes) + if(!pre(node)) { + ret = false; + break; + } + post(); + return ret; +} + +bool CConnman::ForEachNodeThen(std::function pre, std::function post) const +{ + bool ret = true; + LOCK(cs_vNodes); + for (const auto& node : vNodes) + if(!pre(node)) { + ret = false; + break; + } + post(); + return ret; +} + int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -- cgit v1.2.3 From 6c19d92361fe4afb26dfa5d48a0748b84bca6f12 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 17 Apr 2016 18:34:32 -0400 Subject: net: move whitelist functions into CConnman --- src/net.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index f20f63e04..eb312ef1e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -625,10 +625,7 @@ void CConnman::SetBannedSetDirty(bool dirty) } -std::vector CNode::vWhitelistedRange; -CCriticalSection CNode::cs_vWhitelistedRange; - -bool CNode::IsWhitelistedRange(const CNetAddr &addr) { +bool CConnman::IsWhitelistedRange(const CNetAddr &addr) { LOCK(cs_vWhitelistedRange); BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) { if (subnet.Match(addr)) @@ -637,7 +634,7 @@ bool CNode::IsWhitelistedRange(const CNetAddr &addr) { return false; } -void CNode::AddWhitelistedRange(const CSubNet &subnet) { +void CConnman::AddWhitelistedRange(const CSubNet &subnet) { LOCK(cs_vWhitelistedRange); vWhitelistedRange.push_back(subnet); } @@ -992,7 +989,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) LogPrintf("Warning: Unknown socket family\n"); - bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr); + bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr); { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) -- cgit v1.2.3 From 551e0887db9034b1e6490a267ba864b1d26ff469 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 17 Apr 2016 20:20:34 -0400 Subject: net: move nLastNodeId to CConnman --- src/net.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index eb312ef1e..8bc8ecc43 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -89,9 +89,6 @@ std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -NodeId nLastNodeId = 0; -CCriticalSection cs_nLastNodeId; - static CSemaphore *semOutbound = NULL; boost::condition_variable messageHandlerCondition; @@ -404,7 +401,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), hSocket, addrConnect, pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -1038,7 +1035,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), hSocket, addr, "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2030,6 +2027,7 @@ CConnman::CConnman() { setBannedIsDirty = false; fAddressesInitialized = false; + nLastNodeId = 0; } bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) @@ -2041,9 +2039,13 @@ bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& return ret; } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +NodeId CConnman::GetNewNodeId() { + return nLastNodeId.fetch_add(1, std::memory_order_relaxed); +} +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +{ uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2089,7 +2091,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2478,7 +2480,7 @@ void CNode::Fuzz(int nChance) unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); } unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); } -CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), @@ -2531,16 +2533,12 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa minFeeFilter = 0; lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; + id = idIn; BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; - { - LOCK(cs_nLastNodeId); - id = nLastNodeId++; - } - if (fLogIPs) LogPrint("net", "Added connection to %s peer=%d\n", addrName, id); else -- cgit v1.2.3 From 960cf2e4058a9c195bf64e1aecb46024f9ef022a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 17 Apr 2016 20:21:58 -0400 Subject: net: move nLocalHostNonce to CConnman This behavior seems to have been quite racy and broken. Move nLocalHostNonce into CNode, and check received nonces against all non-fully-connected nodes. If there's a match, assume we've connected to ourself. --- src/net.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8bc8ecc43..71b4b0168 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -83,7 +83,6 @@ CCriticalSection cs_mapLocalHost; std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; -uint64_t nLocalHostNonce = 0; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; std::string strSubVersion; @@ -346,6 +345,16 @@ CNode* CConnman::FindNode(const CService& addr) return NULL; } +bool CConnman::CheckIncomingNonce(uint64_t nonce) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { + if (!pnode->fSuccessfullyConnected && !pnode->fInbound && pnode->GetLocalNonce() == nonce) + return false; + } + return true; +} + CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) { if (pszDest == NULL) { @@ -465,7 +474,6 @@ void CNode::PushVersion() int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = GetLocalAddress(&addr); - GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); else @@ -2535,6 +2543,8 @@ CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::s nextSendTimeFeeFilter = 0; id = idIn; + GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); + BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; -- cgit v1.2.3 From ee44fa95761724a83a76dd862a36bd9af0fc021f Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 18 Apr 2016 21:33:54 -0400 Subject: net: move messageHandlerCondition to CConnman --- src/net.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 71b4b0168..a62ee2291 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -89,7 +89,6 @@ std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static CSemaphore *semOutbound = NULL; -boost::condition_variable messageHandlerCondition; // Signals for message handling static CNodeSignals g_signals; @@ -688,8 +687,9 @@ void CNode::copyStats(CNodeStats &stats) #undef X // requires LOCK(cs_vRecvMsg) -bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) +bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete) { + complete = false; while (nBytes > 0) { // get current incomplete message, or create a new one @@ -728,7 +728,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE; msg.nTime = GetTimeMicros(); - messageHandlerCondition.notify_one(); + complete = true; } } @@ -1247,8 +1247,11 @@ void CConnman::ThreadSocketHandler() int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); if (nBytes > 0) { - if (!pnode->ReceiveMsgBytes(pchBuf, nBytes)) + bool notify = false; + if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) pnode->CloseSocketDisconnect(); + if(notify) + messageHandlerCondition.notify_one(); pnode->nLastRecv = GetTime(); pnode->nRecvBytes += nBytes; pnode->RecordBytesRecv(nBytes); -- cgit v1.2.3 From adf5d4c2e4e7a2979a6ca6de806151fe04c23162 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 21 May 2016 12:04:02 +0200 Subject: net: SocketSendData returns written size --- src/net.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a62ee2291..aded8d05d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -791,9 +791,10 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes) // requires LOCK(cs_vSend) -void SocketSendData(CNode *pnode) +size_t SocketSendData(CNode *pnode) { std::deque::iterator it = pnode->vSendMsg.begin(); + size_t nSentSize = 0; while (it != pnode->vSendMsg.end()) { const CSerializeData &data = *it; @@ -804,6 +805,7 @@ void SocketSendData(CNode *pnode) pnode->nSendBytes += nBytes; pnode->nSendOffset += nBytes; pnode->RecordBytesSent(nBytes); + nSentSize += nBytes; if (pnode->nSendOffset == data.size()) { pnode->nSendOffset = 0; pnode->nSendSize -= data.size(); @@ -832,6 +834,7 @@ void SocketSendData(CNode *pnode) assert(pnode->nSendSize == 0); } pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it); + return nSentSize; } static std::list vNodesDisconnected; -- cgit v1.2.3 From 63cafa6329e1a0a1daf2d324931aca42ba1cbb19 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 18 Apr 2016 21:44:42 -0400 Subject: net: move send/recv statistics to CConnman --- src/net.cpp | 63 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 28 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index aded8d05d..0787b16ad 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -298,15 +298,6 @@ bool IsReachable(const CNetAddr& addr) return IsReachable(net); } -uint64_t CNode::nTotalBytesRecv = 0; -uint64_t CNode::nTotalBytesSent = 0; -CCriticalSection CNode::cs_totalBytesRecv; -CCriticalSection CNode::cs_totalBytesSent; - -uint64_t CNode::nMaxOutboundLimit = 0; -uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0; -uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day -uint64_t CNode::nMaxOutboundCycleStartTime = 0; CNode* CConnman::FindNode(const CNetAddr& ip) { @@ -804,7 +795,6 @@ size_t SocketSendData(CNode *pnode) pnode->nLastSend = GetTime(); pnode->nSendBytes += nBytes; pnode->nSendOffset += nBytes; - pnode->RecordBytesSent(nBytes); nSentSize += nBytes; if (pnode->nSendOffset == data.size()) { pnode->nSendOffset = 0; @@ -1176,9 +1166,15 @@ void CConnman::ThreadSocketHandler() // * We process a message in the buffer (message handler thread). { TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend && !pnode->vSendMsg.empty()) { - FD_SET(pnode->hSocket, &fdsetSend); - continue; + if (lockSend) { + if (pnode->nOptimisticBytesWritten) { + RecordBytesSent(pnode->nOptimisticBytesWritten); + pnode->nOptimisticBytesWritten = 0; + } + if (!pnode->vSendMsg.empty()) { + FD_SET(pnode->hSocket, &fdsetSend); + continue; + } } } { @@ -1257,7 +1253,7 @@ void CConnman::ThreadSocketHandler() messageHandlerCondition.notify_one(); pnode->nLastRecv = GetTime(); pnode->nRecvBytes += nBytes; - pnode->RecordBytesRecv(nBytes); + RecordBytesRecv(nBytes); } else if (nBytes == 0) { @@ -1289,8 +1285,11 @@ void CConnman::ThreadSocketHandler() if (FD_ISSET(pnode->hSocket, &fdsetSend)) { TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend) - SocketSendData(pnode); + if (lockSend) { + size_t nBytes = SocketSendData(pnode); + if (nBytes) + RecordBytesSent(nBytes); + } } // @@ -2060,6 +2059,13 @@ NodeId CConnman::GetNewNodeId() bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) { + nTotalBytesRecv = 0; + nTotalBytesSent = 0; + nMaxOutboundLimit = 0; + nMaxOutboundTotalBytesSentInCycle = 0; + nMaxOutboundTimeframe = 60*60*24; //1 day + nMaxOutboundCycleStartTime = 0; + uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2344,13 +2350,13 @@ void CConnman::RelayTransaction(const CTransaction& tx) } } -void CNode::RecordBytesRecv(uint64_t bytes) +void CConnman::RecordBytesRecv(uint64_t bytes) { LOCK(cs_totalBytesRecv); nTotalBytesRecv += bytes; } -void CNode::RecordBytesSent(uint64_t bytes) +void CConnman::RecordBytesSent(uint64_t bytes) { LOCK(cs_totalBytesSent); nTotalBytesSent += bytes; @@ -2367,7 +2373,7 @@ void CNode::RecordBytesSent(uint64_t bytes) nMaxOutboundTotalBytesSentInCycle += bytes; } -void CNode::SetMaxOutboundTarget(uint64_t limit) +void CConnman::SetMaxOutboundTarget(uint64_t limit) { LOCK(cs_totalBytesSent); uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SERIALIZED_SIZE; @@ -2377,19 +2383,19 @@ void CNode::SetMaxOutboundTarget(uint64_t limit) LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum); } -uint64_t CNode::GetMaxOutboundTarget() +uint64_t CConnman::GetMaxOutboundTarget() { LOCK(cs_totalBytesSent); return nMaxOutboundLimit; } -uint64_t CNode::GetMaxOutboundTimeframe() +uint64_t CConnman::GetMaxOutboundTimeframe() { LOCK(cs_totalBytesSent); return nMaxOutboundTimeframe; } -uint64_t CNode::GetMaxOutboundTimeLeftInCycle() +uint64_t CConnman::GetMaxOutboundTimeLeftInCycle() { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2403,7 +2409,7 @@ uint64_t CNode::GetMaxOutboundTimeLeftInCycle() return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime(); } -void CNode::SetMaxOutboundTimeframe(uint64_t timeframe) +void CConnman::SetMaxOutboundTimeframe(uint64_t timeframe) { LOCK(cs_totalBytesSent); if (nMaxOutboundTimeframe != timeframe) @@ -2415,7 +2421,7 @@ void CNode::SetMaxOutboundTimeframe(uint64_t timeframe) nMaxOutboundTimeframe = timeframe; } -bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) +bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2435,7 +2441,7 @@ bool CNode::OutboundTargetReached(bool historicalBlockServingLimit) return false; } -uint64_t CNode::GetOutboundTargetBytesLeft() +uint64_t CConnman::GetOutboundTargetBytesLeft() { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) @@ -2444,13 +2450,13 @@ uint64_t CNode::GetOutboundTargetBytesLeft() return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle; } -uint64_t CNode::GetTotalBytesRecv() +uint64_t CConnman::GetTotalBytesRecv() { LOCK(cs_totalBytesRecv); return nTotalBytesRecv; } -uint64_t CNode::GetTotalBytesSent() +uint64_t CConnman::GetTotalBytesSent() { LOCK(cs_totalBytesSent); return nTotalBytesSent; @@ -2548,6 +2554,7 @@ CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::s lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; id = idIn; + nOptimisticBytesWritten = 0; GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); @@ -2665,7 +2672,7 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) // If write queue empty, attempt "optimistic write" if (it == vSendMsg.begin()) - SocketSendData(this); + nOptimisticBytesWritten += SocketSendData(this); LEAVE_CRITICAL_SECTION(cs_vSend); } -- cgit v1.2.3 From be9c796dc51c05cab0b84d2e66c928973c6e5ed6 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 19 Apr 2016 00:01:19 -0400 Subject: net: move SendBufferSize/ReceiveFloodSize to CConnman --- src/net.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 0787b16ad..2839474cb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1181,7 +1181,7 @@ void CConnman::ThreadSocketHandler() TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv && ( pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() || - pnode->GetTotalRecvSize() <= ReceiveFloodSize())) + pnode->GetTotalRecvSize() <= GetReceiveFloodSize())) FD_SET(pnode->hSocket, &fdsetRecv); } } @@ -1851,7 +1851,7 @@ void CConnman::ThreadMessageHandler() if (!GetNodeSignals().ProcessMessages(pnode, *this)) pnode->CloseSocketDisconnect(); - if (pnode->nSendSize < SendBufferSize()) + if (pnode->nSendSize < GetSendBufferSize()) { if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg[0].complete())) { @@ -2041,6 +2041,8 @@ CConnman::CConnman() setBannedIsDirty = false; fAddressesInitialized = false; nLastNodeId = 0; + nSendBufferMaxSize = 0; + nReceiveFloodSize = 0; } bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) @@ -2066,6 +2068,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nMaxOutboundTimeframe = 60*60*24; //1 day nMaxOutboundCycleStartTime = 0; + nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); + nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2497,8 +2502,8 @@ void CNode::Fuzz(int nChance) Fuzz(2); } -unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); } -unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); } +unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } +unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), -- cgit v1.2.3 From bd72937dc462b86f0e84184b270a232f7bfaa8db Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 19 Apr 2016 00:04:58 -0400 Subject: net: move nLocalServices/nRelevantServices to CConnman These are in-turn passed to CNode at connection time. This allows us to offer different services to different peers (or test the effects of doing so). --- src/net.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 2839474cb..66e3d91f4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -69,15 +69,11 @@ namespace { const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; -/** Services this node implementation cares about */ -ServiceFlags nRelevantServices = NODE_NETWORK; - // // Global state variables // bool fDiscover = true; bool fListen = true; -ServiceFlags nLocalServices = NODE_NETWORK; bool fRelayTxes = true; CCriticalSection cs_mapLocalHost; std::map mapLocalHost; @@ -155,7 +151,7 @@ static std::vector convertSeed6(const std::vector &vSeedsIn // Otherwise, return the unroutable 0.0.0.0 but filled in with // the normal parameters, since the IP may be changed to a useful // one by discovery. -CAddress GetLocalAddress(const CNetAddr *paddrPeer) +CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) { CAddress ret(CService(CNetAddr(),GetListenPort()), NODE_NONE); CService addr; @@ -187,7 +183,7 @@ void AdvertiseLocal(CNode *pnode) { if (fListen && pnode->fSuccessfullyConnected) { - CAddress addrLocal = GetLocalAddress(&pnode->addr); + CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices()); // If discovery is enabled, sometimes give our peer the address it // tells us that it sees us as in case it has a better idea of our // address than we do. @@ -400,7 +396,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(GetNewNodeId(), hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, hSocket, addrConnect, pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -463,7 +459,7 @@ void CNode::PushVersion() int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); - CAddress addrMe = GetLocalAddress(&addr); + CAddress addrMe = GetLocalAddress(&addr, nLocalServices); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); else @@ -1036,7 +1032,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(GetNewNodeId(), hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, hSocket, addr, "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2045,11 +2041,11 @@ CConnman::CConnman() nReceiveFloodSize = 0; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, std::string& strNodeError) { Discover(threadGroup); - bool ret = connman.Start(threadGroup, scheduler, strNodeError); + bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, strNodeError); return ret; } @@ -2059,13 +2055,15 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, std::string& strNodeError) { nTotalBytesRecv = 0; nTotalBytesSent = 0; nMaxOutboundLimit = 0; nMaxOutboundTotalBytesSentInCycle = 0; nMaxOutboundTimeframe = 60*60*24; //1 day + nLocalServices = nLocalServicesIn; + nRelevantServices = nRelevantServicesIn; nMaxOutboundCycleStartTime = 0; nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); @@ -2116,7 +2114,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(GetNewNodeId(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2467,6 +2465,11 @@ uint64_t CConnman::GetTotalBytesSent() return nTotalBytesSent; } +ServiceFlags CConnman::GetLocalServices() const +{ + return nLocalServices; +} + void CNode::Fuzz(int nChance) { if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake @@ -2505,7 +2508,7 @@ void CNode::Fuzz(int nChance) unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } -CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), @@ -2560,6 +2563,7 @@ CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress& addrIn, const std::s nextSendTimeFeeFilter = 0; id = idIn; nOptimisticBytesWritten = 0; + nLocalServices = nLocalServicesIn; GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); -- cgit v1.2.3 From 8a593694b1495656411717fbae5d3167576df973 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 19 Apr 2016 00:15:52 -0400 Subject: net: move semOutbound to CConnman --- src/net.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 66e3d91f4..853c0cdd6 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -84,8 +84,6 @@ std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); -static CSemaphore *semOutbound = NULL; - // Signals for message handling static CNodeSignals g_signals; CNodeSignals& GetNodeSignals() { return g_signals; } @@ -2039,6 +2037,7 @@ CConnman::CConnman() nLastNodeId = 0; nSendBufferMaxSize = 0; nReceiveFloodSize = 0; + semOutbound = NULL; } bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, std::string& strNodeError) -- cgit v1.2.3 From fdf69ff21aef8ed8071a757979f4239537f7afba Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sun, 22 May 2016 09:52:03 +0200 Subject: net: move max/max-outbound to CConnman --- src/net.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 853c0cdd6..fe4daaaeb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -63,7 +63,6 @@ namespace { - const int MAX_OUTBOUND_CONNECTIONS = 8; const int MAX_FEELER_CONNECTIONS = 1; } @@ -79,7 +78,6 @@ CCriticalSection cs_mapLocalHost; std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; -int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); @@ -974,7 +972,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; - int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); + int nMaxInbound = nMaxConnections - (nMaxOutbound + MAX_FEELER_CONNECTIONS); assert(nMaxInbound > 0); if (hSocket != INVALID_SOCKET) @@ -1626,7 +1624,7 @@ void CConnman::ThreadOpenConnections() } } } - assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS)); + assert(nOutbound <= (nMaxOutbound + MAX_FEELER_CONNECTIONS)); // Feeler Connections // @@ -1641,7 +1639,7 @@ void CConnman::ThreadOpenConnections() // * Only make a feeler connection once every few minutes. // bool fFeeler = false; - if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) { + if (nOutbound >= nMaxOutbound) { int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds). if (nTime > nNextFeeler) { nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL); @@ -2038,13 +2036,15 @@ CConnman::CConnman() nSendBufferMaxSize = 0; nReceiveFloodSize = 0; semOutbound = NULL; + nMaxConnections = 0; + nMaxOutbound = 0; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, std::string& strNodeError) +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError) { Discover(threadGroup); - bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, strNodeError); + bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, strNodeError); return ret; } @@ -2054,7 +2054,7 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError) { nTotalBytesRecv = 0; nTotalBytesSent = 0; @@ -2065,6 +2065,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se nRelevantServices = nRelevantServicesIn; nMaxOutboundCycleStartTime = 0; + nMaxConnections = nMaxConnectionsIn; + nMaxOutbound = std::min((nMaxOutboundIn), nMaxConnections); + nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); @@ -2106,8 +2109,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections); - semOutbound = new CSemaphore(nMaxOutbound); + semOutbound = new CSemaphore(std::min((nMaxOutbound + MAX_FEELER_CONNECTIONS), nMaxConnections)); } if (pnodeLocalHost == NULL) { @@ -2174,7 +2176,7 @@ instance_of_cnetcleanup; void CConnman::Stop() { if (semOutbound) - for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) + for (int i=0; i<(nMaxOutbound + MAX_FEELER_CONNECTIONS); i++) semOutbound->post(); if (fAddressesInitialized) -- cgit v1.2.3 From f60b9059e4958245bda82e9656c52a31d5268ad9 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 24 May 2016 16:42:17 -0400 Subject: net: Pass best block known height into CConnman CConnman then passes the current best height into CNode at creation time. This way CConnman/CNode have no dependency on main for height, and the signals only move in one direction. This also helps to prevent identity leakage a tiny bit. Before this change, an attacker could theoretically make 2 connections on different interfaces. They would connect fully on one, and only establish the initial connection on the other. Once they receive a new block, they would relay it to your first connection, and immediately commence the version handshake on the second. Since the new block height is reflected immediately, they could attempt to learn whether the two connections were correlated. This is, of course, incredibly unlikely to work due to the small timings involved and receipt from other senders. But it doesn't hurt to lock-in nBestHeight at the time of connection, rather than letting the remote choose the time. --- src/net.cpp | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index fe4daaaeb..d51095255 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -392,7 +392,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -451,17 +451,15 @@ void CNode::CloseSocketDisconnect() void CNode::PushVersion() { - int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0); - int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = GetLocalAddress(&addr, nLocalServices); if (fLogIPs) - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); + LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id); else - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); + LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), id); PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes); + nLocalHostNonce, strSubVersion, nMyStartingHeight, ::fRelayTxes); } @@ -1028,7 +1026,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2038,13 +2036,14 @@ CConnman::CConnman() semOutbound = NULL; nMaxConnections = 0; nMaxOutbound = 0; + nBestHeight = 0; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError) +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError) { Discover(threadGroup); - bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, strNodeError); + bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, nBestHeightIn, strNodeError); return ret; } @@ -2054,7 +2053,7 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError) { nTotalBytesRecv = 0; nTotalBytesSent = 0; @@ -2071,6 +2070,8 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + SetBestHeight(nBestHeightIn); + uiInterface.InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2115,7 +2116,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2471,6 +2472,16 @@ ServiceFlags CConnman::GetLocalServices() const return nLocalServices; } +void CConnman::SetBestHeight(int height) +{ + nBestHeight.store(height, std::memory_order_release); +} + +int CConnman::GetBestHeight() const +{ + return nBestHeight.load(std::memory_order_acquire); +} + void CNode::Fuzz(int nChance) { if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake @@ -2509,7 +2520,7 @@ void CNode::Fuzz(int nChance) unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), @@ -2567,6 +2578,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const nLocalServices = nLocalServicesIn; GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); + nMyStartingHeight = nMyStartingHeightIn; BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; -- cgit v1.2.3 From e81a602cf02edfb21c3ec097bd7cf71f189ed783 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 25 May 2016 21:26:46 -0400 Subject: net: pass CClientUIInterface into CConnman --- src/net.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index d51095255..13218b422 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -474,7 +474,8 @@ void CConnman::ClearBanned() setBannedIsDirty = true; } DumpBanlist(); //store banlist to disk - uiInterface.BannedListChanged(); + if(clientInterface) + clientInterface->BannedListChanged(); } bool CConnman::IsBanned(CNetAddr ip) @@ -534,7 +535,8 @@ void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t ba else return; } - uiInterface.BannedListChanged(); + if(clientInterface) + clientInterface->BannedListChanged(); { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { @@ -558,7 +560,8 @@ bool CConnman::Unban(const CSubNet &subNet) { return false; setBannedIsDirty = true; } - uiInterface.BannedListChanged(); + if(clientInterface) + clientInterface->BannedListChanged(); DumpBanlist(); //store banlist to disk immediately return true; } @@ -1104,7 +1107,8 @@ void CConnman::ThreadSocketHandler() } if(vNodes.size() != nPrevNodeCount) { nPrevNodeCount = vNodes.size(); - uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount); + if(clientInterface) + clientInterface->NotifyNumConnectionsChanged(nPrevNodeCount); } // @@ -2037,13 +2041,14 @@ CConnman::CConnman() nMaxConnections = 0; nMaxOutbound = 0; nBestHeight = 0; + clientInterface = NULL; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError) +bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError) { Discover(threadGroup); - bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, nBestHeightIn, strNodeError); + bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, nBestHeightIn, interfaceIn, strNodeError); return ret; } @@ -2053,7 +2058,7 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError) { nTotalBytesRecv = 0; nTotalBytesSent = 0; @@ -2072,7 +2077,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se SetBestHeight(nBestHeightIn); - uiInterface.InitMessage(_("Loading addresses...")); + clientInterface = interfaceIn; + if (clientInterface) + clientInterface->InitMessage(_("Loading addresses...")); // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); { @@ -2085,8 +2092,8 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se DumpAddresses(); } } - - uiInterface.InitMessage(_("Loading banlist...")); + if (clientInterface) + clientInterface->InitMessage(_("Loading banlist...")); // Load addresses from banlist.dat nStart = GetTimeMillis(); CBanDB bandb; -- cgit v1.2.3 From bafa5fc5a1ba33337b5eb3d8ae24ba2fac2949f8 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 26 May 2016 23:29:39 -0400 Subject: net: Drop StartNode/StopNode and use CConnman directly --- src/net.cpp | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 13218b422..15c066cd7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1979,7 +1979,7 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b return true; } -void static Discover(boost::thread_group& threadGroup) +void Discover(boost::thread_group& threadGroup) { if (!fDiscover) return; @@ -2044,15 +2044,6 @@ CConnman::CConnman() clientInterface = NULL; } -bool StartNode(CConnman& connman, boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServices, ServiceFlags nRelevantServices, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError) -{ - Discover(threadGroup); - - bool ret = connman.Start(threadGroup, scheduler, nLocalServices, nRelevantServices, nMaxConnectionsIn, nMaxOutboundIn, nBestHeightIn, interfaceIn, strNodeError); - - return ret; -} - NodeId CConnman::GetNewNodeId() { return nLastNodeId.fetch_add(1, std::memory_order_relaxed); @@ -2136,9 +2127,6 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se else threadGroup.create_thread(boost::bind(&TraceThread >, "dnsseed", boost::function(boost::bind(&CConnman::ThreadDNSAddressSeed, this)))); - // Map ports with UPnP - MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); - // Send and receive from sockets, accept connections threadGroup.create_thread(boost::bind(&TraceThread >, "net", boost::function(boost::bind(&CConnman::ThreadSocketHandler, this)))); @@ -2157,15 +2145,6 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, Se return true; } -bool StopNode(CConnman& connman) -{ - LogPrintf("StopNode()\n"); - MapPort(false); - - connman.Stop(); - return true; -} - class CNetCleanup { public: @@ -2183,6 +2162,7 @@ instance_of_cnetcleanup; void CConnman::Stop() { + LogPrintf("%s\n",__func__); if (semOutbound) for (int i=0; i<(nMaxOutbound + MAX_FEELER_CONNECTIONS); i++) semOutbound->post(); -- cgit v1.2.3 From a19553b992f40b9f98e6e0be4cd529a89746ef50 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 26 May 2016 23:53:08 -0400 Subject: net: Introduce CConnection::Options to avoid passing so many params --- src/net.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 15c066cd7..8ea600b37 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2049,26 +2049,26 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, ServiceFlags nLocalServicesIn, ServiceFlags nRelevantServicesIn, int nMaxConnectionsIn, int nMaxOutboundIn, int nBestHeightIn, CClientUIInterface* interfaceIn, std::string& strNodeError) +bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options connOptions) { nTotalBytesRecv = 0; nTotalBytesSent = 0; nMaxOutboundLimit = 0; nMaxOutboundTotalBytesSentInCycle = 0; nMaxOutboundTimeframe = 60*60*24; //1 day - nLocalServices = nLocalServicesIn; - nRelevantServices = nRelevantServicesIn; nMaxOutboundCycleStartTime = 0; - nMaxConnections = nMaxConnectionsIn; - nMaxOutbound = std::min((nMaxOutboundIn), nMaxConnections); + nRelevantServices = connOptions.nRelevantServices; + nLocalServices = connOptions.nLocalServices; + nMaxConnections = connOptions.nMaxConnections; + nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); - SetBestHeight(nBestHeightIn); + SetBestHeight(connOptions.nBestHeight); - clientInterface = interfaceIn; + clientInterface = connOptions.uiInterface; if (clientInterface) clientInterface->InitMessage(_("Loading addresses...")); // Load addresses from peers.dat -- cgit v1.2.3 From fa2f8bc47fa17deccb281b750ff6c48402c5b1ce Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 27 May 2016 00:00:02 -0400 Subject: net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8ea600b37..9b18a3274 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2063,8 +2063,8 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); - nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); - nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + nSendBufferMaxSize = connOptions.nSendBufferMaxSize; + nReceiveFloodSize = connOptions.nSendBufferMaxSize; SetBestHeight(connOptions.nBestHeight); -- cgit v1.2.3 From 98591c50273b13cfc5419548b527280d6a84a43d Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 27 May 2016 01:00:01 -0400 Subject: net: move vNodesDisconnected into CConnman --- src/net.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 9b18a3274..508b0dd96 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -820,8 +820,6 @@ size_t SocketSendData(CNode *pnode) return nSentSize; } -static std::list vNodesDisconnected; - struct NodeEvictionCandidate { NodeId id; -- cgit v1.2.3 From d1a2295f0d58423652b124b48fc887a9721b765c Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Wed, 15 Jun 2016 19:28:04 -0400 Subject: Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting --- src/net.cpp | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 508b0dd96..bf5cc07db 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2697,7 +2697,7 @@ bool CConnman::ForNode(NodeId id, std::function func) return found != nullptr && func(found); } -bool CConnman::ForEachNode(std::function func) +bool CConnman::ForEachNodeContinueIf(std::function func) { LOCK(cs_vNodes); for (auto&& node : vNodes) @@ -2706,7 +2706,7 @@ bool CConnman::ForEachNode(std::function func) return true; } -bool CConnman::ForEachNode(std::function func) const +bool CConnman::ForEachNodeContinueIf(std::function func) const { LOCK(cs_vNodes); for (const auto& node : vNodes) @@ -2715,7 +2715,7 @@ bool CConnman::ForEachNode(std::function func) const return true; } -bool CConnman::ForEachNodeThen(std::function pre, std::function post) +bool CConnman::ForEachNodeContinueIfThen(std::function pre, std::function post) { bool ret = true; LOCK(cs_vNodes); @@ -2728,7 +2728,7 @@ bool CConnman::ForEachNodeThen(std::function pre, std::funct return ret; } -bool CConnman::ForEachNodeThen(std::function pre, std::function post) const +bool CConnman::ForEachNodeContinueIfThen(std::function pre, std::function post) const { bool ret = true; LOCK(cs_vNodes); @@ -2741,6 +2741,35 @@ bool CConnman::ForEachNodeThen(std::function pre, std: return ret; } +void CConnman::ForEachNode(std::function func) +{ + LOCK(cs_vNodes); + for (auto&& node : vNodes) + func(node); +} + +void CConnman::ForEachNode(std::function func) const +{ + LOCK(cs_vNodes); + for (const auto& node : vNodes) + func(node); +} + +void CConnman::ForEachNodeThen(std::function pre, std::function post) +{ + LOCK(cs_vNodes); + for (auto&& node : vNodes) + pre(node); + post(); +} + +void CConnman::ForEachNodeThen(std::function pre, std::function post) const +{ + LOCK(cs_vNodes); + for (const auto& node : vNodes) + pre(node); + post(); +} int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -- cgit v1.2.3 From e700cd0bc885340563df9e6b7a5b6c6603b8c984 Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Sun, 19 Jun 2016 21:42:15 -0400 Subject: Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead --- src/net.cpp | 73 ------------------------------------------------------------- 1 file changed, 73 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index bf5cc07db..19c14e105 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2697,79 +2697,6 @@ bool CConnman::ForNode(NodeId id, std::function func) return found != nullptr && func(found); } -bool CConnman::ForEachNodeContinueIf(std::function func) -{ - LOCK(cs_vNodes); - for (auto&& node : vNodes) - if(!func(node)) - return false; - return true; -} - -bool CConnman::ForEachNodeContinueIf(std::function func) const -{ - LOCK(cs_vNodes); - for (const auto& node : vNodes) - if(!func(node)) - return false; - return true; -} - -bool CConnman::ForEachNodeContinueIfThen(std::function pre, std::function post) -{ - bool ret = true; - LOCK(cs_vNodes); - for (auto&& node : vNodes) - if(!pre(node)) { - ret = false; - break; - } - post(); - return ret; -} - -bool CConnman::ForEachNodeContinueIfThen(std::function pre, std::function post) const -{ - bool ret = true; - LOCK(cs_vNodes); - for (const auto& node : vNodes) - if(!pre(node)) { - ret = false; - break; - } - post(); - return ret; -} - -void CConnman::ForEachNode(std::function func) -{ - LOCK(cs_vNodes); - for (auto&& node : vNodes) - func(node); -} - -void CConnman::ForEachNode(std::function func) const -{ - LOCK(cs_vNodes); - for (const auto& node : vNodes) - func(node); -} - -void CConnman::ForEachNodeThen(std::function pre, std::function post) -{ - LOCK(cs_vNodes); - for (auto&& node : vNodes) - pre(node); - post(); -} - -void CConnman::ForEachNodeThen(std::function pre, std::function post) const -{ - LOCK(cs_vNodes); - for (const auto& node : vNodes) - pre(node); - post(); -} int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -- cgit v1.2.3 From 0103c5b90fa61b5d159a825fcb5a05ca31d0d1c3 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 31 Aug 2016 13:17:28 -0400 Subject: net: move MAX_FEELER_CONNECTIONS into connman --- src/net.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 19c14e105..b39ef9f54 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -61,11 +61,6 @@ #endif #endif - -namespace { - const int MAX_FEELER_CONNECTIONS = 1; -} - const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; // @@ -971,7 +966,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; - int nMaxInbound = nMaxConnections - (nMaxOutbound + MAX_FEELER_CONNECTIONS); + int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler); assert(nMaxInbound > 0); if (hSocket != INVALID_SOCKET) @@ -1624,7 +1619,7 @@ void CConnman::ThreadOpenConnections() } } } - assert(nOutbound <= (nMaxOutbound + MAX_FEELER_CONNECTIONS)); + assert(nOutbound <= (nMaxOutbound + nMaxFeeler)); // Feeler Connections // @@ -2060,6 +2055,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nLocalServices = connOptions.nLocalServices; nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); + nMaxFeeler = connOptions.nMaxFeeler; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; nReceiveFloodSize = connOptions.nSendBufferMaxSize; @@ -2106,7 +2102,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (semOutbound == NULL) { // initialize semaphore - semOutbound = new CSemaphore(std::min((nMaxOutbound + MAX_FEELER_CONNECTIONS), nMaxConnections)); + semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); } if (pnodeLocalHost == NULL) { @@ -2162,7 +2158,7 @@ void CConnman::Stop() { LogPrintf("%s\n",__func__); if (semOutbound) - for (int i=0; i<(nMaxOutbound + MAX_FEELER_CONNECTIONS); i++) + for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) semOutbound->post(); if (fAddressesInitialized) -- cgit v1.2.3 From 1b6bcdd3aa379a50c960e23d7c55db8294e76f7f Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 13 Sep 2016 18:08:17 +0200 Subject: Remove maxuploadtargets recommended minimum --- src/net.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b39ef9f54..888ed4437 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2362,11 +2362,7 @@ void CConnman::RecordBytesSent(uint64_t bytes) void CConnman::SetMaxOutboundTarget(uint64_t limit) { LOCK(cs_totalBytesSent); - uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SERIALIZED_SIZE; nMaxOutboundLimit = limit; - - if (limit > 0 && limit < recommendedMinimum) - LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum); } uint64_t CConnman::GetMaxOutboundTarget() -- cgit v1.2.3 From 36fa01f217fbc32afb90314fd257650c71a47045 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 13 Sep 2016 14:42:55 -0400 Subject: net: only delete CConnman if it's been created In the case of (for example) an already-running bitcoind, the shutdown sequence begins before CConnman has been created, leading to a null-pointer dereference when g_connman->Stop() is called. Instead, Just let the CConnman dtor take care of stopping. --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b39ef9f54..30513a3b9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2205,6 +2205,7 @@ void CConnman::DeleteNode(CNode* pnode) CConnman::~CConnman() { + Stop(); } size_t CConnman::GetAddressCount() const -- cgit v1.2.3 From f3552da81393a8e78ce3e2afed0b9c9d1ff5cee0 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 12 Sep 2016 15:04:20 -0400 Subject: net: fix maxuploadtarget setting This was broken by 63cafa6329e1a. Note that while this fixes the settings, it doesn't fix the actual usage of -maxuploadtarget completely, as there is currently a bug in the nOptimisticBytesWritten accounting that causes a delayed response if the target is reached. That bug will be addressed separately. --- src/net.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cc9728b85..ac64b28ea 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2046,9 +2046,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st { nTotalBytesRecv = 0; nTotalBytesSent = 0; - nMaxOutboundLimit = 0; nMaxOutboundTotalBytesSentInCycle = 0; - nMaxOutboundTimeframe = 60*60*24; //1 day nMaxOutboundCycleStartTime = 0; nRelevantServices = connOptions.nRelevantServices; @@ -2060,6 +2058,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nSendBufferMaxSize = connOptions.nSendBufferMaxSize; nReceiveFloodSize = connOptions.nSendBufferMaxSize; + nMaxOutboundLimit = connOptions.nMaxOutboundLimit; + nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; + SetBestHeight(connOptions.nBestHeight); clientInterface = connOptions.uiInterface; -- cgit v1.2.3 From d9c99c3058c90f4f7075cf5c495b8dcd2e7519a7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 15 Sep 2016 23:32:45 +0200 Subject: net: No longer send local address in addrMe After #8594 the addrFrom sent by a node is not used anymore at all, so don't bother sending it. Also mitigates the privacy issue in (#8616). It doesn't completely solve the issue as GetLocalAddress is also called in AdvertiseLocal, but at least when advertising addresses it stands out less as *our* address. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cc9728b85..38b1e7926 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -448,7 +448,7 @@ void CNode::PushVersion() { int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); - CAddress addrMe = GetLocalAddress(&addr, nLocalServices); + CAddress addrMe = CAddress(CService(), nLocalServices); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id); else -- cgit v1.2.3 From d9ff591d42158e8a0a4ebdcf5fbb74978c483202 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 9 Sep 2016 12:48:10 +0200 Subject: Move static global randomizer seeds into CConnman --- src/net.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 38b1e7926..5863f9d3f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -63,6 +63,7 @@ const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; +static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8] // // Global state variables // @@ -387,7 +388,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -1022,7 +1023,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2023,7 +2024,7 @@ void Discover(boost::thread_group& threadGroup) #endif } -CConnman::CConnman() +CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In) { setBannedIsDirty = false; fAddressesInitialized = false; @@ -2108,7 +2109,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2498,10 +2499,10 @@ void CNode::Fuzz(int nChance) 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, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), - nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), + nKeyedNetGroup(nKeyedNetGroupIn), addrKnown(5000, 0.001), filterInventoryKnown(50000, 0.000001) { @@ -2694,12 +2695,14 @@ int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -/* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad) +CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) { - static const uint64_t k0 = GetRand(std::numeric_limits::max()); - static const uint64_t k1 = GetRand(std::numeric_limits::max()); + return CSipHasher(nSeed0, nSeed1).Write(id); +} +uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) +{ std::vector vchNetGroup(ad.GetGroup()); - return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); + return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); } -- cgit v1.2.3 From 41e58faf043864a64a6db08a8df527fa5fd1ec5b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 27 Sep 2016 14:05:24 +0200 Subject: net: Consistent checksum handling In principle, the checksums of P2P packets are simply 4-byte blobs which are the first four bytes of SHA256(SHA256(payload)). Currently they are handled as little-endian 32-bit integers half of the time, as blobs the other half, sometimes copying the one to the other, resulting in somewhat confused code. This PR changes the handling to be consistent both at packet creation and receiving, making it (I think) easier to understand. --- src/net.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cce06f2d6..770e2d295 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2661,10 +2661,8 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) // Set the checksum uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); - unsigned int nChecksum = 0; - memcpy(&nChecksum, &hash, sizeof(nChecksum)); - assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); - memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum)); + assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + CMessageHeader::CHECKSUM_SIZE); + memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE); LogPrint("net", "(%d bytes) peer=%d\n", nSize, id); -- cgit v1.2.3 From cb78c60534e5be205f9190cb0cde700f9e9fa38d Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 4 Oct 2016 19:27:11 -0400 Subject: gui: fix ban from qt console Rather than doing a circle and re-resolving the node's IP, just use the one from nodestats directly. This requires syncing the addr field from CNode. --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 770e2d295..19dd04099 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -629,6 +629,7 @@ void CNode::copyStats(CNodeStats &stats) { stats.nodeid = this->GetId(); X(nServices); + X(addr); X(fRelayTxes); X(nLastSend); X(nLastRecv); -- cgit v1.2.3 From 1724a405c9065f2c939e936aca9b5d37fca5e954 Mon Sep 17 00:00:00 2001 From: R E Broadley Date: Fri, 14 Oct 2016 21:11:38 +0700 Subject: Display minimum ping in debug window. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 19dd04099..0f719a9c7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -659,7 +659,7 @@ void CNode::copyStats(CNodeStats &stats) // Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :) stats.dPingTime = (((double)nPingUsecTime) / 1e6); - stats.dPingMin = (((double)nMinPingUsecTime) / 1e6); + stats.dMinPing = (((double)nMinPingUsecTime) / 1e6); stats.dPingWait = (((double)nPingUsecWait) / 1e6); // Leave string empty if addrLocal invalid (not filled in yet) -- cgit v1.2.3 From 5eaaa83ac1f5eb525f93e2808fafd73f5ed97013 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 13 Oct 2016 16:19:20 +0200 Subject: Kill insecure_random and associated global state There are only a few uses of `insecure_random` outside the tests. This PR replaces uses of insecure_random (and its accompanying global state) in the core code with an FastRandomContext that is automatically seeded on creation. This is meant to be used for inner loops. The FastRandomContext can be in the outer scope, or the class itself, then rand32() is used inside the loop. Useful e.g. for pushing addresses in CNode or the fee rounding, or randomization for coin selection. As a context is created per purpose, thus it gets rid of cross-thread unprotected shared usage of a single set of globals, this should also get rid of the potential race conditions. - I'd say TxMempool::check is not called enough to warrant using a special fast random context, this is switched to GetRand() (open for discussion...) - The use of `insecure_rand` in ConnectThroughProxy has been replaced by an atomic integer counter. The only goal here is to have a different credentials pair for each connection to go on a different Tor circuit, it does not need to be random nor unpredictable. - To avoid having a FastRandomContext on every CNode, the context is passed into PushAddress as appropriate. There remains an insecure_random for test usage in `test_random.h`. --- src/net.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 19dd04099..643dd806d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -187,7 +187,8 @@ void AdvertiseLocal(CNode *pnode) if (addrLocal.IsRoutable()) { LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); - pnode->PushAddress(addrLocal); + FastRandomContext insecure_rand; + pnode->PushAddress(addrLocal, insecure_rand); } } } -- cgit v1.2.3 From 504c72ad346a1b619f1fc58d0edce91ec955a67d Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 17 Oct 2016 11:25:25 -0400 Subject: Comment that most dnsseeds only support some service bits combos --- src/net.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 19dd04099..5f9942c9d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1454,6 +1454,7 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe return data.host; } + // See chainparams.cpp, most dnsseeds only support one or two possible servicebits hostnames return strprintf("x%x.%s", *requiredServiceBits, data.host); } -- cgit v1.2.3 From 1ab21cf344ed0547de5ae679b7e479cb4b1a923b Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 17 Oct 2016 16:29:03 -0400 Subject: Remove bogus assert on number of oubound connections. This value can be significantly higher if the users uses addnode --- src/net.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 5f9942c9d..cdd3076a2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1622,7 +1622,6 @@ void CConnman::ThreadOpenConnections() } } } - assert(nOutbound <= (nMaxOutbound + nMaxFeeler)); // Feeler Connections // -- cgit v1.2.3 From 9583477288072e203541b747fcffe8d50cfefb8d Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 17 Oct 2016 23:08:52 +0000 Subject: Be more aggressive in connecting to peers with relevant services. Only allow skipping relevant services until there are four outbound connections up. This avoids quickly filling up with peers lacking the relevant services when addrman has few or none of them. --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 5f9942c9d..de8f8184a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1675,8 +1675,8 @@ void CConnman::ThreadOpenConnections() if (nANow - addr.nLastTry < 600 && nTries < 30) continue; - // only consider nodes missing relevant services after 40 failed attempts - if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40) + // only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up. + if ((addr.nServices & nRelevantServices) != nRelevantServices && (nTries < 40 || nOutbound >= (nMaxOutbound >> 1))) continue; // do not allow non-default ports, unless after 50 invalid addresses selected already -- cgit v1.2.3 From 46304791353d2bb61004a035869612620c30b4eb Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 17 Oct 2016 23:11:35 +0000 Subject: Make dnsseed's definition of acute need include relevant services. We normally prefer to connect to peers offering the relevant services. If we're not connected to enough peers with relevant services, we probably don't know about them and could use dnsseed's help. --- src/net.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index de8f8184a..99f5604ff 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1462,12 +1462,19 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe void CConnman::ThreadDNSAddressSeed() { // goal: only query DNS seeds if address need is acute + // Avoiding DNS seeds when we don't need them improves user privacy by + // 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))) { MilliSleep(11 * 1000); LOCK(cs_vNodes); - if (vNodes.size() >= 2) { + int nRelevant = 0; + for (auto pnode : vNodes) { + nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices); + } + if (nRelevant >= 2) { LogPrintf("P2P peers available. Skipped DNS seeding.\n"); return; } -- cgit v1.2.3 From 7c9a98aac843c9efabd8653caebc35e968b2f335 Mon Sep 17 00:00:00 2001 From: Jon Lund Steffensen Date: Tue, 26 Mar 2013 02:33:25 +0100 Subject: Allow network activity to be temporarily suspended. Added the function SetNetworkActive() which when called with argument set to false disconnects all nodes and sets the flag fNetworkActive to false. As long as this flag is false no new connections are attempted and no incoming connections are accepted. Network activity is reenabled by calling the function with argument true. --- src/net.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index cce06f2d6..973e278e0 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -990,6 +990,12 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { return; } + if (!fNetworkActive) { + LogPrintf("connection from %s dropped: not accepting new connections\n", addr.ToString()); + CloseSocket(hSocket); + return; + } + if (!IsSelectableSocket(hSocket)) { LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString()); @@ -1783,6 +1789,9 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai // Initiate outbound network connection // boost::this_thread::interruption_point(); + if (!fNetworkActive) { + return false; + } if (!pszDest) { if (IsLocal(addrConnect) || FindNode((CNetAddr)addrConnect) || IsBanned(addrConnect) || @@ -2024,8 +2033,28 @@ void Discover(boost::thread_group& threadGroup) #endif } +void CConnman::SetNetworkActive(bool active) +{ + if (fDebug) { + LogPrint("net", "SetNetworkActive: %s\n", active); + } + + if (!active) { + fNetworkActive = false; + + LOCK(cs_vNodes); + // Close sockets to all nodes + BOOST_FOREACH(CNode* pnode, vNodes) { + pnode->CloseSocketDisconnect(); + } + } else { + fNetworkActive = true; + } +} + CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In) { + fNetworkActive = true; setBannedIsDirty = false; fAddressesInitialized = false; nLastNodeId = 0; -- cgit v1.2.3 From 32efa79e0e63b6d3f055326b2e6b794815d408ad Mon Sep 17 00:00:00 2001 From: Jon Lund Steffensen Date: Tue, 26 Mar 2013 03:07:06 +0100 Subject: Qt: Add GUI feedback and control of network activity state. Add getNetworkActive()/setNetworkActive() method to client model. Send network active status through NotifyNetworkActiveChanged. Indicate in tool tip of gui status bar network indicator whether network activity is disabled. Indicate in debug window whether network activity is disabled and add button to allow user to toggle network activity state. --- src/net.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 973e278e0..7c5e00c6f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2050,6 +2050,8 @@ void CConnman::SetNetworkActive(bool active) } else { fNetworkActive = true; } + + uiInterface.NotifyNetworkActiveChanged(fNetworkActive); } CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In) -- cgit v1.2.3 From fa1c3c2eb0a1853ed0e0662fc2bdbca51e05ccf5 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 24 Oct 2016 21:38:20 +0200 Subject: [net] Remove assert(nMaxInbound > 0) nMaxInbound might very well be 0 or -1, if the user prefers to keep a small number of maxconnections. Note: nMaxInbound of -1 means that the user set maxconnections to 8 or less, but we still want to keep an additional slot for the feeler connection. --- src/net.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 1bca168d1..83a85dfbd 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -970,7 +970,6 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { CAddress addr; int nInbound = 0; int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler); - assert(nMaxInbound > 0); if (hSocket != INVALID_SOCKET) if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) -- cgit v1.2.3 From 515e2642eb45bda56156b1213b25fb4886d3fdbe Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 24 Oct 2016 01:21:04 +0000 Subject: Make connect=0 disable automatic outbound connections. Otherwise it just responds to this obvious bit of configuration by trying to connect to "0" in a loop. --- src/net.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 1bca168d1..953377a9f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2138,8 +2138,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st // Initiate outbound connections from -addnode threadGroup.create_thread(boost::bind(&TraceThread >, "addcon", boost::function(boost::bind(&CConnman::ThreadOpenAddedConnections, this)))); - // Initiate outbound connections - threadGroup.create_thread(boost::bind(&TraceThread >, "opencon", boost::function(boost::bind(&CConnman::ThreadOpenConnections, this)))); + // Initiate outbound connections unless connect=0 + if (!mapArgs.count("-connect") || mapMultiArgs["-connect"].size() != 1 || mapMultiArgs["-connect"][0] != "0") + threadGroup.create_thread(boost::bind(&TraceThread >, "opencon", boost::function(boost::bind(&CConnman::ThreadOpenConnections, this)))); // Process messages threadGroup.create_thread(boost::bind(&TraceThread >, "msghand", boost::function(boost::bind(&CConnman::ThreadMessageHandler, this)))); -- cgit v1.2.3 From fe1dc62cef88280d2490a619beded052f313c6fc Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sun, 30 Oct 2016 18:02:16 -0400 Subject: Hash P2P messages as they are received instead of at process-time --- src/net.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 48ba9588d..a2414acf4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -758,12 +758,21 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes) vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024)); } + hasher.Write((const unsigned char*)pch, nCopy); memcpy(&vRecv[nDataPos], pch, nCopy); nDataPos += nCopy; return nCopy; } +const uint256& CNetMessage::GetMessageHash() const +{ + assert(complete()); + if (data_hash.IsNull()) + hasher.Finalize(data_hash.begin()); + return data_hash; +} + -- cgit v1.2.3 From aff6584e09938768838a768b67722db553cf8ef4 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 31 Oct 2016 17:06:15 -0400 Subject: net: constify a few CNode vars to indicate that they're threadsafe --- src/net.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 48ba9588d..f27516aae 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2512,9 +2512,13 @@ unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), + fInbound(fInboundIn), + id(idIn), nKeyedNetGroup(nKeyedNetGroupIn), addrKnown(5000, 0.001), - filterInventoryKnown(50000, 0.000001) + filterInventoryKnown(50000, 0.000001), + nLocalServices(nLocalServicesIn), + nMyStartingHeight(nMyStartingHeightIn) { nServices = NODE_NONE; nServicesExpected = NODE_NONE; @@ -2533,7 +2537,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn fOneShot = false; fClient = false; // set by version message fFeeler = false; - fInbound = fInboundIn; fNetworkNode = false; fSuccessfullyConnected = false; fDisconnect = false; @@ -2562,12 +2565,8 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn minFeeFilter = 0; lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; - id = idIn; nOptimisticBytesWritten = 0; - nLocalServices = nLocalServicesIn; - GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); - nMyStartingHeight = nMyStartingHeightIn; BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; -- cgit v1.2.3 From 59ac5c5b72fef6a70fe621537faf27df1076b524 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 26 Oct 2016 15:10:15 -0400 Subject: net: Use deterministic randomness for CNode's nonce, and make it const --- src/net.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index f27516aae..18d25cbcd 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -64,6 +64,7 @@ const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8] +static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8] // // Global state variables // @@ -389,7 +390,10 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), pszDest ? pszDest : "", false); + NodeId id = GetNewNodeId(); + uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); + CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false); + GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -1024,7 +1028,10 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), "", true); + NodeId id = GetNewNodeId(); + uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); + + CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2118,7 +2125,11 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0); + + NodeId id = GetNewNodeId(); + uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); + + pnodeLocalHost = new CNode(id, nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0, nonce); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2509,7 +2520,7 @@ void CNode::Fuzz(int nChance) 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, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), fInbound(fInboundIn), @@ -2517,6 +2528,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nKeyedNetGroup(nKeyedNetGroupIn), addrKnown(5000, 0.001), filterInventoryKnown(50000, 0.000001), + nLocalHostNonce(nLocalHostNonceIn), nLocalServices(nLocalServicesIn), nMyStartingHeight(nMyStartingHeightIn) { @@ -2566,7 +2578,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; nOptimisticBytesWritten = 0; - GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; -- cgit v1.2.3 From d32036a47d9ccdc38628a7a75bb8b711af462e4f Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Tue, 1 Nov 2016 00:08:47 +0000 Subject: Use RelevantServices instead of node_network in AttemptToEvict. Use of node_network here is really meant to be a proxy of "likely to send us blocks in the future". RelevantServices is the right criteria now. --- src/net.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 48ba9588d..6020da16f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -825,7 +825,7 @@ struct NodeEvictionCandidate int64_t nMinPingUsecTime; int64_t nLastBlockTime; int64_t nLastTXTime; - bool fNetworkNode; + bool fRelevantServices; bool fRelayTxes; bool fBloomFilter; CAddress addr; @@ -850,7 +850,7 @@ static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvict { // There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block. if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime; - if (a.fNetworkNode != b.fNetworkNode) return b.fNetworkNode; + if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices; return a.nTimeConnected > b.nTimeConnected; } @@ -885,7 +885,8 @@ bool CConnman::AttemptToEvictConnection() if (node->fDisconnect) continue; NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, - node->nLastBlockTime, node->nLastTXTime, node->fNetworkNode, + node->nLastBlockTime, node->nLastTXTime, + (node->nServices & nRelevantServices) == nRelevantServices, node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } -- cgit v1.2.3 From 3e32cd09f643bf7d4344d3bb2e1136f186f3d109 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 12 Sep 2016 20:00:33 -0400 Subject: connman is in charge of pushing messages The changes here are dense and subtle, but hopefully all is more explicit than before. - CConnman is now in charge of sending data rather than the nodes themselves. This is necessary because many decisions need to be made with all nodes in mind, and a model that requires the nodes calling up to their manager quickly turns to spaghetti. - The per-node-serializer (ssSend) has been replaced with a (quasi-)const send-version. Since the send version for serialization can only change once per connection, we now explicitly tag messages with INIT_PROTO_VERSION if they are sent before the handshake. With this done, there's no need to lock for access to nSendVersion. Also, a new stream is used for each message, so there's no need to lock during the serialization process. - This takes care of accounting for optimistic sends, so the nOptimisticBytesWritten hack can be removed. - -dropmessagestest and -fuzzmessagestest have not been preserved, as I suspect they haven't been used in years. --- src/net.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 22 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 18d25cbcd..f271aed24 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -394,6 +394,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false); + + PushVersion(pnode, GetTime()); + GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -415,6 +418,24 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo return NULL; } +void CConnman::PushVersion(CNode* pnode, int64_t nTime) +{ + ServiceFlags nLocalNodeServices = pnode->GetLocalServices(); + CAddress addrYou = (pnode->addr.IsRoutable() && !IsProxy(pnode->addr) ? pnode->addr : CAddress(CService(), pnode->addr.nServices)); + CAddress addrMe = CAddress(CService(), nLocalNodeServices); + uint64_t nonce = pnode->GetLocalNonce(); + int nNodeStartingHeight = pnode->nMyStartingHeight; + NodeId id = pnode->GetId(); + + PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, + nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes); + + if (fLogIPs) + LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), id); + else + LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), id); +} + void CConnman::DumpBanlist() { SweepBanned(); // clean unused entries (if bantime has expired) @@ -450,23 +471,6 @@ void CNode::CloseSocketDisconnect() vRecvMsg.clear(); } -void CNode::PushVersion() -{ - int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); - CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); - CAddress addrMe = CAddress(CService(), nLocalServices); - if (fLogIPs) - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id); - else - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), id); - PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nMyStartingHeight, ::fRelayTxes); -} - - - - - void CConnman::ClearBanned() { { @@ -2530,7 +2534,8 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn filterInventoryKnown(50000, 0.000001), nLocalHostNonce(nLocalHostNonceIn), nLocalServices(nLocalServicesIn), - nMyStartingHeight(nMyStartingHeightIn) + nMyStartingHeight(nMyStartingHeightIn), + nSendVersion(0) { nServices = NODE_NONE; nServicesExpected = NODE_NONE; @@ -2587,10 +2592,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn LogPrint("net", "Added connection to %s peer=%d\n", addrName, id); else LogPrint("net", "Added connection peer=%d\n", id); - - // Be shy and don't send version until we hear - if (hSocket != INVALID_SOCKET && !fInbound) - PushVersion(); } CNode::~CNode() @@ -2696,6 +2697,52 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) LEAVE_CRITICAL_SECTION(cs_vSend); } +CDataStream CConnman::BeginMessage(CNode* pnode, int nVersion, int flags, const std::string& sCommand) +{ + return {SER_NETWORK, (nVersion ? nVersion : pnode->GetSendVersion()) | flags, CMessageHeader(Params().MessageStart(), sCommand.c_str(), 0) }; +} + +void CConnman::EndMessage(CDataStream& strm) +{ + // Set the size + assert(strm.size () >= CMessageHeader::HEADER_SIZE); + unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE; + WriteLE32((uint8_t*)&strm[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); + // Set the checksum + uint256 hash = Hash(strm.begin() + CMessageHeader::HEADER_SIZE, strm.end()); + memcpy((char*)&strm[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE); + +} + +void CConnman::PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand) +{ + if(strm.empty()) + return; + + unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE; + LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(sCommand.c_str()), nSize, pnode->id); + + size_t nBytesSent = 0; + { + LOCK(pnode->cs_vSend); + if(pnode->hSocket == INVALID_SOCKET) { + return; + } + bool optimisticSend(pnode->vSendMsg.empty()); + pnode->vSendMsg.emplace_back(strm.begin(), strm.end()); + + //log total amount of bytes per command + pnode->mapSendBytesPerMsgCmd[sCommand] += strm.size(); + pnode->nSendSize += strm.size(); + + // If write queue empty, attempt "optimistic write" + if (optimisticSend == true) + nBytesSent = SocketSendData(pnode); + } + if (nBytesSent) + RecordBytesSent(nBytesSent); +} + bool CConnman::ForNode(NodeId id, std::function func) { CNode* found = nullptr; -- cgit v1.2.3 From ea3326891d8c3dcbcff178b618108d657c5586a3 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 12 Sep 2016 20:07:44 -0400 Subject: net: switch all callers to connman for pushing messages Drop all of the old stuff. --- src/net.cpp | 61 ------------------------------------------------------------- 1 file changed, 61 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index f271aed24..2cc14a222 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2636,67 +2636,6 @@ void CNode::AskFor(const CInv& inv) mapAskFor.insert(std::make_pair(nRequestTime, inv)); } -void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) -{ - ENTER_CRITICAL_SECTION(cs_vSend); - assert(ssSend.size() == 0); - ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0); - LogPrint("net", "sending: %s ", SanitizeString(pszCommand)); -} - -void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend) -{ - ssSend.clear(); - - LEAVE_CRITICAL_SECTION(cs_vSend); - - LogPrint("net", "(aborted)\n"); -} - -void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) -{ - // The -*messagestest options are intentionally not documented in the help message, - // since they are only used during development to debug the networking code and are - // not intended for end-users. - if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0) - { - LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n"); - AbortMessage(); - return; - } - if (mapArgs.count("-fuzzmessagestest")) - Fuzz(GetArg("-fuzzmessagestest", 10)); - - if (ssSend.size() == 0) - { - LEAVE_CRITICAL_SECTION(cs_vSend); - return; - } - // Set the size - unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; - WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); - - //log total amount of bytes per command - mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE; - - // Set the checksum - uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); - assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + CMessageHeader::CHECKSUM_SIZE); - memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE); - - LogPrint("net", "(%d bytes) peer=%d\n", nSize, id); - - std::deque::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData()); - ssSend.GetAndClear(*it); - nSendSize += (*it).size(); - - // If write queue empty, attempt "optimistic write" - if (it == vSendMsg.begin()) - nOptimisticBytesWritten += SocketSendData(this); - - LEAVE_CRITICAL_SECTION(cs_vSend); -} - CDataStream CConnman::BeginMessage(CNode* pnode, int nVersion, int flags, const std::string& sCommand) { return {SER_NETWORK, (nVersion ? nVersion : pnode->GetSendVersion()) | flags, CMessageHeader(Params().MessageStart(), sCommand.c_str(), 0) }; -- cgit v1.2.3 From 5c2169cc3f263b39ba42d66bcf014163fada2390 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 12 Sep 2016 20:09:24 -0400 Subject: drop the optimistic write counter hack This is now handled properly in realtime. --- src/net.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 2cc14a222..2d6573f7f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1167,10 +1167,6 @@ void CConnman::ThreadSocketHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) { - if (pnode->nOptimisticBytesWritten) { - RecordBytesSent(pnode->nOptimisticBytesWritten); - pnode->nOptimisticBytesWritten = 0; - } if (!pnode->vSendMsg.empty()) { FD_SET(pnode->hSocket, &fdsetSend); continue; @@ -2582,7 +2578,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn minFeeFilter = 0; lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; - nOptimisticBytesWritten = 0; BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; -- cgit v1.2.3 From 440f1d3e4c60c9c3e0a1a74d3321b0a8e37a1e8d Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 30 Sep 2016 15:03:57 -0400 Subject: net: remove now-unused ssSend and Fuzz --- src/net.cpp | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 2d6573f7f..16d9527ee 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1063,7 +1063,7 @@ void CConnman::ThreadSocketHandler() BOOST_FOREACH(CNode* pnode, vNodesCopy) { if (pnode->fDisconnect || - (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty())) + (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0)) { // remove from vNodes vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); @@ -2482,46 +2482,10 @@ int CConnman::GetBestHeight() const return nBestHeight.load(std::memory_order_acquire); } -void CNode::Fuzz(int nChance) -{ - if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake - if (GetRand(nChance) != 0) return; // Fuzz 1 of every nChance messages - - switch (GetRand(3)) - { - case 0: - // xor a random byte with a random value: - if (!ssSend.empty()) { - CDataStream::size_type pos = GetRand(ssSend.size()); - ssSend[pos] ^= (unsigned char)(GetRand(256)); - } - break; - case 1: - // delete a random byte: - if (!ssSend.empty()) { - CDataStream::size_type pos = GetRand(ssSend.size()); - ssSend.erase(ssSend.begin()+pos); - } - break; - case 2: - // insert a random byte at a random position - { - CDataStream::size_type pos = GetRand(ssSend.size()); - char ch = (char)GetRand(256); - ssSend.insert(ssSend.begin()+pos, ch); - } - break; - } - // Chance of more than one change half the time: - // (more changes exponentially less likely): - Fuzz(2); -} - 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 std::string& addrNameIn, bool fInboundIn) : - ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), fInbound(fInboundIn), id(idIn), -- cgit v1.2.3 From 902768099cb92b39f5ff509cd91fdd8970759b8a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 26 Oct 2016 18:08:11 -0400 Subject: net: handle version push in InitializeNode --- src/net.cpp | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 16d9527ee..15cf7ce8b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -393,21 +393,15 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo NodeId id = GetNewNodeId(); uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false); - - - PushVersion(pnode, GetTime()); - - GetNodeSignals().InitializeNode(pnode->GetId(), pnode); + pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); + pnode->nTimeConnected = GetTime(); pnode->AddRef(); - + GetNodeSignals().InitializeNode(pnode, *this); { LOCK(cs_vNodes); vNodes.push_back(pnode); } - pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); - pnode->nTimeConnected = GetTime(); - return pnode; } else if (!proxyConnectionFailed) { // If connecting to the node failed, and failure is not caused by a problem connecting to @@ -418,24 +412,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo return NULL; } -void CConnman::PushVersion(CNode* pnode, int64_t nTime) -{ - ServiceFlags nLocalNodeServices = pnode->GetLocalServices(); - CAddress addrYou = (pnode->addr.IsRoutable() && !IsProxy(pnode->addr) ? pnode->addr : CAddress(CService(), pnode->addr.nServices)); - CAddress addrMe = CAddress(CService(), nLocalNodeServices); - uint64_t nonce = pnode->GetLocalNonce(); - int nNodeStartingHeight = pnode->nMyStartingHeight; - NodeId id = pnode->GetId(); - - PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, - nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes); - - if (fLogIPs) - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), id); - else - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), id); -} - void CConnman::DumpBanlist() { SweepBanned(); // clean unused entries (if bantime has expired) @@ -1036,9 +1012,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, "", true); - GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; + GetNodeSignals().InitializeNode(pnode, *this); LogPrint("net", "connection from %s accepted\n", addr.ToString()); @@ -2130,7 +2106,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); pnodeLocalHost = new CNode(id, nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0, nonce); - GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); + GetNodeSignals().InitializeNode(pnodeLocalHost, *this); } // -- cgit v1.2.3 From c7be56dceff625991cb2884f2ce053996ac613cd Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 10 Nov 2016 20:17:30 -0500 Subject: net: push only raw data into CConnman This fixes one of the last major layer violations in the networking stack. The network side is no longer in charge of message serialization, so it is now decoupled from Bitcoin structures. Only the header is serialized and attached to the payload. --- src/net.cpp | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 15c4514f1..ce87150ae 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -768,13 +768,13 @@ const uint256& CNetMessage::GetMessageHash() const // requires LOCK(cs_vSend) size_t SocketSendData(CNode *pnode) { - std::deque::iterator it = pnode->vSendMsg.begin(); + auto it = pnode->vSendMsg.begin(); size_t nSentSize = 0; while (it != pnode->vSendMsg.end()) { - const CSerializeData &data = *it; + const auto &data = *it; assert(data.size() > pnode->nSendOffset); - int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); + int nBytes = send(pnode->hSocket, reinterpret_cast(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); if (nBytes > 0) { pnode->nLastSend = GetTime(); pnode->nSendBytes += nBytes; @@ -2612,30 +2612,19 @@ void CNode::AskFor(const CInv& inv) mapAskFor.insert(std::make_pair(nRequestTime, inv)); } -CDataStream CConnman::BeginMessage(CNode* pnode, int nVersion, int flags, const std::string& sCommand) +void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) { - return {SER_NETWORK, (nVersion ? nVersion : pnode->GetSendVersion()) | flags, CMessageHeader(Params().MessageStart(), sCommand.c_str(), 0) }; -} - -void CConnman::EndMessage(CDataStream& strm) -{ - // Set the size - assert(strm.size () >= CMessageHeader::HEADER_SIZE); - unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE; - WriteLE32((uint8_t*)&strm[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); - // Set the checksum - uint256 hash = Hash(strm.begin() + CMessageHeader::HEADER_SIZE, strm.end()); - memcpy((char*)&strm[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE); - -} + size_t nMessageSize = msg.data.size(); + size_t nTotalSize = nMessageSize + CMessageHeader::HEADER_SIZE; + LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.command.c_str()), nMessageSize, pnode->id); -void CConnman::PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand) -{ - if(strm.empty()) - return; + std::vector serializedHeader; + serializedHeader.reserve(CMessageHeader::HEADER_SIZE); + uint256 hash = Hash(msg.data.data(), msg.data.data() + nMessageSize); + CMessageHeader hdr(Params().MessageStart(), msg.command.c_str(), nMessageSize); + memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE); - unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE; - LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(sCommand.c_str()), nSize, pnode->id); + CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, serializedHeader, 0, hdr}; size_t nBytesSent = 0; { @@ -2644,11 +2633,14 @@ void CConnman::PushMessage(CNode* pnode, CDataStream& strm, const std::string& s return; } bool optimisticSend(pnode->vSendMsg.empty()); - pnode->vSendMsg.emplace_back(strm.begin(), strm.end()); //log total amount of bytes per command - pnode->mapSendBytesPerMsgCmd[sCommand] += strm.size(); - pnode->nSendSize += strm.size(); + pnode->mapSendBytesPerMsgCmd[msg.command] += nTotalSize; + pnode->nSendSize += nTotalSize; + + pnode->vSendMsg.push_back(std::move(serializedHeader)); + if (nMessageSize) + pnode->vSendMsg.push_back(std::move(msg.data)); // If write queue empty, attempt "optimistic write" if (optimisticSend == true) -- cgit v1.2.3 From dfed983f19e7b61da243362f00fa3a14c92dae45 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 25 Nov 2016 19:29:55 -0800 Subject: Fix unlocked access to vNodes.size() --- src/net.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 15c4514f1..233c0fbc8 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1103,8 +1103,13 @@ void CConnman::ThreadSocketHandler() } } } - if(vNodes.size() != nPrevNodeCount) { - nPrevNodeCount = vNodes.size(); + size_t vNodesSize; + { + LOCK(cs_vNodes); + vNodesSize = vNodes.size(); + } + if(vNodesSize != nPrevNodeCount) { + nPrevNodeCount = vNodesSize; if(clientInterface) clientInterface->NotifyNumConnectionsChanged(nPrevNodeCount); } -- cgit v1.2.3 From 083f20369878196785151e038e5f5126fed74021 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 27 Nov 2016 02:47:22 +0000 Subject: Remove fNetworkNode. Matt pointed out to me that this appeared to be doing nothing (except involving itself in data races). --- src/net.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index ce87150ae..08115a351 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1067,8 +1067,7 @@ void CConnman::ThreadSocketHandler() pnode->CloseSocketDisconnect(); // hold in disconnected pool until all refs are released - if (pnode->fNetworkNode || pnode->fInbound) - pnode->Release(); + pnode->Release(); vNodesDisconnected.push_back(pnode); } } @@ -1808,7 +1807,6 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai return false; if (grantOutbound) grantOutbound->MoveTo(pnode->grantOutbound); - pnode->fNetworkNode = true; if (fOneShot) pnode->fOneShot = true; if (fFeeler) @@ -2531,7 +2529,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn fOneShot = false; fClient = false; // set by version message fFeeler = false; - fNetworkNode = false; fSuccessfullyConnected = false; fDisconnect = false; nRefCount = 0; -- cgit v1.2.3 From bdb922b34c9a477c4ebf358653f6bcfb9bee48ce Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 27 Nov 2016 04:19:37 +0000 Subject: Remove pnodeLocalHost. Mostly a legacy of the long removed pub/sub system. --- src/net.cpp | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 08115a351..c9317c302 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -74,7 +74,6 @@ bool fRelayTxes = true; CCriticalSection cs_mapLocalHost; std::map mapLocalHost; static bool vfLimited[NET_MAX] = {}; -static CNode* pnodeLocalHost = NULL; std::string strSubVersion; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); @@ -2137,17 +2136,6 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); } - if (pnodeLocalHost == NULL) { - CNetAddr local; - LookupHost("127.0.0.1", local, false); - - NodeId id = GetNewNodeId(); - uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); - - pnodeLocalHost = new CNode(id, nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0, nonce); - GetNodeSignals().InitializeNode(pnodeLocalHost, *this); - } - // // Start threads // @@ -2225,9 +2213,6 @@ void CConnman::Stop() vhListenSocket.clear(); delete semOutbound; semOutbound = NULL; - if(pnodeLocalHost) - DeleteNode(pnodeLocalHost); - pnodeLocalHost = NULL; } void CConnman::DeleteNode(CNode* pnode) -- cgit v1.2.3 From 2b5f085ad11b4b354f48d77e66698fa386c8abbd Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 29 Nov 2016 16:50:49 -0800 Subject: Fix non-const mapMultiArgs[] access after init. Swap mapMultiArgs for a const-reference to a _mapMultiArgs which is only accessed in util.cpp --- src/net.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 27b200b3f..3ac962354 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1569,12 +1569,12 @@ void CConnman::ProcessOneShot() void CConnman::ThreadOpenConnections() { // Connect to specific addresses - if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) + if (mapMultiArgs.count("-connect") && mapMultiArgs.at("-connect").size() > 0) { for (int64_t nLoop = 0;; nLoop++) { ProcessOneShot(); - BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"]) + BOOST_FOREACH(const std::string& strAddr, mapMultiArgs.at("-connect")) { CAddress addr(CService(), NODE_NONE); OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); @@ -1765,7 +1765,8 @@ void CConnman::ThreadOpenAddedConnections() { { LOCK(cs_vAddedNodes); - vAddedNodes = mapMultiArgs["-addnode"]; + if (mapMultiArgs.count("-addnode")) + vAddedNodes = mapMultiArgs.at("-addnode"); } for (unsigned int i = 0; true; i++) @@ -2157,7 +2158,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st threadGroup.create_thread(boost::bind(&TraceThread >, "addcon", boost::function(boost::bind(&CConnman::ThreadOpenAddedConnections, this)))); // Initiate outbound connections unless connect=0 - if (!mapArgs.count("-connect") || mapMultiArgs["-connect"].size() != 1 || mapMultiArgs["-connect"][0] != "0") + if (!mapMultiArgs.count("-connect") || mapMultiArgs.at("-connect").size() != 1 || mapMultiArgs.at("-connect")[0] != "0") threadGroup.create_thread(boost::bind(&TraceThread >, "opencon", boost::function(boost::bind(&CConnman::ThreadOpenConnections, this)))); // Process messages -- cgit v1.2.3 From 27765b6403cece54320374b37afb01a0cfe571c3 Mon Sep 17 00:00:00 2001 From: isle2983 Date: Sat, 31 Dec 2016 11:01:21 -0700 Subject: Increment MIT Licence copyright header year on files modified in 2016 Edited via: $ contrib/devtools/copyright_header.py update . --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3ac962354..52fd72539 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -- cgit v1.2.3 From 7325b1556684158461c9c0df056c9d071444b54e Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 27 Dec 2016 17:11:57 -0500 Subject: net: a few small cleanups before replacing boost threads - Drop the interruption point directly after the pnode allocation. This would be leaky if hit. - Rearrange thread creation so that the socket handler comes first --- src/net.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3ac962354..9c58577f1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1806,7 +1806,6 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai return false; CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure); - boost::this_thread::interruption_point(); if (!pnode) return false; @@ -2146,14 +2145,14 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st // Start threads // + // Send and receive from sockets, accept connections + threadGroup.create_thread(boost::bind(&TraceThread >, "net", boost::function(boost::bind(&CConnman::ThreadSocketHandler, this)))); + if (!GetBoolArg("-dnsseed", true)) LogPrintf("DNS seeding disabled\n"); else threadGroup.create_thread(boost::bind(&TraceThread >, "dnsseed", boost::function(boost::bind(&CConnman::ThreadDNSAddressSeed, this)))); - // Send and receive from sockets, accept connections - threadGroup.create_thread(boost::bind(&TraceThread >, "net", boost::function(boost::bind(&CConnman::ThreadSocketHandler, this)))); - // Initiate outbound connections from -addnode threadGroup.create_thread(boost::bind(&TraceThread >, "addcon", boost::function(boost::bind(&CConnman::ThreadOpenAddedConnections, this)))); -- cgit v1.2.3 From 0985052319263bd7ca9744af3504682b3ea8e21a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 27 Dec 2016 17:12:44 -0500 Subject: net: make net interruptible Also now that net threads are interruptible, switch them to use std threads/binds/mutexes/condvars. --- src/net.cpp | 105 ++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 34 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 9c58577f1..a66679cd8 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1042,7 +1042,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { void CConnman::ThreadSocketHandler() { unsigned int nPrevNodeCount = 0; - while (true) + while (!interruptNet) { // // Disconnect nodes @@ -1180,7 +1180,8 @@ void CConnman::ThreadSocketHandler() int nSelect = select(have_fds ? hSocketMax + 1 : 0, &fdsetRecv, &fdsetSend, &fdsetError, &timeout); - boost::this_thread::interruption_point(); + if (interruptNet) + return; if (nSelect == SOCKET_ERROR) { @@ -1193,7 +1194,8 @@ void CConnman::ThreadSocketHandler() } FD_ZERO(&fdsetSend); FD_ZERO(&fdsetError); - MilliSleep(timeout.tv_usec/1000); + if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000))) + return; } // @@ -1219,7 +1221,8 @@ void CConnman::ThreadSocketHandler() } BOOST_FOREACH(CNode* pnode, vNodesCopy) { - boost::this_thread::interruption_point(); + if (interruptNet) + return; // // Receive @@ -1241,7 +1244,7 @@ void CConnman::ThreadSocketHandler() if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) pnode->CloseSocketDisconnect(); if(notify) - messageHandlerCondition.notify_one(); + condMsgProc.notify_one(); pnode->nLastRecv = GetTime(); pnode->nRecvBytes += nBytes; RecordBytesRecv(nBytes); @@ -1469,7 +1472,8 @@ void CConnman::ThreadDNSAddressSeed() // less influence on the network topology, and reduces traffic to the seeds. if ((addrman.size() > 0) && (!GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) { - MilliSleep(11 * 1000); + if (!interruptNet.sleep_for(std::chrono::seconds(11))) + return; LOCK(cs_vNodes); int nRelevant = 0; @@ -1580,10 +1584,12 @@ void CConnman::ThreadOpenConnections() OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { - MilliSleep(500); + if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) + return; } } - MilliSleep(500); + if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) + return; } } @@ -1592,14 +1598,16 @@ void CConnman::ThreadOpenConnections() // Minimum time before next feeler connection (in microseconds). int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL); - while (true) + while (!interruptNet) { ProcessOneShot(); - MilliSleep(500); + if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) + return; CSemaphoreGrant grant(*semOutbound); - boost::this_thread::interruption_point(); + if (interruptNet) + return; // Add seed nodes if DNS seeds are all down (an infrastructure attack?). if (addrman.size() == 0 && (GetTime() - nStart > 60)) { @@ -1657,7 +1665,7 @@ void CConnman::ThreadOpenConnections() int64_t nANow = GetAdjustedTime(); int nTries = 0; - while (true) + while (!interruptNet) { CAddrInfo addr = addrman.Select(fFeeler); @@ -1700,7 +1708,8 @@ void CConnman::ThreadOpenConnections() if (fFeeler) { // Add small amount of random noise before connection to avoid synchronization. int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000); - MilliSleep(randsleep); + if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep))) + return; LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString()); } @@ -1779,11 +1788,12 @@ void CConnman::ThreadOpenAddedConnections() // OpenNetworkConnection can detect existing connections to that IP/port. CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort())); OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false); - MilliSleep(500); + if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) + return; } } - - MilliSleep(120000); // Retry every 2 minutes + if (!interruptNet.sleep_for(std::chrono::minutes(2))) + return; } } @@ -1793,7 +1803,9 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai // // Initiate outbound network connection // - boost::this_thread::interruption_point(); + if (interruptNet) { + return false; + } if (!fNetworkActive) { return false; } @@ -1819,13 +1831,9 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai return true; } - void CConnman::ThreadMessageHandler() { - boost::mutex condition_mutex; - boost::unique_lock lock(condition_mutex); - - while (true) + while (!flagInterruptMsgProc) { std::vector vNodesCopy; { @@ -1860,7 +1868,8 @@ void CConnman::ThreadMessageHandler() } } } - boost::this_thread::interruption_point(); + if (flagInterruptMsgProc) + return; // Send messages { @@ -1868,7 +1877,8 @@ void CConnman::ThreadMessageHandler() if (lockSend) GetNodeSignals().SendMessages(pnode, *this); } - boost::this_thread::interruption_point(); + if (flagInterruptMsgProc) + return; } { @@ -1877,8 +1887,10 @@ void CConnman::ThreadMessageHandler() pnode->Release(); } - if (fSleep) - messageHandlerCondition.timed_wait(lock, boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(100)); + if (fSleep) { + std::unique_lock lock(mutexMsgProc); + condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100)); + } } } @@ -2070,6 +2082,7 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe nMaxOutbound = 0; nBestHeight = 0; clientInterface = NULL; + flagInterruptMsgProc = false; } NodeId CConnman::GetNewNodeId() @@ -2077,7 +2090,7 @@ NodeId CConnman::GetNewNodeId() return nLastNodeId.fetch_add(1, std::memory_order_relaxed); } -bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options connOptions) +bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options connOptions) { nTotalBytesRecv = 0; nTotalBytesSent = 0; @@ -2144,24 +2157,26 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st // // Start threads // + interruptNet.reset(); + flagInterruptMsgProc = false; // Send and receive from sockets, accept connections - threadGroup.create_thread(boost::bind(&TraceThread >, "net", boost::function(boost::bind(&CConnman::ThreadSocketHandler, this)))); + threadSocketHandler = std::thread(&TraceThread >, "net", std::function(std::bind(&CConnman::ThreadSocketHandler, this))); if (!GetBoolArg("-dnsseed", true)) LogPrintf("DNS seeding disabled\n"); else - threadGroup.create_thread(boost::bind(&TraceThread >, "dnsseed", boost::function(boost::bind(&CConnman::ThreadDNSAddressSeed, this)))); + threadDNSAddressSeed = std::thread(&TraceThread >, "dnsseed", std::function(std::bind(&CConnman::ThreadDNSAddressSeed, this))); // Initiate outbound connections from -addnode - threadGroup.create_thread(boost::bind(&TraceThread >, "addcon", boost::function(boost::bind(&CConnman::ThreadOpenAddedConnections, this)))); + threadOpenAddedConnections = std::thread(&TraceThread >, "addcon", std::function(std::bind(&CConnman::ThreadOpenAddedConnections, this))); // Initiate outbound connections unless connect=0 if (!mapMultiArgs.count("-connect") || mapMultiArgs.at("-connect").size() != 1 || mapMultiArgs.at("-connect")[0] != "0") - threadGroup.create_thread(boost::bind(&TraceThread >, "opencon", boost::function(boost::bind(&CConnman::ThreadOpenConnections, this)))); + threadOpenConnections = std::thread(&TraceThread >, "opencon", std::function(std::bind(&CConnman::ThreadOpenConnections, this))); // Process messages - threadGroup.create_thread(boost::bind(&TraceThread >, "msghand", boost::function(boost::bind(&CConnman::ThreadMessageHandler, this)))); + threadMessageHandler = std::thread(&TraceThread >, "msghand", std::function(std::bind(&CConnman::ThreadMessageHandler, this))); // Dump network addresses scheduler.scheduleEvery(boost::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL); @@ -2184,12 +2199,33 @@ public: } instance_of_cnetcleanup; -void CConnman::Stop() +void CConnman::Interrupt() { - LogPrintf("%s\n",__func__); + { + std::lock_guard lock(mutexMsgProc); + flagInterruptMsgProc = true; + } + condMsgProc.notify_all(); + + interruptNet(); + if (semOutbound) for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) semOutbound->post(); +} + +void CConnman::Stop() +{ + if (threadMessageHandler.joinable()) + threadMessageHandler.join(); + if (threadOpenConnections.joinable()) + threadOpenConnections.join(); + if (threadOpenAddedConnections.joinable()) + threadOpenAddedConnections.join(); + if (threadDNSAddressSeed.joinable()) + threadDNSAddressSeed.join(); + if (threadSocketHandler.joinable()) + threadSocketHandler.join(); if (fAddressesInitialized) { @@ -2232,6 +2268,7 @@ void CConnman::DeleteNode(CNode* pnode) CConnman::~CConnman() { + Interrupt(); Stop(); } -- cgit v1.2.3 From d3d7056d2a562301b3770c4ede1dfc8ffb00cf4b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 27 Dec 2016 17:13:04 -0500 Subject: net: make net processing interruptible --- src/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index a66679cd8..bbfada430 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1856,7 +1856,7 @@ void CConnman::ThreadMessageHandler() TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) { - if (!GetNodeSignals().ProcessMessages(pnode, *this)) + if (!GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc)) pnode->CloseSocketDisconnect(); if (pnode->nSendSize < GetSendBufferSize()) @@ -1875,7 +1875,7 @@ void CConnman::ThreadMessageHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) - GetNodeSignals().SendMessages(pnode, *this); + GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); } if (flagInterruptMsgProc) return; -- cgit v1.2.3 From 8b3159ef0a912da67c545a3d24f4558f8df866e4 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 27 Dec 2016 17:13:31 -0500 Subject: net: make proxy receives interruptible --- src/net.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index bbfada430..7e16e2382 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2157,6 +2157,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c // // Start threads // + InterruptSocks5(false); interruptNet.reset(); flagInterruptMsgProc = false; @@ -2208,6 +2209,7 @@ void CConnman::Interrupt() condMsgProc.notify_all(); interruptNet(); + InterruptSocks5(true); if (semOutbound) for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) -- cgit v1.2.3 From 67ee4ec9015592c8447955356adfcbb1bf473e32 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 27 Dec 2016 17:13:51 -0500 Subject: net: misc header cleanups --- src/net.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 7e16e2382..66c853915 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -35,8 +35,6 @@ #include #endif -#include -#include #include -- cgit v1.2.3 From 53ad9a133a53feb35e31698720cec69c14f56dc1 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:05 -0500 Subject: net: fix typo causing the wrong receive buffer size Surprisingly this hasn't been causing me any issues while testing, probably because it requires lots of large blocks to be flying around. Send/Recv corks need tests! --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index bf2beb774..e7c7cf011 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2102,7 +2102,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c nMaxFeeler = connOptions.nMaxFeeler; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; - nReceiveFloodSize = connOptions.nSendBufferMaxSize; + nReceiveFloodSize = connOptions.nReceiveFloodSize; nMaxOutboundLimit = connOptions.nMaxOutboundLimit; nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; -- cgit v1.2.3 From e5bcd9c84fd3107321ff6dbdef067ba03f2b43cb Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:07 -0500 Subject: net: make vRecvMsg a list so that we can use splice() --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e7c7cf011..3478d04a7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1859,7 +1859,7 @@ void CConnman::ThreadMessageHandler() if (pnode->nSendSize < GetSendBufferSize()) { - if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg[0].complete())) + if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg.front().complete())) { fSleep = false; } -- cgit v1.2.3 From f6315e07f9383f3f43e37ada0d6a835810d610b9 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:11 -0500 Subject: net: only disconnect if fDisconnect has been set These conditions are problematic to check without locking, and we shouldn't be relying on the refcount to disconnect. --- src/net.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 3478d04a7..65f1c62ad 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1051,8 +1051,7 @@ void CConnman::ThreadSocketHandler() std::vector vNodesCopy = vNodes; BOOST_FOREACH(CNode* pnode, vNodesCopy) { - if (pnode->fDisconnect || - (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0)) + if (pnode->fDisconnect) { // remove from vNodes vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); -- cgit v1.2.3 From 60425870d78cf2bef1fce926ad53f51166c6a3f0 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:13 -0500 Subject: net: wait until the node is destroyed to delete its recv buffer when vRecvMsg becomes a private buffer, it won't make sense to allow other threads to mess with it anymore. --- src/net.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 65f1c62ad..9ce7475bc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -437,11 +437,6 @@ void CNode::CloseSocketDisconnect() LogPrint("net", "disconnecting peer=%d\n", id); CloseSocket(hSocket); } - - // in case this fails, we'll empty the recv buffer when the CNode is deleted - TRY_LOCK(cs_vRecvMsg, lockRecv); - if (lockRecv) - vRecvMsg.clear(); } void CConnman::ClearBanned() -- cgit v1.2.3 From 56212e20acf1534d443cb910c9bf3a30f84d0f02 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:15 -0500 Subject: net: set message deserialization version when it's actually time to deserialize We'll soon no longer have access to vRecvMsg, and this is more intuitive anyway. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 9ce7475bc..6d9971a0f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -653,7 +653,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete // get current incomplete message, or create a new one if (vRecvMsg.empty() || vRecvMsg.back().complete()) - vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, nRecvVersion)); + vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, INIT_PROTO_VERSION)); CNetMessage& msg = vRecvMsg.back(); -- cgit v1.2.3 From 50bd12ce0c49e574a5baf1a8df3a667810c6ad1e Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 11 Dec 2016 04:39:26 +0000 Subject: Break addnode out from the outbound connection limits. Previously addnodes were in competition with outbound connections for access to the eight outbound slots. One result of this is that frequently a node with several addnode configured peers would end up connected to none of them, because while the addnode loop was in its two minute sleep the automatic connection logic would fill any free slots with random peers. This is particularly unwelcome to users trying to maintain links to specific nodes for fast block relay or purposes. Another result is that a group of nine or more nodes which are have addnode configured towards each other can become partitioned from the public network. This commit introduces a new limit of eight connections just for addnode peers which is not subject to any of the other connection limitations (including maxconnections). The choice of eight is sufficient so that under no condition would a user find themselves connected to fewer addnoded peers than previously. It is also low enough that users who are confused about the significance of more connections and have gotten too copy-and-paste happy will not consume more than twice the slot usage of a typical user. Any additional load on the network resulting from this will likely be offset by a reduction in users applying even more wasteful workaround for the prior behavior. The retry delays are reduced to avoid nodes sitting around without their added peers up, but are still sufficient to prevent overly aggressive repeated connections. The reduced delays also make the system much more responsive to the addnode RPC. Ban-disconnects are also exempted for peers added via addnode since the outbound addnode logic ignores bans. Previously it would ban an addnode then immediately reconnect to it. A minor change was also made to CSemaphoreGrant so that it is possible to re-acquire via an object whos grant was moved. --- src/net.cpp | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index bf2beb774..6640cc001 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -621,6 +621,7 @@ void CNode::copyStats(CNodeStats &stats) X(nVersion); X(cleanSubVer); X(fInbound); + X(fAddnode); X(nStartingHeight); X(nSendBytes); X(mapSendBytesPerMsgCmd); @@ -1631,7 +1632,7 @@ void CConnman::ThreadOpenConnections() { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - if (!pnode->fInbound) { + if (!pnode->fInbound && !pnode->fAddnode) { setConnected.insert(pnode->addr.GetGroup()); nOutbound++; } @@ -1776,27 +1777,35 @@ void CConnman::ThreadOpenAddedConnections() vAddedNodes = mapMultiArgs.at("-addnode"); } - for (unsigned int i = 0; true; i++) + while (true) { + CSemaphoreGrant grant(*semAddnode); std::vector vInfo = GetAddedNodeInfo(); + bool tried = false; for (const AddedNodeInfo& info : vInfo) { if (!info.fConnected) { - CSemaphoreGrant grant(*semOutbound); + if (!grant.TryAcquire()) { + // If we've used up our semaphore and need a new one, lets not wait here since while we are waiting + // 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); + OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true); if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) return; } } - if (!interruptNet.sleep_for(std::chrono::minutes(2))) + // Retry every 60 seconds if a connection was attempted, otherwise two seconds + if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2))); return; } } // 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 CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode) { // // Initiate outbound network connection @@ -1825,6 +1834,8 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai pnode->fOneShot = true; if (fFeeler) pnode->fFeeler = true; + if (fAddnode) + pnode->fAddnode = true; return true; } @@ -2076,8 +2087,10 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe nSendBufferMaxSize = 0; nReceiveFloodSize = 0; semOutbound = NULL; + semAddnode = NULL; nMaxConnections = 0; nMaxOutbound = 0; + nMaxAddnode = 0; nBestHeight = 0; clientInterface = NULL; flagInterruptMsgProc = false; @@ -2099,6 +2112,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c nLocalServices = connOptions.nLocalServices; nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); + nMaxAddnode = connOptions.nMaxAddnode; nMaxFeeler = connOptions.nMaxFeeler; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; @@ -2151,6 +2165,10 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c // initialize semaphore semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); } + if (semAddnode == NULL) { + // initialize semaphore + semAddnode = new CSemaphore(nMaxAddnode); + } // // Start threads @@ -2227,6 +2245,10 @@ void CConnman::Stop() if (threadSocketHandler.joinable()) threadSocketHandler.join(); + if (semAddnode) + for (int i=0; ipost(); + if (fAddressesInitialized) { DumpData(); @@ -2254,6 +2276,8 @@ void CConnman::Stop() vhListenSocket.clear(); delete semOutbound; semOutbound = NULL; + delete semAddnode; + semAddnode = NULL; } void CConnman::DeleteNode(CNode* pnode) @@ -2554,6 +2578,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn strSubVer = ""; fWhitelisted = false; fOneShot = false; + fAddnode = false; fClient = false; // set by version message fFeeler = false; fSuccessfullyConnected = false; -- cgit v1.2.3 From 032ba3f0665432bd15ff76ee01cde245ad29e3e6 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 11 Dec 2016 20:26:06 +0000 Subject: RPC help documentation for addnode peerinfo. Also adds a comment about the netgroup exclusion behavior. --- src/net.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6640cc001..0f0a7bf8d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1633,6 +1633,11 @@ void CConnman::ThreadOpenConnections() LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { if (!pnode->fInbound && !pnode->fAddnode) { + // 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 + // also have the added issue that they're attacker controlled and could be used + // to prevent us from connecting to particular hosts if we used them here. setConnected.insert(pnode->addr.GetGroup()); nOutbound++; } -- cgit v1.2.3 From cc0589639cd0c9c417daff917f2fe7c516e59e03 Mon Sep 17 00:00:00 2001 From: Douglas Roark Date: Sat, 7 Jan 2017 09:49:14 -0800 Subject: Remove stray semicolon (Fix empty body warning) Empty body introduced by commit #9319 should not be empty. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 0f0a7bf8d..37e7dfed4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1804,7 +1804,7 @@ void CConnman::ThreadOpenAddedConnections() } } // Retry every 60 seconds if a connection was attempted, otherwise two seconds - if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2))); + if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2))) return; } } -- cgit v1.2.3 From 60befa3997b98d3f913010f2621bec734f643526 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:17 -0500 Subject: net: handle message accounting in ReceiveMsgBytes This allows locking to be pushed down to only where it's needed Also reuse the current time rather than checking multiple times. --- src/net.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 6d9971a0f..776047171 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -648,6 +648,9 @@ void CNode::copyStats(CNodeStats &stats) bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete) { complete = false; + int64_t nTimeMicros = GetTimeMicros(); + nLastRecv = nTimeMicros / 1000000; + nRecvBytes += nBytes; while (nBytes > 0) { // get current incomplete message, or create a new one @@ -685,7 +688,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete assert(i != mapRecvBytesPerMsgCmd.end()); i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE; - msg.nTime = GetTimeMicros(); + msg.nTime = nTimeMicros; complete = true; } } @@ -1237,8 +1240,6 @@ void CConnman::ThreadSocketHandler() pnode->CloseSocketDisconnect(); if(notify) condMsgProc.notify_one(); - pnode->nLastRecv = GetTime(); - pnode->nRecvBytes += nBytes; RecordBytesRecv(nBytes); } else if (nBytes == 0) -- cgit v1.2.3 From f5c36d19b636f01cc24417bc2b2f5b226ff3dd2c Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:19 -0500 Subject: net: record bytes written before notifying the message processor --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 776047171..312a6e094 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1238,9 +1238,9 @@ void CConnman::ThreadSocketHandler() bool notify = false; if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) pnode->CloseSocketDisconnect(); + RecordBytesRecv(nBytes); if(notify) condMsgProc.notify_one(); - RecordBytesRecv(nBytes); } else if (nBytes == 0) { -- cgit v1.2.3 From ef7b5ecbb73e9fd3670494c99cfc13ccf3574170 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:21 -0500 Subject: net: Add a simple function for waking the message handler This may be used publicly in the future --- src/net.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 312a6e094..36db77abb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1239,8 +1239,8 @@ void CConnman::ThreadSocketHandler() if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) pnode->CloseSocketDisconnect(); RecordBytesRecv(nBytes); - if(notify) - condMsgProc.notify_one(); + if (notify) + WakeMessageHandler(); } else if (nBytes == 0) { @@ -1315,8 +1315,10 @@ void CConnman::ThreadSocketHandler() } } - - +void CConnman::WakeMessageHandler() +{ + condMsgProc.notify_one(); +} -- cgit v1.2.3 From c5a8b1b946b1ab0bb82bd4270b2a40f5731abcff Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:26 -0500 Subject: net: rework the way that the messagehandler sleeps In order to sleep accurately, the message handler needs to know if _any_ node has more processing that it should do before the entire thread sleeps. Rather than returning a value that represents whether ProcessMessages encountered a message that should trigger a disconnnect, interpret the return value as whether or not that node has more work to do. Also, use a global fProcessWake value that can be set by other threads, which takes precedence (for one cycle) over the messagehandler's decision. Note that the previous behavior was to only process one message per loop (except in the case of a bad checksum or invalid header). That was changed in PR #3180. The only change here in that regard is that the current node now falls to the back of the processing queue for the bad checksum/invalid header cases. --- src/net.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 36db77abb..947f01679 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1317,6 +1317,10 @@ void CConnman::ThreadSocketHandler() void CConnman::WakeMessageHandler() { + { + std::lock_guard lock(mutexMsgProc); + fMsgProcWake = true; + } condMsgProc.notify_one(); } @@ -1839,7 +1843,7 @@ void CConnman::ThreadMessageHandler() } } - bool fSleep = true; + bool fMoreWork = false; BOOST_FOREACH(CNode* pnode, vNodesCopy) { @@ -1851,16 +1855,8 @@ void CConnman::ThreadMessageHandler() TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) { - if (!GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc)) - pnode->CloseSocketDisconnect(); - - if (pnode->nSendSize < GetSendBufferSize()) - { - if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg.front().complete())) - { - fSleep = false; - } - } + bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc); + fMoreWork |= (fMoreNodeWork && pnode->nSendSize < GetSendBufferSize()); } } if (flagInterruptMsgProc) @@ -1882,10 +1878,11 @@ void CConnman::ThreadMessageHandler() pnode->Release(); } - if (fSleep) { - std::unique_lock lock(mutexMsgProc); - condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100)); + std::unique_lock lock(mutexMsgProc); + if (!fMoreWork) { + condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100), [this] { return fMsgProcWake; }); } + fMsgProcWake = false; } } @@ -2156,6 +2153,11 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c interruptNet.reset(); flagInterruptMsgProc = false; + { + std::unique_lock lock(mutexMsgProc); + fMsgProcWake = false; + } + // Send and receive from sockets, accept connections threadSocketHandler = std::thread(&TraceThread >, "net", std::function(std::bind(&CConnman::ThreadSocketHandler, this))); -- cgit v1.2.3 From 4d712e366ca7fffaf96394ef01c9246482c0d92e Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:28 -0500 Subject: net: add a new message queue for the message processor This separates the storage of messages from the net and queued messages for processing, allowing the locks to be split. --- src/net.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 947f01679..df2109e3f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1239,8 +1239,18 @@ void CConnman::ThreadSocketHandler() if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) pnode->CloseSocketDisconnect(); RecordBytesRecv(nBytes); - if (notify) + if (notify) { + auto it(pnode->vRecvMsg.begin()); + for (; it != pnode->vRecvMsg.end(); ++it) { + if (!it->complete()) + break; + } + { + LOCK(pnode->cs_vProcessMsg); + pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it); + } WakeMessageHandler(); + } } else if (nBytes == 0) { -- cgit v1.2.3 From c6e8a9bcffe4c0f236e27c663f08785d1a0a783b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:30 -0500 Subject: net: add a flag to indicate when a node's process queue is full Messages are dumped very quickly from the socket handler to the processor, so it's the depth of the processing queue that's interesting. The socket handler checks the process queue's size during the brief message hand-off and pauses if necessary, and the processor possibly unpauses each time a message is popped off of its queue. --- src/net.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index df2109e3f..70c04d7a0 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1165,9 +1165,7 @@ void CConnman::ThreadSocketHandler() } { TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); - if (lockRecv && ( - pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() || - pnode->GetTotalRecvSize() <= GetReceiveFloodSize())) + if (lockRecv && !pnode->fPauseRecv) FD_SET(pnode->hSocket, &fdsetRecv); } } @@ -1240,14 +1238,18 @@ void CConnman::ThreadSocketHandler() pnode->CloseSocketDisconnect(); RecordBytesRecv(nBytes); if (notify) { + size_t nSizeAdded = 0; auto it(pnode->vRecvMsg.begin()); for (; it != pnode->vRecvMsg.end(); ++it) { if (!it->complete()) break; + nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE; } { LOCK(pnode->cs_vProcessMsg); pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it); + pnode->nProcessQueueSize += nSizeAdded; + pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize; } WakeMessageHandler(); } @@ -2592,6 +2594,8 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn minFeeFilter = 0; lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; + fPauseRecv = false; + nProcessQueueSize = 0; BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; -- cgit v1.2.3 From 991955ee81034dc3fbc1c2a8e60c04fc9e0b538c Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:32 -0500 Subject: net: add a flag to indicate when a node's send buffer is full Similar to the recv flag, but this one indicates whether or not the net's send buffer is full. The socket handler checks the send queue when a new message is added and pauses if necessary, and possibly unpauses after each message is drained from its buffer. --- src/net.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 70c04d7a0..8ae2bebd3 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -761,7 +761,7 @@ const uint256& CNetMessage::GetMessageHash() const // requires LOCK(cs_vSend) -size_t SocketSendData(CNode *pnode) +size_t CConnman::SocketSendData(CNode *pnode) { auto it = pnode->vSendMsg.begin(); size_t nSentSize = 0; @@ -778,6 +778,7 @@ size_t SocketSendData(CNode *pnode) if (pnode->nSendOffset == data.size()) { pnode->nSendOffset = 0; pnode->nSendSize -= data.size(); + pnode->fPauseSend = pnode->nSendSize > nSendBufferMaxSize; it++; } else { // could not send full message; stop sending more @@ -1286,8 +1287,9 @@ void CConnman::ThreadSocketHandler() TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) { size_t nBytes = SocketSendData(pnode); - if (nBytes) + if (nBytes) { RecordBytesSent(nBytes); + } } } @@ -1868,7 +1870,7 @@ void CConnman::ThreadMessageHandler() if (lockRecv) { bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc); - fMoreWork |= (fMoreNodeWork && pnode->nSendSize < GetSendBufferSize()); + fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); } } if (flagInterruptMsgProc) @@ -2595,6 +2597,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; fPauseRecv = false; + fPauseSend = false; nProcessQueueSize = 0; BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) @@ -2675,6 +2678,8 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) pnode->mapSendBytesPerMsgCmd[msg.command] += nTotalSize; pnode->nSendSize += nTotalSize; + if (pnode->nSendSize > nSendBufferMaxSize) + pnode->fPauseSend = true; pnode->vSendMsg.push_back(std::move(serializedHeader)); if (nMessageSize) pnode->vSendMsg.push_back(std::move(msg.data)); -- cgit v1.2.3 From e60360e139852c655930e99d4bb4db554cd8385e Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Sat, 31 Dec 2016 02:05:36 -0500 Subject: net: remove cs_vRecvMsg vRecvMsg is now only touched by the socket handler thread. The accounting vars (nRecvBytes/nLastRecv/mapRecvBytesPerMsgCmd) are also only used by the socket handler thread, with the exception of queries from rpc/gui. These accesses are not threadsafe, but they never were. This needs to be addressed separately. Also, update comment describing data flow --- src/net.cpp | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8ae2bebd3..11638fcc0 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -644,7 +644,6 @@ void CNode::copyStats(CNodeStats &stats) } #undef X -// requires LOCK(cs_vRecvMsg) bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete) { complete = false; @@ -1080,13 +1079,9 @@ void CConnman::ThreadSocketHandler() TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) { - TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); - if (lockRecv) - { TRY_LOCK(pnode->cs_inventory, lockInv); if (lockInv) fDelete = true; - } } } if (fDelete) @@ -1146,15 +1141,10 @@ void CConnman::ThreadSocketHandler() // write buffer in this case before receiving more. This avoids // needlessly queueing received data, if the remote peer is not themselves // receiving data. This means properly utilizing TCP flow control signalling. - // * Otherwise, if there is no (complete) message in the receive buffer, - // or there is space left in the buffer, select() for receiving data. - // * (if neither of the above applies, there is certainly one message - // in the receiver buffer ready to be processed). - // Together, that means that at least one of the following is always possible, - // so we don't deadlock: - // * We send some data. - // * We wait for data to be received (and disconnect after timeout). - // * We process a message in the buffer (message handler thread). + // * Otherwise, if there is space left in the receive buffer, select() for + // receiving data. + // * Hand off all complete messages to the processor, to be handled without + // blocking here. { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) { @@ -1165,8 +1155,7 @@ void CConnman::ThreadSocketHandler() } } { - TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); - if (lockRecv && !pnode->fPauseRecv) + if (!pnode->fPauseRecv) FD_SET(pnode->hSocket, &fdsetRecv); } } @@ -1225,8 +1214,6 @@ void CConnman::ThreadSocketHandler() continue; if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError)) { - TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); - if (lockRecv) { { // typical socket buffer is 8K-64K @@ -1865,14 +1852,8 @@ void CConnman::ThreadMessageHandler() continue; // Receive messages - { - TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); - if (lockRecv) - { - bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc); - fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); - } - } + bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc); + fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend); if (flagInterruptMsgProc) return; -- cgit v1.2.3 From d7c58ad514ee00db00589216166808258bc16b60 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 24 Dec 2016 14:34:20 -0500 Subject: Split CNode::cs_vSend: message processing and message sending cs_vSend is used for two purposes - to lock the datastructures used to queue messages to place on the wire and to only call SendMessages once at a time per-node. I believe SendMessages used to access some of the vSendMsg stuff, but it doesn't anymore, so these locks do not need to be on the same mutex, and also make deadlocking much more likely. --- src/net.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b275bdd80..e7b4562ea 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1147,12 +1147,10 @@ void CConnman::ThreadSocketHandler() // * Hand off all complete messages to the processor, to be handled without // blocking here. { - TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend) { - if (!pnode->vSendMsg.empty()) { - FD_SET(pnode->hSocket, &fdsetSend); - continue; - } + LOCK(pnode->cs_vSend); + if (!pnode->vSendMsg.empty()) { + FD_SET(pnode->hSocket, &fdsetSend); + continue; } } { @@ -1272,12 +1270,10 @@ void CConnman::ThreadSocketHandler() continue; if (FD_ISSET(pnode->hSocket, &fdsetSend)) { - TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend) { - size_t nBytes = SocketSendData(pnode); - if (nBytes) { - RecordBytesSent(nBytes); - } + LOCK(pnode->cs_vSend); + size_t nBytes = SocketSendData(pnode); + if (nBytes) { + RecordBytesSent(nBytes); } } @@ -1875,7 +1871,7 @@ void CConnman::ThreadMessageHandler() // Send messages { - TRY_LOCK(pnode->cs_vSend, lockSend); + TRY_LOCK(pnode->cs_sendProcessing, lockSend); if (lockSend) GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); } -- cgit v1.2.3 From 376b3c2c6e329357e4793c1d1b90d1dc0f30fed0 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 12 Jan 2017 20:08:52 -0800 Subject: Make the cs_sendProcessing a LOCK instead of a TRY_LOCK Technically cs_sendProcessing is entirely useless now because it is only ever taken on the one MessageHandler thread, but because there may be multiple of those in the future, it is left in place --- src/net.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e7b4562ea..1019d5954 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1871,9 +1871,8 @@ void CConnman::ThreadMessageHandler() // Send messages { - TRY_LOCK(pnode->cs_sendProcessing, lockSend); - if (lockSend) - GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); + LOCK(pnode->cs_sendProcessing); + GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc); } if (flagInterruptMsgProc) return; -- cgit v1.2.3 From 5be01906e59d484ec997b594e39bab528845bb78 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 24 Jan 2017 16:49:15 -0500 Subject: Delete some unused (and broken) functions in CConnman --- src/net.cpp | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 1019d5954..4e296a311 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2371,24 +2371,6 @@ void CConnman::GetNodeStats(std::vector& vstats) } } -bool CConnman::DisconnectAddress(const CNetAddr& netAddr) -{ - if (CNode* pnode = FindNode(netAddr)) { - pnode->fDisconnect = true; - return true; - } - return false; -} - -bool CConnman::DisconnectSubnet(const CSubNet& subNet) -{ - if (CNode* pnode = FindNode(subNet)) { - pnode->fDisconnect = true; - return true; - } - return false; -} - bool CConnman::DisconnectNode(const std::string& strNode) { if (CNode* pnode = FindNode(strNode)) { @@ -2409,16 +2391,6 @@ bool CConnman::DisconnectNode(NodeId id) return false; } -void CConnman::RelayTransaction(const CTransaction& tx) -{ - CInv inv(MSG_TX, tx.GetHash()); - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - pnode->PushInventory(inv); - } -} - void CConnman::RecordBytesRecv(uint64_t bytes) { LOCK(cs_totalBytesRecv); -- cgit v1.2.3 From 3c37dc40d39e1a1e56b6b0d3e660626a78656d4f Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 24 Jan 2017 16:50:27 -0500 Subject: Ensure cs_vNodes is held when using the return value from FindNode --- src/net.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4e296a311..7489b3f32 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -369,15 +369,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo // 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 // name catch this early. + LOCK(cs_vNodes); CNode* pnode = FindNode((CService)addrConnect); if (pnode) { pnode->AddRef(); - { - LOCK(cs_vNodes); - if (pnode->addrName.empty()) { - pnode->addrName = std::string(pszDest); - } + if (pnode->addrName.empty()) { + pnode->addrName = std::string(pszDest); } CloseSocket(hSocket); return pnode; @@ -2373,6 +2371,7 @@ void CConnman::GetNodeStats(std::vector& vstats) bool CConnman::DisconnectNode(const std::string& strNode) { + LOCK(cs_vNodes); if (CNode* pnode = FindNode(strNode)) { pnode->fDisconnect = true; return true; -- cgit v1.2.3 From 99464bc38e9575ff47f8e33223b252dcea2055e3 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 19 Jan 2017 13:01:18 -0500 Subject: net: Consistently use GetTimeMicros() for inactivity checks The use of mocktime in test logic means that comparisons between GetTime() and GetTimeMicros()/1000000 are unreliable since the former can use mocktime values while the latter always gets the system clock; this changes the networking code's inactivity checks to consistently use the system clock for inactivity comparisons. Also remove some hacks from setmocktime() that are no longer needed, now that we're using the system clock for nLastSend and nLastRecv. --- src/net.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b275bdd80..97480df13 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -391,7 +391,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false); pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); - pnode->nTimeConnected = GetTime(); + pnode->nTimeConnected = GetSystemTimeInSeconds(); pnode->AddRef(); GetNodeSignals().InitializeNode(pnode, *this); { @@ -771,7 +771,7 @@ size_t CConnman::SocketSendData(CNode *pnode) assert(data.size() > pnode->nSendOffset); int nBytes = send(pnode->hSocket, reinterpret_cast(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); if (nBytes > 0) { - pnode->nLastSend = GetTime(); + pnode->nLastSend = GetSystemTimeInSeconds(); pnode->nSendBytes += nBytes; pnode->nSendOffset += nBytes; nSentSize += nBytes; @@ -1284,7 +1284,7 @@ void CConnman::ThreadSocketHandler() // // Inactivity checking // - int64_t nTime = GetTime(); + int64_t nTime = GetSystemTimeInSeconds(); if (nTime - pnode->nTimeConnected > 60) { if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) @@ -2570,7 +2570,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nLastRecv = 0; nSendBytes = 0; nRecvBytes = 0; - nTimeConnected = GetTime(); + nTimeConnected = GetSystemTimeInSeconds(); nTimeOffset = 0; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; -- cgit v1.2.3 From 236618061a445d2cb11e722cfac5fdae5be26abb Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 24 Jan 2017 16:51:22 -0500 Subject: Do not add to vNodes until fOneShot/fFeeler/fAddNode have been set --- src/net.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 7489b3f32..108d95a17 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -342,8 +342,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo CNode* pnode = FindNode((CService)addrConnect); if (pnode) { - pnode->AddRef(); - return pnode; + LogPrintf("Failed to open new connection, already connected\n"); + return NULL; } } @@ -373,12 +373,12 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo CNode* pnode = FindNode((CService)addrConnect); if (pnode) { - pnode->AddRef(); if (pnode->addrName.empty()) { pnode->addrName = std::string(pszDest); } CloseSocket(hSocket); - return pnode; + LogPrintf("Failed to open new connection, already connected\n"); + return NULL; } } @@ -391,11 +391,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); pnode->nTimeConnected = GetTime(); pnode->AddRef(); - GetNodeSignals().InitializeNode(pnode, *this); - { - LOCK(cs_vNodes); - vNodes.push_back(pnode); - } return pnode; } else if (!proxyConnectionFailed) { @@ -1838,6 +1833,12 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai if (fAddnode) pnode->fAddnode = true; + { + LOCK(cs_vNodes); + vNodes.push_back(pnode); + } + GetNodeSignals().InitializeNode(pnode, *this); + return true; } -- cgit v1.2.3 From d45955fa0992639d6c9856a73c5f7599cc14f811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Tue, 24 Jan 2017 02:32:52 +0100 Subject: Net: CConnman: Make some methods const --- src/net.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index df88b12c7..5a5d94cd1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -754,7 +754,7 @@ const uint256& CNetMessage::GetMessageHash() const // requires LOCK(cs_vSend) -size_t CConnman::SocketSendData(CNode *pnode) +size_t CConnman::SocketSendData(CNode *pnode) const { auto it = pnode->vSendMsg.begin(); size_t nSentSize = 0; @@ -2687,12 +2687,12 @@ int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) +CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const { return CSipHasher(nSeed0, nSeed1).Write(id); } -uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) +uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const { std::vector vchNetGroup(ad.GetGroup()); -- cgit v1.2.3 From 885cfdd2179a2aae733d0690f5a2ef23d181768e Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 2 Feb 2017 13:51:57 -0500 Subject: Fix super-unlikely race introduced in 236618061a445d2cb11e72 Once the CNode has been added to vNodes, it is possible that it is disconnected+deleted in the socket handler thread. However, after that we now call InitializeNode, which accesses the pnode. helgrind managed to tickle this case (somehow), but I suspect it requires in immensely braindead scheduler. --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index df88b12c7..35d3348ad 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1833,11 +1833,11 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai if (fAddnode) pnode->fAddnode = true; + GetNodeSignals().InitializeNode(pnode, *this); { LOCK(cs_vNodes); vNodes.push_back(pnode); } - GetNodeSignals().InitializeNode(pnode, *this); return true; } -- cgit v1.2.3 From 12752af0cc99745d6273ef072645d999c26a9ef7 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 20 Jan 2017 20:34:57 -0500 Subject: net: don't run callbacks on nodes that haven't completed the version handshake Since ForEach* are can be used to send messages to all nodes, the caller may end up sending a message before the version handshake is complete. To limit this, filter out these nodes. While we're at it, may as well filter out disconnected nodes as well. Delete unused methods rather than updating them. --- src/net.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index df88b12c7..19358dd5b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2630,6 +2630,11 @@ void CNode::AskFor(const CInv& inv) mapAskFor.insert(std::make_pair(nRequestTime, inv)); } +bool CConnman::NodeFullyConnected(const CNode* pnode) +{ + return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect; +} + void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) { size_t nMessageSize = msg.data.size(); @@ -2680,7 +2685,7 @@ bool CConnman::ForNode(NodeId id, std::function func) break; } } - return found != nullptr && func(found); + return found != nullptr && NodeFullyConnected(found) && func(found); } int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { -- cgit v1.2.3 From 08bb6f4ed48359aedd869450b99799b9c734084b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 2 Feb 2017 14:33:41 -0500 Subject: net: log an error rather than asserting if send version is misused Also cleaned up the comments and moved from the header to the .cpp so that logging headers aren't needed from net.h --- src/net.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 19358dd5b..db914096f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -689,6 +689,33 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete return true; } +void CNode::SetSendVersion(int nVersionIn) +{ + // Send version may only be changed in the version message, and + // only one version message is allowed per session. We can therefore + // treat this value as const and even atomic as long as it's only used + // once a version message has been successfully processed. Any attempt to + // set this twice is an error. + if (nSendVersion != 0) { + error("Send version already set for node: %i. Refusing to change from %i to %i", id, nSendVersion, nVersionIn); + } else { + nSendVersion = nVersionIn; + } +} + +int CNode::GetSendVersion() const +{ + // The send version should always be explicitly set to + // INIT_PROTO_VERSION rather than using this value until SetSendVersion + // has been called. + if (nSendVersion == 0) { + error("Requesting unset send version for node: %i. Using %i", id, INIT_PROTO_VERSION); + return INIT_PROTO_VERSION; + } + return nSendVersion; +} + + int CNetMessage::readHeader(const char *pch, unsigned int nBytes) { // copy data to temporary parsing buffer -- cgit v1.2.3 From fd13eca147be80f3ebd1a5a1db1ce75bbeeb1953 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 2 Feb 2017 20:03:46 -0500 Subject: Lock cs_vSend and cs_inventory in a consistent order even in TRY --- src/net.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index df88b12c7..5cddc6f44 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1070,12 +1070,13 @@ void CConnman::ThreadSocketHandler() { bool fDelete = false; { - TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend) + TRY_LOCK(pnode->cs_inventory, lockInv); + if (lockInv) { - TRY_LOCK(pnode->cs_inventory, lockInv); - if (lockInv) - fDelete = true; + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend) { + fDelete = true; + } } } if (fDelete) -- cgit v1.2.3 From 2a962d4540a253f63803d1f145fa26b938e69633 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 4 Feb 2017 16:44:05 -0500 Subject: Fixup style a bit by moving { to the same line as if statements --- src/net.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 5cddc6f44..704d3b8d3 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1066,21 +1066,18 @@ void CConnman::ThreadSocketHandler() BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy) { // wait until threads are done using it - if (pnode->GetRefCount() <= 0) - { + if (pnode->GetRefCount() <= 0) { bool fDelete = false; { TRY_LOCK(pnode->cs_inventory, lockInv); - if (lockInv) - { + if (lockInv) { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) { fDelete = true; } } } - if (fDelete) - { + if (fDelete) { vNodesDisconnected.remove(pnode); DeleteNode(pnode); } -- cgit v1.2.3 From 45e2e085612463dd9cca9f1b221733afa6d52991 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 6 Feb 2017 13:47:24 -0500 Subject: net: rearrange so that socket accesses can be grouped together --- src/net.cpp | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4d0d781d6..b47514fd9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1152,9 +1152,6 @@ void CConnman::ThreadSocketHandler() { if (pnode->hSocket == INVALID_SOCKET) continue; - FD_SET(pnode->hSocket, &fdsetError); - hSocketMax = std::max(hSocketMax, pnode->hSocket); - have_fds = true; // Implement the following logic: // * If there is data to send, select() for sending data. As this only @@ -1166,16 +1163,24 @@ void CConnman::ThreadSocketHandler() // receiving data. // * Hand off all complete messages to the processor, to be handled without // blocking here. + + bool select_recv = !pnode->fPauseRecv; + bool select_send; { LOCK(pnode->cs_vSend); - if (!pnode->vSendMsg.empty()) { - FD_SET(pnode->hSocket, &fdsetSend); - continue; - } + select_send = !pnode->vSendMsg.empty(); } - { - if (!pnode->fPauseRecv) - FD_SET(pnode->hSocket, &fdsetRecv); + + FD_SET(pnode->hSocket, &fdsetError); + hSocketMax = std::max(hSocketMax, pnode->hSocket); + have_fds = true; + + if (select_send) { + FD_SET(pnode->hSocket, &fdsetSend); + continue; + } + if (select_recv) { + FD_SET(pnode->hSocket, &fdsetRecv); } } } @@ -1229,9 +1234,15 @@ void CConnman::ThreadSocketHandler() // // Receive // + bool recvSet = false; + bool sendSet = false; + bool errorSet = false; if (pnode->hSocket == INVALID_SOCKET) continue; - if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError)) + recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv); + sendSet = FD_ISSET(pnode->hSocket, &fdsetSend); + errorSet = FD_ISSET(pnode->hSocket, &fdsetError); + if (recvSet || errorSet) { { { @@ -1286,9 +1297,7 @@ void CConnman::ThreadSocketHandler() // // Send // - if (pnode->hSocket == INVALID_SOCKET) - continue; - if (FD_ISSET(pnode->hSocket, &fdsetSend)) + if (sendSet) { LOCK(pnode->cs_vSend); size_t nBytes = SocketSendData(pnode); -- cgit v1.2.3 From 9a0b784deaab6b9fffcab227d928987b981d0572 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 6 Feb 2017 14:05:45 -0500 Subject: net: add a lock around hSocket --- src/net.cpp | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b47514fd9..2625cccaa 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -425,6 +425,7 @@ void CConnman::DumpBanlist() void CNode::CloseSocketDisconnect() { fDisconnect = true; + LOCK(cs_hSocket); if (hSocket != INVALID_SOCKET) { LogPrint("net", "disconnecting peer=%d\n", id); @@ -789,7 +790,13 @@ size_t CConnman::SocketSendData(CNode *pnode) const while (it != pnode->vSendMsg.end()) { const auto &data = *it; assert(data.size() > pnode->nSendOffset); - int nBytes = send(pnode->hSocket, reinterpret_cast(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); + int nBytes = 0; + { + LOCK(pnode->cs_hSocket); + if (pnode->hSocket == INVALID_SOCKET) + break; + nBytes = send(pnode->hSocket, reinterpret_cast(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); + } if (nBytes > 0) { pnode->nLastSend = GetSystemTimeInSeconds(); pnode->nSendBytes += nBytes; @@ -1150,9 +1157,6 @@ void CConnman::ThreadSocketHandler() LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - if (pnode->hSocket == INVALID_SOCKET) - continue; - // Implement the following logic: // * If there is data to send, select() for sending data. As this only // happens when optimistic write failed, we choose to first drain the @@ -1171,6 +1175,10 @@ void CConnman::ThreadSocketHandler() select_send = !pnode->vSendMsg.empty(); } + LOCK(pnode->cs_hSocket); + if (pnode->hSocket == INVALID_SOCKET) + continue; + FD_SET(pnode->hSocket, &fdsetError); hSocketMax = std::max(hSocketMax, pnode->hSocket); have_fds = true; @@ -1237,18 +1245,27 @@ void CConnman::ThreadSocketHandler() bool recvSet = false; bool sendSet = false; bool errorSet = false; - if (pnode->hSocket == INVALID_SOCKET) - continue; - recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv); - sendSet = FD_ISSET(pnode->hSocket, &fdsetSend); - errorSet = FD_ISSET(pnode->hSocket, &fdsetError); + { + LOCK(pnode->cs_hSocket); + if (pnode->hSocket == INVALID_SOCKET) + continue; + recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv); + sendSet = FD_ISSET(pnode->hSocket, &fdsetSend); + errorSet = FD_ISSET(pnode->hSocket, &fdsetError); + } if (recvSet || errorSet) { { { // typical socket buffer is 8K-64K char pchBuf[0x10000]; - int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); + int nBytes = 0; + { + LOCK(pnode->cs_hSocket); + if (pnode->hSocket == INVALID_SOCKET) + continue; + nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); + } if (nBytes > 0) { bool notify = false; @@ -2286,8 +2303,7 @@ void CConnman::Stop() // Close sockets BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->hSocket != INVALID_SOCKET) - CloseSocket(pnode->hSocket); + pnode->CloseSocketDisconnect(); BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket) if (hListenSocket.socket != INVALID_SOCKET) if (!CloseSocket(hListenSocket.socket)) @@ -2688,9 +2704,6 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) size_t nBytesSent = 0; { LOCK(pnode->cs_vSend); - if(pnode->hSocket == INVALID_SOCKET) { - return; - } bool optimisticSend(pnode->vSendMsg.empty()); //log total amount of bytes per command -- cgit v1.2.3 From 2cbd1196b7a07b08cfd91417f2e8ddd09d9f2082 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 7 Feb 2017 15:23:17 -0500 Subject: Disconnect peers which we do not receive VERACKs from within 60 sec --- src/net.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 4d0d781d6..3394f8a08 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1323,6 +1323,11 @@ void CConnman::ThreadSocketHandler() LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart)); pnode->fDisconnect = true; } + else if (!pnode->fSuccessfullyConnected) + { + LogPrintf("version handshake timeout from %d\n", pnode->id); + pnode->fDisconnect = true; + } } } { -- cgit v1.2.3 From 321d0fc6b6624c65508f8b9059418cb936f0bbbe Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 6 Feb 2017 02:34:57 -0500 Subject: net: fix a few races. Credit @TheBlueMatt These are (afaik) all long-standing races or concurrent accesses. Going forward, we can clean these up so that they're not all individual atomic accesses. - Reintroduce cs_vRecv to guard receive-specific vars - Lock vRecv/vSend for CNodeStats - Make some vars atomic. - Only set the connection time in CNode's constructor so that it doesn't change --- src/net.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 7c45cff1d..c96ca469f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -389,7 +389,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false); pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); - pnode->nTimeConnected = GetSystemTimeInSeconds(); pnode->AddRef(); return pnode; @@ -612,10 +611,16 @@ void CNode::copyStats(CNodeStats &stats) X(fInbound); X(fAddnode); X(nStartingHeight); - X(nSendBytes); - X(mapSendBytesPerMsgCmd); - X(nRecvBytes); - X(mapRecvBytesPerMsgCmd); + { + LOCK(cs_vSend); + X(mapSendBytesPerMsgCmd); + X(nSendBytes); + } + { + LOCK(cs_vRecv); + X(mapRecvBytesPerMsgCmd); + X(nRecvBytes); + } X(fWhitelisted); // It is common for nodes with good ping times to suddenly become lagged, @@ -643,6 +648,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete { complete = false; int64_t nTimeMicros = GetTimeMicros(); + LOCK(cs_vRecv); nLastRecv = nTimeMicros / 1000000; nRecvBytes += nBytes; while (nBytes > 0) { -- cgit v1.2.3 From 644f1234e22626a7b5618a1dae60a8457a4063b1 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 6 Feb 2017 11:42:49 -0500 Subject: Make nTimeConnected const in CNode --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index c96ca469f..0e6e00d58 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2574,6 +2574,7 @@ 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 std::string& addrNameIn, bool fInboundIn) : + nTimeConnected(GetSystemTimeInSeconds()), addr(addrIn), fInbound(fInboundIn), id(idIn), @@ -2593,7 +2594,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nLastRecv = 0; nSendBytes = 0; nRecvBytes = 0; - nTimeConnected = GetSystemTimeInSeconds(); nTimeOffset = 0; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; -- cgit v1.2.3 From ae683c1b1960b32134f5a5a29504691c91f39cf3 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 6 Feb 2017 11:44:38 -0500 Subject: Avoid copying CNodeStats to make helgrind OK with buggy std::string --- src/net.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 0e6e00d58..b7243dce2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2420,9 +2420,8 @@ void CConnman::GetNodeStats(std::vector& vstats) vstats.reserve(vNodes.size()); for(std::vector::iterator it = vNodes.begin(); it != vNodes.end(); ++it) { CNode* pnode = *it; - CNodeStats stats; - pnode->copyStats(stats); - vstats.push_back(stats); + vstats.emplace_back(); + pnode->copyStats(vstats.back()); } } -- cgit v1.2.3 From 512731bed0782f10092de35a960153b17ecc11eb Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 6 Feb 2017 11:53:34 -0500 Subject: Access fRelayTxes with cs_filter lock in copyStats --- src/net.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index b7243dce2..ea8a2a0a4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -600,7 +600,10 @@ void CNode::copyStats(CNodeStats &stats) stats.nodeid = this->GetId(); X(nServices); X(addr); - X(fRelayTxes); + { + LOCK(cs_filter); + X(fRelayTxes); + } X(nLastSend); X(nLastRecv); X(nTimeConnected); -- cgit v1.2.3 From 22b4966a29501c4f3f2e970ac5008fbd91e665a9 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 6 Feb 2017 12:08:31 -0500 Subject: Move [clean|str]SubVer writes/copyStats into a lock --- src/net.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index ea8a2a0a4..e7521f86d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -610,7 +610,10 @@ void CNode::copyStats(CNodeStats &stats) X(nTimeOffset); X(addrName); X(nVersion); - X(cleanSubVer); + { + LOCK(cs_SubVer); + X(cleanSubVer); + } X(fInbound); X(fAddnode); X(nStartingHeight); -- cgit v1.2.3 From 036073bf87c07f8d69e39168dd93a52f1aafe85c Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 6 Feb 2017 12:04:34 -0500 Subject: Move CNode::addrName accesses behind locked accessors --- src/net.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e7521f86d..8aa126198 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -307,9 +307,11 @@ CNode* CConnman::FindNode(const CSubNet& subNet) CNode* CConnman::FindNode(const std::string& addrName) { LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if (pnode->addrName == addrName) + BOOST_FOREACH(CNode* pnode, vNodes) { + if (pnode->GetAddrName() == addrName) { return (pnode); + } + } return NULL; } @@ -373,9 +375,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo CNode* pnode = FindNode((CService)addrConnect); if (pnode) { - if (pnode->addrName.empty()) { - pnode->addrName = std::string(pszDest); - } + pnode->MaybeSetAddrName(std::string(pszDest)); CloseSocket(hSocket); LogPrintf("Failed to open new connection, already connected\n"); return NULL; @@ -593,6 +593,19 @@ void CConnman::AddWhitelistedRange(const CSubNet &subnet) { vWhitelistedRange.push_back(subnet); } + +std::string CNode::GetAddrName() const { + LOCK(cs_addrName); + return addrName; +} + +void CNode::MaybeSetAddrName(const std::string& addrNameIn) { + LOCK(cs_addrName); + if (addrName.empty()) { + addrName = addrNameIn; + } +} + #undef X #define X(name) stats.name = name void CNode::copyStats(CNodeStats &stats) @@ -608,7 +621,7 @@ void CNode::copyStats(CNodeStats &stats) X(nLastRecv); X(nTimeConnected); X(nTimeOffset); - X(addrName); + stats.addrName = GetAddrName(); X(nVersion); { LOCK(cs_SubVer); @@ -1798,8 +1811,9 @@ std::vector CConnman::GetAddedNodeInfo() if (pnode->addr.IsValid()) { mapConnected[pnode->addr] = pnode->fInbound; } - if (!pnode->addrName.empty()) { - mapConnectedByName[pnode->addrName] = std::make_pair(pnode->fInbound, static_cast(pnode->addr)); + std::string addrName = pnode->GetAddrName(); + if (!addrName.empty()) { + mapConnectedByName[std::move(addrName)] = std::make_pair(pnode->fInbound, static_cast(pnode->addr)); } } } -- cgit v1.2.3 From db2dc7a58cb0a3df58188b748df8e0d04ba76f00 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 6 Feb 2017 12:18:51 -0500 Subject: Move CNode::addrLocal access behind locked accessors --- src/net.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 8aa126198..505eb971c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -164,8 +164,9 @@ int GetnScore(const CService& addr) // Is our peer's addrLocal potentially useful as an external IP source? bool IsPeerAddrLocalGood(CNode *pnode) { - return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() && - !IsLimited(pnode->addrLocal.GetNetwork()); + CService addrLocal = pnode->GetAddrLocal(); + return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() && + !IsLimited(addrLocal.GetNetwork()); } // pushes our own address to a peer @@ -180,7 +181,7 @@ void AdvertiseLocal(CNode *pnode) if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() || GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0)) { - addrLocal.SetIP(pnode->addrLocal); + addrLocal.SetIP(pnode->GetAddrLocal()); } if (addrLocal.IsRoutable()) { @@ -606,6 +607,20 @@ void CNode::MaybeSetAddrName(const std::string& addrNameIn) { } } +CService CNode::GetAddrLocal() const { + LOCK(cs_addrLocal); + return addrLocal; +} + +void CNode::SetAddrLocal(const CService& addrLocalIn) { + LOCK(cs_addrLocal); + if (addrLocal.IsValid()) { + error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString()); + } else { + addrLocal = addrLocalIn; + } +} + #undef X #define X(name) stats.name = name void CNode::copyStats(CNodeStats &stats) @@ -659,7 +674,8 @@ void CNode::copyStats(CNodeStats &stats) stats.dPingWait = (((double)nPingUsecWait) / 1e6); // Leave string empty if addrLocal invalid (not filled in yet) - stats.addrLocal = addrLocal.IsValid() ? addrLocal.ToString() : ""; + CService addrLocalUnlocked = GetAddrLocal(); + stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : ""; } #undef X -- cgit v1.2.3 From d2548a4f9704b1f475b4068d2d1686cf3780f742 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 8 Mar 2017 14:41:57 -0500 Subject: Fix shutdown hang with >= 8 -addnodes set We previously would block waiting for a CSemaphoreGrant in ThreadOpenAddedConnections, when we did not need to. This would block as the posts in CConnman shutdown were both to the wrong semaphore and in the wrong location. Github-Pull: #9953 Rebased-From: e007b243c4840e44857b5ccf686ed35899e44af0 --- src/net.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index de5fc2969..e35a89e74 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2321,6 +2321,10 @@ void CConnman::Interrupt() if (semOutbound) for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) semOutbound->post(); + + if (semAddnode) + for (int i=0; ipost(); } void CConnman::Stop() @@ -2336,10 +2340,6 @@ void CConnman::Stop() if (threadSocketHandler.joinable()) threadSocketHandler.join(); - if (semAddnode) - for (int i=0; ipost(); - if (fAddressesInitialized) { DumpData(); -- cgit v1.2.3 From 4e2502bb512c00fa76c59ed8c758c2a6781a7425 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 8 Mar 2017 14:55:28 -0500 Subject: Add missing braces in semaphore posts in net Github-Pull: #9953 Rebased-From: 819b513a5415d1669b5440e214862cda6c2261f8 --- src/net.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index e35a89e74..03c8e5ecc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2318,13 +2318,17 @@ void CConnman::Interrupt() interruptNet(); InterruptSocks5(true); - if (semOutbound) - for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) + if (semOutbound) { + for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) { semOutbound->post(); + } + } - if (semAddnode) - for (int i=0; ipost(); + } + } } void CConnman::Stop() -- cgit v1.2.3 From 37a8fc54d480788a06ff17415128d815ac55eaed Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Thu, 18 May 2017 16:57:53 -0400 Subject: Populate services in GetLocalAddress Previously if we didn't have any local addresses, GetLocalAddress would return 0.0.0.0 and then we'd swap in a peer's notion of our address in AdvertiseLocal, but then nServices would never get set. Github-Pull: #10424 Rebased-From: 307013469f9a3b8f13d3eb9dbeea419a55148493 --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 03c8e5ecc..5593f81ef 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -143,7 +143,7 @@ static std::vector convertSeed6(const std::vector &vSeedsIn // one by discovery. CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) { - CAddress ret(CService(CNetAddr(),GetListenPort()), NODE_NONE); + CAddress ret(CService(CNetAddr(),GetListenPort()), nLocalServices); CService addr; if (GetLocal(addr, paddrPeer)) { -- cgit v1.2.3 From 0aee4a132b6d3be276503c517cb2b7f07d774bf6 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 14 Apr 2017 16:29:57 -0400 Subject: Check interruptNet during dnsseed lookups --- src/net.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 5593f81ef..2fca99474 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1579,6 +1579,9 @@ void CConnman::ThreadDNSAddressSeed() LogPrintf("Loading addresses from DNS seeds (could take a while)\n"); BOOST_FOREACH(const CDNSSeedData &seed, vSeeds) { + if (interruptNet) { + return; + } if (HaveNameProxy()) { AddOneShot(seed.host); } else { @@ -1596,6 +1599,9 @@ void CConnman::ThreadDNSAddressSeed() found++; } } + if (interruptNet) { + return; + } // TODO: The seed name resolve may fail, yielding an IP of [::], which results in // addrman assigning the same source to results from different seeds. // This should switch to a hard-coded stable dummy IP for each seed name, so that the -- cgit v1.2.3 From 9e3ad500780b284765654cff4144451c7fa5ef6b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 24 May 2017 17:00:27 -0400 Subject: net: only enforce the services required to connect also once half of all outgoing nodes have our preferred flags, require only minimal flags from the rest. Github-Pull: #10441 Rebased-From: b6fbfc228236947eaea5c14dda299f5a01810e92 --- src/net.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 2fca99474..1752c7707 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1722,11 +1722,17 @@ 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 > setConnected; { LOCK(cs_vNodes); BOOST_FOREACH(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++; + } // 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 @@ -1790,14 +1796,27 @@ void CConnman::ThreadOpenConnections() continue; // only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up. - if ((addr.nServices & nRelevantServices) != nRelevantServices && (nTries < 40 || nOutbound >= (nMaxOutbound >> 1))) + ServiceFlags nRequiredServices = nRelevantServices; + if (nTries >= 40 && nOutbound < (nMaxOutbound >> 1)) { + nRequiredServices = REQUIRED_SERVICES; + } + + if ((addr.nServices & nRequiredServices) != nRequiredServices) { continue; + } // do not allow non-default ports, unless after 50 invalid addresses selected already if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50) 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; } -- cgit v1.2.3 From d289b564e3ae125cb54c3d9157a13e7bad48c5f5 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 19 Apr 2017 12:49:11 -0400 Subject: [net] listbanned RPC and QT should show correct banned subnets Github-Pull: #10234 Rebased-From: 77c54b270dd3b469d662c8f69e06f7b00fc4136d --- src/net.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 1752c7707..5bc886c34 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -413,10 +413,10 @@ void CConnman::DumpBanlist() CBanDB bandb; banmap_t banmap; - SetBannedSetDirty(false); GetBanned(banmap); - if (!bandb.Write(banmap)) - SetBannedSetDirty(true); + if (bandb.Write(banmap)) { + SetBannedSetDirty(false); + } LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); @@ -536,6 +536,8 @@ bool CConnman::Unban(const CSubNet &subNet) { void CConnman::GetBanned(banmap_t &banMap) { LOCK(cs_setBanned); + // Sweep the banlist so expired bans are not returned + SweepBanned(); banMap = setBanned; //create a thread safe copy } -- cgit v1.2.3 From 148a2aca05fe98031bcf857fa186d792c507090c Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Mon, 27 Jul 2015 16:35:30 +0100 Subject: Introduce basic Dogecoin branding --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 5bc886c34..e89f1b11d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1468,7 +1468,7 @@ void ThreadMapPort() } } - std::string strDesc = "Bitcoin " + FormatFullVersion(); + std::string strDesc = "Dogecoin " + FormatFullVersion(); try { while (true) { -- cgit v1.2.3