mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-12 23:18:14 +01:00
Merge branch 'master' into 20150703_banlist_updates
This commit is contained in:
179
src/net.cpp
179
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.
|
||||
|
||||
@@ -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"
|
||||
@@ -35,6 +36,8 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
|
||||
#define DUMP_ADDRESSES_INTERVAL 900
|
||||
|
||||
@@ -66,6 +69,8 @@ namespace {
|
||||
};
|
||||
}
|
||||
|
||||
const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
|
||||
|
||||
//
|
||||
// Global state variables
|
||||
//
|
||||
@@ -215,6 +220,7 @@ void AdvertizeLocal(CNode *pnode)
|
||||
}
|
||||
if (addrLocal.IsRoutable())
|
||||
{
|
||||
LogPrintf("AdvertizeLocal: advertizing address %s\n", addrLocal.ToString());
|
||||
pnode->PushAddress(addrLocal);
|
||||
}
|
||||
}
|
||||
@@ -261,6 +267,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)
|
||||
{
|
||||
@@ -326,6 +340,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);
|
||||
@@ -444,8 +463,8 @@ 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,
|
||||
nLocalHostNonce, strSubVersion, nBestHeight, true);
|
||||
PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
|
||||
nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY));
|
||||
}
|
||||
|
||||
|
||||
@@ -506,12 +525,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;
|
||||
@@ -604,6 +622,7 @@ void CNode::copyStats(CNodeStats &stats)
|
||||
{
|
||||
stats.nodeid = this->GetId();
|
||||
X(nServices);
|
||||
X(fRelayTxes);
|
||||
X(nLastSend);
|
||||
X(nLastRecv);
|
||||
X(nTimeConnected);
|
||||
@@ -614,7 +633,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,
|
||||
@@ -669,6 +690,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();
|
||||
}
|
||||
@@ -965,6 +995,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());
|
||||
@@ -1333,7 +1372,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
|
||||
}
|
||||
@@ -1391,7 +1430,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);
|
||||
@@ -1693,11 +1732,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)
|
||||
@@ -1728,7 +1762,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();
|
||||
}
|
||||
@@ -1787,8 +1821,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
|
||||
@@ -2073,6 +2110,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 > 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()
|
||||
{
|
||||
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()
|
||||
@@ -2223,13 +2348,13 @@ 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),
|
||||
addrKnown(5000, 0.001),
|
||||
setInventoryKnown(SendBufferSize() / 1000)
|
||||
filterInventoryKnown(50000, 0.000001)
|
||||
{
|
||||
nServices = 0;
|
||||
hSocket = hSocketIn;
|
||||
@@ -2256,7 +2381,11 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
|
||||
nSendOffset = 0;
|
||||
hashContinue = uint256();
|
||||
nStartingHeight = -1;
|
||||
filterInventoryKnown.reset();
|
||||
fGetAddr = false;
|
||||
nNextLocalAddrSend = 0;
|
||||
nNextAddrSend = 0;
|
||||
nNextInvSend = 0;
|
||||
fRelayTxes = false;
|
||||
pfilter = new CBloomFilter();
|
||||
nPingNonceSent = 0;
|
||||
@@ -2264,6 +2393,9 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
|
||||
nPingUsecTime = 0;
|
||||
fPingQueued = false;
|
||||
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
|
||||
BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
|
||||
mapRecvBytesPerMsgCmd[msg] = 0;
|
||||
mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
|
||||
|
||||
{
|
||||
LOCK(cs_nLastNodeId);
|
||||
@@ -2294,8 +2426,12 @@ 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 have multiple non-responded queue positions for a single inv item
|
||||
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;
|
||||
@@ -2339,7 +2475,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
|
||||
@@ -2362,6 +2498,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;
|
||||
@@ -2501,3 +2640,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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user