From 321d0fc6b6624c65508f8b9059418cb936f0bbbe Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 6 Feb 2017 02:34:57 -0500 Subject: [PATCH] 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 +++++++++++----- src/net.h | 19 ++++++++++--------- src/net_processing.cpp | 2 +- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 7c45cff1dd2..c96ca469ff6 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) { diff --git a/src/net.h b/src/net.h index e5a19e0f43e..89501c764e5 100644 --- a/src/net.h +++ b/src/net.h @@ -573,6 +573,7 @@ public: std::deque> vSendMsg; CCriticalSection cs_vSend; CCriticalSection cs_hSocket; + CCriticalSection cs_vRecv; CCriticalSection cs_vProcessMsg; std::list vProcessMsg; @@ -584,10 +585,10 @@ public: uint64_t nRecvBytes; std::atomic nRecvVersion; - int64_t nLastSend; - int64_t nLastRecv; + std::atomic nLastSend; + std::atomic nLastRecv; int64_t nTimeConnected; - int64_t nTimeOffset; + std::atomic nTimeOffset; const CAddress addr; std::string addrName; CService addrLocal; @@ -614,7 +615,7 @@ public: CSemaphoreGrant grantOutbound; CCriticalSection cs_filter; CBloomFilter* pfilter; - int nRefCount; + std::atomic nRefCount; const NodeId id; const uint64_t nKeyedNetGroup; @@ -665,15 +666,15 @@ public: // Ping time measurement: // The pong reply we're expecting, or 0 if no pong expected. - uint64_t nPingNonceSent; + std::atomic nPingNonceSent; // Time (in usec) the last ping was sent, or 0 if no ping was ever sent. - int64_t nPingUsecStart; + std::atomic nPingUsecStart; // Last measured round-trip time. - int64_t nPingUsecTime; + std::atomic nPingUsecTime; // Best measured round-trip time. - int64_t nMinPingUsecTime; + std::atomic nMinPingUsecTime; // Whether a ping is requested. - bool fPingQueued; + std::atomic fPingQueued; // Minimum fee rate with which to filter inv's to this node CAmount minFeeFilter; CCriticalSection cs_feeFilter; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index bb14e69d83c..e89a897bd54 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2450,7 +2450,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (pingUsecTime > 0) { // Successful ping time measurement, replace previous pfrom->nPingUsecTime = pingUsecTime; - pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime); + pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime); } else { // This should never happen sProblem = "Timing mishap";