diff --git a/src/init.cpp b/src/init.cpp index f618e5ccc..a7f893c24 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1240,7 +1240,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif if (mapArgs.count("-maxuploadtarget")) { - CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); + connman.SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); } // ********************************************************* Step 7: load block chain diff --git a/src/main.cpp b/src/main.cpp index 43ccb6374..019db0bdb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4766,7 +4766,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); } -void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams) +void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman) { std::deque::iterator it = pfrom->vRecvGetData.begin(); @@ -4808,7 +4808,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // disconnect node in case we have reached the outbound limit for serving historical blocks // never disconnect whitelisted nodes static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical - if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) + if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) { LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); @@ -5312,7 +5312,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); - ProcessGetData(pfrom, chainparams.GetConsensus()); + ProcessGetData(pfrom, chainparams.GetConsensus(), connman); } @@ -5986,7 +5986,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } - if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted) + if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted) { LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); pfrom->fDisconnect = true; @@ -6202,7 +6202,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman) bool fOk = true; if (!pfrom->vRecvGetData.empty()) - ProcessGetData(pfrom, chainparams.GetConsensus()); + ProcessGetData(pfrom, chainparams.GetConsensus(), connman); // this maintains the order of responses if (!pfrom->vRecvGetData.empty()) return fOk; 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); } diff --git a/src/net.h b/src/net.h index 503e009c4..e2d98a90d 100644 --- a/src/net.h +++ b/src/net.h @@ -171,6 +171,31 @@ public: bool DisconnectSubnet(const CSubNet& subnet); void AddWhitelistedRange(const CSubNet &subnet); + + //!set the max outbound target in bytes + void SetMaxOutboundTarget(uint64_t limit); + uint64_t GetMaxOutboundTarget(); + + //!set the timeframe for the max outbound target + void SetMaxOutboundTimeframe(uint64_t timeframe); + uint64_t GetMaxOutboundTimeframe(); + + //!check if the outbound target is reached + // if param historicalBlockServingLimit is set true, the function will + // response true if the limit for serving historical blocks has been reached + bool OutboundTargetReached(bool historicalBlockServingLimit); + + //!response the bytes left in the current max outbound cycle + // in case of no limit, it will always response 0 + uint64_t GetOutboundTargetBytesLeft(); + + //!response the time in second left in the current max outbound cycle + // in case of no limit, it will always response 0 + uint64_t GetMaxOutboundTimeLeftInCycle(); + + uint64_t GetTotalBytesRecv(); + uint64_t GetTotalBytesSent(); + private: struct ListenSocket { SOCKET socket; @@ -210,6 +235,22 @@ private: void DumpData(); void DumpBanlist(); + // Network stats + void RecordBytesRecv(uint64_t bytes); + void RecordBytesSent(uint64_t bytes); + + // Network usage totals + CCriticalSection cs_totalBytesRecv; + CCriticalSection cs_totalBytesSent; + uint64_t nTotalBytesRecv; + uint64_t nTotalBytesSent; + + // outbound limit & stats + uint64_t nMaxOutboundTotalBytesSentInCycle; + uint64_t nMaxOutboundCycleStartTime; + uint64_t nMaxOutboundLimit; + uint64_t nMaxOutboundTimeframe; + // Whitelisted ranges. Any node connecting from these is automatically // whitelisted (as well as those connecting to whitelisted binds). std::vector vWhitelistedRange; @@ -396,6 +437,7 @@ public: CDataStream ssSend; size_t nSendSize; // total size of all vSendMsg entries size_t nSendOffset; // offset inside the first vSendMsg already sent + uint64_t nOptimisticBytesWritten; uint64_t nSendBytes; std::deque vSendMsg; CCriticalSection cs_vSend; @@ -507,18 +549,6 @@ public: ~CNode(); private: - // Network usage totals - static CCriticalSection cs_totalBytesRecv; - static CCriticalSection cs_totalBytesSent; - static uint64_t nTotalBytesRecv; - static uint64_t nTotalBytesSent; - - // outbound limit & stats - static uint64_t nMaxOutboundTotalBytesSentInCycle; - static uint64_t nMaxOutboundCycleStartTime; - static uint64_t nMaxOutboundLimit; - static uint64_t nMaxOutboundTimeframe; - CNode(const CNode&); void operator=(const CNode&); @@ -812,34 +842,6 @@ public: void CloseSocketDisconnect(); void copyStats(CNodeStats &stats); - - // Network stats - static void RecordBytesRecv(uint64_t bytes); - static void RecordBytesSent(uint64_t bytes); - - static uint64_t GetTotalBytesRecv(); - static uint64_t GetTotalBytesSent(); - - //!set the max outbound target in bytes - static void SetMaxOutboundTarget(uint64_t limit); - static uint64_t GetMaxOutboundTarget(); - - //!set the timeframe for the max outbound target - static void SetMaxOutboundTimeframe(uint64_t timeframe); - static uint64_t GetMaxOutboundTimeframe(); - - //!check if the outbound target is reached - // if param historicalBlockServingLimit is set true, the function will - // response true if the limit for serving historical blocks has been reached - static bool OutboundTargetReached(bool historicalBlockServingLimit); - - //!response the bytes left in the current max outbound cycle - // in case of no limit, it will always response 0 - static uint64_t GetOutboundTargetBytesLeft(); - - //!response the time in second left in the current max outbound cycle - // in case of no limit, it will always response 0 - static uint64_t GetMaxOutboundTimeLeftInCycle(); }; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index f72bbfe6b..83c78850e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -72,12 +72,16 @@ int ClientModel::getNumBlocks() const quint64 ClientModel::getTotalBytesRecv() const { - return CNode::GetTotalBytesRecv(); + if(!g_connman) + return 0; + return g_connman->GetTotalBytesRecv(); } quint64 ClientModel::getTotalBytesSent() const { - return CNode::GetTotalBytesSent(); + if(!g_connman) + return 0; + return g_connman->GetTotalBytesSent(); } QDateTime ClientModel::getLastBlockDate() const diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 509b57aa7..4fe582399 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -347,19 +347,21 @@ UniValue getnettotals(const UniValue& params, bool fHelp) + HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); - obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); + obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv())); + obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); UniValue outboundLimit(UniValue::VOBJ); - outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe())); - outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget())); - outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false))); - outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true))); - outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft())); - outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle())); + outboundLimit.push_back(Pair("timeframe", g_connman->GetMaxOutboundTimeframe())); + outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget())); + outboundLimit.push_back(Pair("target_reached", g_connman->OutboundTargetReached(false))); + outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true))); + outboundLimit.push_back(Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft())); + outboundLimit.push_back(Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle())); obj.push_back(Pair("uploadtarget", outboundLimit)); return obj; }