diff options
| author | langerhans <[email protected]> | 2019-06-09 19:49:48 +0200 |
|---|---|---|
| committer | langerhans <[email protected]> | 2019-06-09 19:51:03 +0200 |
| commit | d278efaccdc45e7155147d2c86a50f193eafdc07 (patch) | |
| tree | 05cf92afa059fafff80e460c1619edd5bec231b3 /src/net.h | |
| parent | Revert "Change fPIE to fPIC (#1420)" (#1447) (diff) | |
| parent | Mark 1.14 ready for release (diff) | |
| download | archived-discoin-d278efaccdc45e7155147d2c86a50f193eafdc07.tar.xz archived-discoin-d278efaccdc45e7155147d2c86a50f193eafdc07.zip | |
Merge branch '1.14-branding'
Diffstat (limited to 'src/net.h')
| -rw-r--r-- | src/net.h | 848 |
1 files changed, 524 insertions, 324 deletions
@@ -1,26 +1,33 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 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. #ifndef BITCOIN_NET_H #define BITCOIN_NET_H +#include "addrdb.h" +#include "addrman.h" +#include "alert.h" +#include "amount.h" #include "bloom.h" #include "compat.h" #include "hash.h" #include "limitedmap.h" -#include "mruset.h" -#include "netbase.h" +#include "netaddress.h" #include "protocol.h" #include "random.h" #include "streams.h" #include "sync.h" #include "uint256.h" -#include "utilstrencodings.h" +#include "threadinterrupt.h" +#include <atomic> #include <deque> #include <stdint.h> +#include <thread> +#include <memory> +#include <condition_variable> #ifndef WIN32 #include <arpa/inet.h> @@ -31,7 +38,6 @@ #include <boost/signals2/signal.hpp> class CAddrMan; -class CBlockIndex; class CScheduler; class CNode; @@ -43,12 +49,20 @@ namespace boost { static const int PING_INTERVAL = 2 * 60; /** Time after which to disconnect, after waiting for a ping response (or inactivity). */ static const int TIMEOUT_INTERVAL = 20 * 60; +/** Run the feeler connection loop once every 2 minutes or 120 seconds. **/ +static const int FEELER_INTERVAL = 120; /** The maximum number of entries in an 'inv' protocol message */ static const unsigned int MAX_INV_SZ = 50000; /** The maximum number of new addresses to accumulate before announcing. */ static const unsigned int MAX_ADDR_TO_SEND = 1000; -/** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */ -static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024; +/** Maximum length of incoming protocol messages (no message over 4 MB is currently acceptable). */ +static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000; +/** Maximum length of strSubVer in `version` message */ +static const unsigned int MAX_SUBVERSION_LENGTH = 256; +/** Maximum number of automatic outgoing nodes */ +static const int MAX_OUTBOUND_CONNECTIONS = 8; +/** Maximum number of addnode outgoing nodes */ +static const int MAX_ADDNODE_CONNECTIONS = 8; /** -listen default */ static const bool DEFAULT_LISTEN = true; /** -upnp default */ @@ -59,25 +73,343 @@ static const bool DEFAULT_UPNP = false; #endif /** The maximum number of entries in mapAskFor */ static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ; +/** The maximum number of entries in setAskFor (larger due to getdata latency)*/ +static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ; +/** The maximum number of peer connections to maintain. */ +static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; +/** The default for -maxuploadtarget. 0 = Unlimited */ +static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0; +/** The default timeframe for -maxuploadtarget. 1 day. */ +static const uint64_t MAX_UPLOAD_TIMEFRAME = 60 * 60 * 24; +/** Default for blocks only*/ +static const bool DEFAULT_BLOCKSONLY = false; -unsigned int ReceiveFloodSize(); -unsigned int SendBufferSize(); +static const bool DEFAULT_FORCEDNSSEED = false; +static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000; +static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000; -void AddOneShot(std::string strDest); -void AddressCurrentlyConnected(const CService& addr); -CNode* FindNode(const CNetAddr& ip); -CNode* FindNode(const std::string& addrName); -CNode* FindNode(const CService& ip); -CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL); -bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); +static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK; + +// NOTE: When adjusting this, update rpcnet:setban's help ("24h") +static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban + +typedef int64_t NodeId; + +struct AddedNodeInfo +{ + std::string strAddedNode; + CService resolvedAddress; + bool fConnected; + bool fInbound; +}; + +class CTransaction; +class CNodeStats; +class CClientUIInterface; + +struct CSerializedNetMsg +{ + CSerializedNetMsg() = default; + CSerializedNetMsg(CSerializedNetMsg&&) = default; + CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default; + // No copying, only moves. + CSerializedNetMsg(const CSerializedNetMsg& msg) = delete; + CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete; + + std::vector<unsigned char> data; + std::string command; +}; + + +class CConnman +{ +public: + + enum NumConnections { + CONNECTIONS_NONE = 0, + CONNECTIONS_IN = (1U << 0), + CONNECTIONS_OUT = (1U << 1), + CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT), + }; + + struct Options + { + ServiceFlags nLocalServices = NODE_NONE; + ServiceFlags nRelevantServices = NODE_NONE; + int nMaxConnections = 0; + int nMaxOutbound = 0; + int nMaxAddnode = 0; + int nMaxFeeler = 0; + int nBestHeight = 0; + CClientUIInterface* uiInterface = nullptr; + unsigned int nSendBufferMaxSize = 0; + unsigned int nReceiveFloodSize = 0; + uint64_t nMaxOutboundTimeframe = 0; + uint64_t nMaxOutboundLimit = 0; + }; + CConnman(uint64_t seed0, uint64_t seed1); + ~CConnman(); + bool Start(CScheduler& scheduler, std::string& strNodeError, Options options); + void Stop(); + void Interrupt(); + bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); + bool GetNetworkActive() const { return fNetworkActive; }; + void SetNetworkActive(bool active); + bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false); + bool CheckIncomingNonce(uint64_t nonce); + + bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func); + + void PushMessage(CNode* pnode, CSerializedNetMsg&& msg); + + template<typename Callable> + void ForEachNode(Callable&& func) + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) { + if (NodeFullyConnected(node)) + func(node); + } + }; + + template<typename Callable> + void ForEachNode(Callable&& func) const + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) { + if (NodeFullyConnected(node)) + func(node); + } + }; + + template<typename Callable, typename CallableAfter> + void ForEachNodeThen(Callable&& pre, CallableAfter&& post) + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) { + if (NodeFullyConnected(node)) + pre(node); + } + post(); + }; + + template<typename Callable, typename CallableAfter> + void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) { + if (NodeFullyConnected(node)) + pre(node); + } + post(); + }; + + // Addrman functions + size_t GetAddressCount() const; + void SetServices(const CService &addr, ServiceFlags nServices); + void MarkAddressGood(const CAddress& addr); + void AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty = 0); + void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0); + std::vector<CAddress> GetAddresses(); + void AddressCurrentlyConnected(const CService& addr); + + // Denial-of-service detection/prevention + // The idea is to detect peers that are behaving + // badly and disconnect/ban them, but do it in a + // one-coding-mistake-won't-shatter-the-entire-network + // way. + // IMPORTANT: There should be nothing I can give a + // node that it will forward on that will make that + // node's peers drop it. If there is, an attacker + // can isolate a node and/or try to split the network. + // Dropping a node for sending stuff that is invalid + // now but might be valid in a later version is also + // dangerous, because it can cause a network split + // between nodes running old code and nodes running + // new code. + void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); + void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); + void ClearBanned(); // needed for unit testing + bool IsBanned(CNetAddr ip); + bool IsBanned(CSubNet subnet); + bool Unban(const CNetAddr &ip); + bool Unban(const CSubNet &ip); + void GetBanned(banmap_t &banmap); + void SetBanned(const banmap_t &banmap); + + void AddOneShot(const std::string& strDest); + + bool AddNode(const std::string& node); + bool RemoveAddedNode(const std::string& node); + std::vector<AddedNodeInfo> GetAddedNodeInfo(); + + size_t GetNodeCount(NumConnections num); + void GetNodeStats(std::vector<CNodeStats>& vstats); + bool DisconnectNode(const std::string& node); + bool DisconnectNode(NodeId id); + + unsigned int GetSendBufferSize() const; + + void AddWhitelistedRange(const CSubNet &subnet); + + ServiceFlags GetLocalServices() const; + + //!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(); + + void SetBestHeight(int height); + int GetBestHeight() const; + + /** Get a unique deterministic randomizer. */ + CSipHasher GetDeterministicRandomizer(uint64_t id) const; + + unsigned int GetReceiveFloodSize() const; + + void WakeMessageHandler(); +private: + struct ListenSocket { + SOCKET socket; + bool whitelisted; + + ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {} + }; + + void ThreadOpenAddedConnections(); + void ProcessOneShot(); + void ThreadOpenConnections(); + void ThreadMessageHandler(); + void AcceptConnection(const ListenSocket& hListenSocket); + void ThreadSocketHandler(); + void ThreadDNSAddressSeed(); + + uint64_t CalculateKeyedNetGroup(const CAddress& ad) const; + + CNode* FindNode(const CNetAddr& ip); + CNode* FindNode(const CSubNet& subNet); + CNode* FindNode(const std::string& addrName); + CNode* FindNode(const CService& addr); + + bool AttemptToEvictConnection(); + CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure); + bool IsWhitelistedRange(const CNetAddr &addr); + + void DeleteNode(CNode* pnode); + + NodeId GetNewNodeId(); + + size_t SocketSendData(CNode *pnode) const; + //!check is the banlist has unwritten changes + bool BannedSetIsDirty(); + //!set the "dirty" flag for the banlist + void SetBannedSetDirty(bool dirty=true); + //!clean unused entries (if bantime has expired) + void SweepBanned(); + void DumpAddresses(); + void DumpData(); + void DumpBanlist(); + + // Network stats + void RecordBytesRecv(uint64_t bytes); + void RecordBytesSent(uint64_t bytes); + + // Whether the node should be passed out in ForEach* callbacks + static bool NodeFullyConnected(const CNode* pnode); + + // 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<CSubNet> vWhitelistedRange; + CCriticalSection cs_vWhitelistedRange; + + unsigned int nSendBufferMaxSize; + unsigned int nReceiveFloodSize; + + std::vector<ListenSocket> vhListenSocket; + std::atomic<bool> fNetworkActive; + banmap_t setBanned; + CCriticalSection cs_setBanned; + bool setBannedIsDirty; + bool fAddressesInitialized; + CAddrMan addrman; + std::deque<std::string> vOneShots; + CCriticalSection cs_vOneShots; + std::vector<std::string> vAddedNodes; + CCriticalSection cs_vAddedNodes; + std::vector<CNode*> vNodes; + std::list<CNode*> vNodesDisconnected; + mutable CCriticalSection cs_vNodes; + std::atomic<NodeId> nLastNodeId; + + /** Services this instance offers */ + ServiceFlags nLocalServices; + + /** Services this instance cares about */ + ServiceFlags nRelevantServices; + + CSemaphore *semOutbound; + CSemaphore *semAddnode; + int nMaxConnections; + int nMaxOutbound; + int nMaxAddnode; + int nMaxFeeler; + std::atomic<int> nBestHeight; + CClientUIInterface* clientInterface; + + /** SipHasher seeds for deterministic randomness */ + const uint64_t nSeed0, nSeed1; + + /** flag for waking the message processor. */ + bool fMsgProcWake; + + std::condition_variable condMsgProc; + std::mutex mutexMsgProc; + std::atomic<bool> flagInterruptMsgProc; + + CThreadInterrupt interruptNet; + + std::thread threadDNSAddressSeed; + std::thread threadSocketHandler; + std::thread threadOpenAddedConnections; + std::thread threadOpenConnections; + std::thread threadMessageHandler; +}; +extern std::unique_ptr<CConnman> g_connman; +void Discover(boost::thread_group& threadGroup); void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); -void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler); -bool StopNode(); -void SocketSendData(CNode *pnode); - -typedef int NodeId; struct CombinerAll { @@ -97,11 +429,10 @@ struct CombinerAll // Signals for message handling struct CNodeSignals { - boost::signals2::signal<int ()> GetHeight; - boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages; - boost::signals2::signal<bool (CNode*, bool), CombinerAll> SendMessages; - boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode; - boost::signals2::signal<void (NodeId)> FinalizeNode; + boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), CombinerAll> ProcessMessages; + boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), CombinerAll> SendMessages; + boost::signals2::signal<void (CNode*, CConnman&)> InitializeNode; + boost::signals2::signal<void (NodeId, bool&)> FinalizeNode; }; @@ -120,40 +451,29 @@ enum }; bool IsPeerAddrLocalGood(CNode *pnode); -void AdvertizeLocal(CNode *pnode); +void AdvertiseLocal(CNode *pnode); void SetLimited(enum Network net, bool fLimited = true); bool IsLimited(enum Network net); bool IsLimited(const CNetAddr& addr); bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); +bool RemoveLocal(const CService& addr); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); bool IsReachable(enum Network net); bool IsReachable(const CNetAddr &addr); -void SetReachable(enum Network net, bool fFlag = true); -CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); +CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices); extern bool fDiscover; extern bool fListen; -extern uint64_t nLocalServices; -extern uint64_t nLocalHostNonce; -extern CAddrMan addrman; -extern int nMaxConnections; - -extern std::vector<CNode*> vNodes; -extern CCriticalSection cs_vNodes; -extern std::map<CInv, CDataStream> mapRelay; -extern std::deque<std::pair<int64_t, CInv> > vRelayExpiration; -extern CCriticalSection cs_mapRelay; -extern limitedmap<CInv, int64_t> mapAlreadyAskedFor; +extern bool fRelayTxes; -extern std::vector<std::string> vAddedNodes; -extern CCriticalSection cs_vAddedNodes; +extern limitedmap<uint256, int64_t> mapAlreadyAskedFor; -extern NodeId nLastNodeId; -extern CCriticalSection cs_nLastNodeId; +/** Subversion as sent to the P2P network in `version` messages */ +extern std::string strSubVersion; struct LocalServiceInfo { int nScore; @@ -162,12 +482,14 @@ struct LocalServiceInfo { extern CCriticalSection cs_mapLocalHost; extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost; +typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes class CNodeStats { public: NodeId nodeid; - uint64_t nServices; + ServiceFlags nServices; + bool fRelayTxes; int64_t nLastSend; int64_t nLastRecv; int64_t nTimeConnected; @@ -176,19 +498,27 @@ public: int nVersion; std::string cleanSubVer; bool fInbound; + bool fAddnode; int nStartingHeight; uint64_t nSendBytes; + mapMsgCmdSize mapSendBytesPerMsgCmd; uint64_t nRecvBytes; + mapMsgCmdSize mapRecvBytesPerMsgCmd; bool fWhitelisted; double dPingTime; double dPingWait; + double dMinPing; std::string addrLocal; + CAddress addr; }; class CNetMessage { +private: + mutable CHash256 hasher; + mutable uint256 data_hash; public: bool in_data; // parsing header (false) or data (true) @@ -216,6 +546,8 @@ public: return (hdr.nMessageSize == nDataPos); } + const uint256& GetMessageHash() const; + void SetVersion(int nVersionIn) { hdrbuf.SetVersion(nVersionIn); @@ -227,144 +559,187 @@ public: }; - - - /** Information about a peer */ class CNode { + friend class CConnman; public: // socket - uint64_t nServices; + std::atomic<ServiceFlags> nServices; + ServiceFlags nServicesExpected; SOCKET hSocket; - CDataStream ssSend; size_t nSendSize; // total size of all vSendMsg entries size_t nSendOffset; // offset inside the first vSendMsg already sent uint64_t nSendBytes; - std::deque<CSerializeData> vSendMsg; + std::deque<std::vector<unsigned char>> vSendMsg; CCriticalSection cs_vSend; + CCriticalSection cs_hSocket; + CCriticalSection cs_vRecv; + + CCriticalSection cs_vProcessMsg; + std::list<CNetMessage> vProcessMsg; + size_t nProcessQueueSize; + + CCriticalSection cs_sendProcessing; std::deque<CInv> vRecvGetData; - std::deque<CNetMessage> vRecvMsg; - CCriticalSection cs_vRecvMsg; uint64_t nRecvBytes; - int nRecvVersion; - - int64_t nLastSend; - int64_t nLastRecv; - int64_t nTimeConnected; - int64_t nTimeOffset; - CAddress addr; - std::string addrName; - CService addrLocal; - int nVersion; + std::atomic<int> nRecvVersion; + + std::atomic<int64_t> nLastSend; + std::atomic<int64_t> nLastRecv; + const int64_t nTimeConnected; + std::atomic<int64_t> nTimeOffset; + const CAddress addr; + std::atomic<int> nVersion; // strSubVer is whatever byte array we read from the wire. However, this field is intended // to be printed out, displayed to humans in various forms and so on. So we sanitize it and // store the sanitized version in cleanSubVer. The original should be used when dealing with // the network or wire types and the cleaned string used when displayed or logged. std::string strSubVer, cleanSubVer; + CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer bool fWhitelisted; // This peer can bypass DoS banning. + bool fFeeler; // If true this node is being used as a short lived feeler. bool fOneShot; + bool fAddnode; bool fClient; - bool fInbound; - bool fNetworkNode; - bool fSuccessfullyConnected; - bool fDisconnect; + const bool fInbound; + std::atomic_bool fSuccessfullyConnected; + std::atomic_bool fDisconnect; // We use fRelayTxes for two purposes - // a) it allows us to not relay tx invs before receiving the peer's version message // b) the peer may tell us in its version message that we should not relay tx invs - // until it has initialized its bloom filter. - bool fRelayTxes; + // unless it loads a bloom filter. + bool fRelayTxes; //protected by cs_filter + bool fSentAddr; CSemaphoreGrant grantOutbound; CCriticalSection cs_filter; CBloomFilter* pfilter; - int nRefCount; - NodeId id; -protected: + std::atomic<int> nRefCount; + const NodeId id; - // Denial-of-service detection/prevention - // Key is IP address, value is banned-until-time - static std::map<CNetAddr, int64_t> setBanned; - static CCriticalSection cs_setBanned; - - // Whitelisted ranges. Any node connecting from these is automatically - // whitelisted (as well as those connecting to whitelisted binds). - static std::vector<CSubNet> vWhitelistedRange; - static CCriticalSection cs_vWhitelistedRange; + const uint64_t nKeyedNetGroup; + std::atomic_bool fPauseRecv; + std::atomic_bool fPauseSend; +protected: - // Basic fuzz-testing - void Fuzz(int nChance); // modifies ssSend + mapMsgCmdSize mapSendBytesPerMsgCmd; + mapMsgCmdSize mapRecvBytesPerMsgCmd; public: uint256 hashContinue; - int nStartingHeight; + std::atomic<int> nStartingHeight; // flood relay std::vector<CAddress> vAddrToSend; CRollingBloomFilter addrKnown; bool fGetAddr; std::set<uint256> setKnown; + int64_t nNextAddrSend; + int64_t nNextLocalAddrSend; // inventory based relay - mruset<CInv> setInventoryKnown; - std::vector<CInv> vInventoryToSend; + CRollingBloomFilter filterInventoryKnown; + // Set of transaction ids we still have to announce. + // They are sorted by the mempool before relay, so the order is not important. + std::set<uint256> setInventoryTxToSend; + // List of block ids we still have announce. + // There is no final sorting before sending, as they are always sent immediately + // and in the order requested. + std::vector<uint256> vInventoryBlockToSend; CCriticalSection cs_inventory; + std::set<uint256> setAskFor; std::multimap<int64_t, CInv> mapAskFor; + int64_t nNextInvSend; + // Used for headers announcements - unfiltered blocks to relay + // Also protected by cs_inventory + std::vector<uint256> vBlockHashesToAnnounce; + // Used for BIP35 mempool sending, also protected by cs_inventory + bool fSendMempool; + + // Last time a "MEMPOOL" request was serviced. + std::atomic<int64_t> timeLastMempoolReq; + + // Block and TXN accept times + std::atomic<int64_t> nLastBlockTime; + std::atomic<int64_t> nLastTXTime; // Ping time measurement: // The pong reply we're expecting, or 0 if no pong expected. - uint64_t nPingNonceSent; + std::atomic<uint64_t> nPingNonceSent; // Time (in usec) the last ping was sent, or 0 if no ping was ever sent. - int64_t nPingUsecStart; + std::atomic<int64_t> nPingUsecStart; // Last measured round-trip time. - int64_t nPingUsecTime; + std::atomic<int64_t> nPingUsecTime; + // Best measured round-trip time. + std::atomic<int64_t> nMinPingUsecTime; // Whether a ping is requested. - bool fPingQueued; + std::atomic<bool> fPingQueued; + // Minimum fee rate with which to filter inv's to this node + CAmount minFeeFilter; + CCriticalSection cs_feeFilter; + CAmount lastSentFeeFilter; + int64_t nextSendTimeFeeFilter; + + // Alert relay + std::vector<CAlert> vAlertToSend; - CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false); + CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); private: - // Network usage totals - static CCriticalSection cs_totalBytesRecv; - static CCriticalSection cs_totalBytesSent; - static uint64_t nTotalBytesRecv; - static uint64_t nTotalBytesSent; - CNode(const CNode&); void operator=(const CNode&); + + const uint64_t nLocalHostNonce; + // Services offered to this peer + const ServiceFlags nLocalServices; + const int nMyStartingHeight; + int nSendVersion; + std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread + + mutable CCriticalSection cs_addrName; + std::string addrName; + + CService addrLocal; + mutable CCriticalSection cs_addrLocal; public: NodeId GetId() const { return id; } + uint64_t GetLocalNonce() const { + return nLocalHostNonce; + } + + int GetMyStartingHeight() const { + return nMyStartingHeight; + } + int GetRefCount() { assert(nRefCount >= 0); return nRefCount; } - // requires LOCK(cs_vRecvMsg) - unsigned int GetTotalRecvSize() - { - unsigned int total = 0; - BOOST_FOREACH(const CNetMessage &msg, vRecvMsg) - total += msg.vRecv.size() + 24; - return total; - } - - // requires LOCK(cs_vRecvMsg) - bool ReceiveMsgBytes(const char *pch, unsigned int nBytes); + bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete); - // requires LOCK(cs_vRecvMsg) void SetRecvVersion(int nVersionIn) { nRecvVersion = nVersionIn; - BOOST_FOREACH(CNetMessage &msg, vRecvMsg) - msg.SetVersion(nVersionIn); } + int GetRecvVersion() + { + return nRecvVersion; + } + void SetSendVersion(int nVersionIn); + int GetSendVersion() const; + + CService GetAddrLocal() const; + //! May not be called more than once + void SetAddrLocal(const CService& addrLocalIn); CNode* AddRef() { @@ -379,262 +754,87 @@ public: - void AddAddressKnown(const CAddress& addr) + void AddAddressKnown(const CAddress& _addr) { - addrKnown.insert(addr.GetKey()); + addrKnown.insert(_addr.GetKey()); } - void PushAddress(const CAddress& addr) + void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand) { // Known checking here is only to save space from duplicates. // SendMessages will filter it again for knowns that were added // after addresses were pushed. - if (addr.IsValid() && !addrKnown.contains(addr.GetKey())) { + if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { - vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr; + vAddrToSend[insecure_rand.rand32() % vAddrToSend.size()] = _addr; } else { - vAddrToSend.push_back(addr); + vAddrToSend.push_back(_addr); } } } - - void AddInventoryKnown(const CInv& inv) - { - { - LOCK(cs_inventory); - setInventoryKnown.insert(inv); - } - } - - void PushInventory(const CInv& inv) + void PushAlert(const CAlert& _alert) { - { - LOCK(cs_inventory); - if (!setInventoryKnown.count(inv)) - vInventoryToSend.push_back(inv); - } - } - - void AskFor(const CInv& inv); - - // TODO: Document the postcondition of this function. Is cs_vSend locked? - void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend); - - // TODO: Document the precondition of this function. Is cs_vSend locked? - void AbortMessage() UNLOCK_FUNCTION(cs_vSend); - - // TODO: Document the precondition of this function. Is cs_vSend locked? - void EndMessage() UNLOCK_FUNCTION(cs_vSend); - - void PushVersion(); - - - void PushMessage(const char* pszCommand) - { - try - { - BeginMessage(pszCommand); - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template<typename T1> - void PushMessage(const char* pszCommand, const T1& a1) - { - try - { - BeginMessage(pszCommand); - ssSend << a1; - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template<typename T1, typename T2> - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2; - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template<typename T1, typename T2, typename T3> - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3; - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; + // don't relay to nodes which haven't sent their version message + if (_alert.IsInEffect() && nVersion != 0) { + vAlertToSend.push_back(_alert); } } - template<typename T1, typename T2, typename T3, typename T4> - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4; - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; - } - } - template<typename T1, typename T2, typename T3, typename T4, typename T5> - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5) + void AddInventoryKnown(const CInv& inv) { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5; - EndMessage(); - } - catch (...) { - AbortMessage(); - throw; + LOCK(cs_inventory); + filterInventoryKnown.insert(inv.hash); } } - template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6) + void PushInventory(const CInv& inv) { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6; - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; + LOCK(cs_inventory); + if (inv.type == MSG_TX) { + if (!filterInventoryKnown.contains(inv.hash)) { + setInventoryTxToSend.insert(inv.hash); + } + } else if (inv.type == MSG_BLOCK) { + vInventoryBlockToSend.push_back(inv.hash); } } - template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7) + void PushAlertHash(const uint256 &hash) { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; - } + LOCK(cs_inventory); + vBlockHashesToAnnounce.push_back(hash); } - template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8) + void PushBlockHash(const uint256 &hash) { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; - } + LOCK(cs_inventory); + vBlockHashesToAnnounce.push_back(hash); } - template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; - EndMessage(); - } - catch (...) - { - AbortMessage(); - throw; - } - } + void AskFor(const CInv& inv); void CloseSocketDisconnect(); - // Denial-of-service detection/prevention - // The idea is to detect peers that are behaving - // badly and disconnect/ban them, but do it in a - // one-coding-mistake-won't-shatter-the-entire-network - // way. - // IMPORTANT: There should be nothing I can give a - // node that it will forward on that will make that - // node's peers drop it. If there is, an attacker - // can isolate a node and/or try to split the network. - // Dropping a node for sending stuff that is invalid - // now but might be valid in a later version is also - // dangerous, because it can cause a network split - // between nodes running old code and nodes running - // new code. - static void ClearBanned(); // needed for unit testing - static bool IsBanned(CNetAddr ip); - static bool Ban(const CNetAddr &ip); void copyStats(CNodeStats &stats); - static bool IsWhitelistedRange(const CNetAddr &ip); - static void AddWhitelistedRange(const CSubNet &subnet); - - // Network stats - static void RecordBytesRecv(uint64_t bytes); - static void RecordBytesSent(uint64_t bytes); + ServiceFlags GetLocalServices() const + { + return nLocalServices; + } - static uint64_t GetTotalBytesRecv(); - static uint64_t GetTotalBytesSent(); + std::string GetAddrName() const; + //! Sets the addrName only if it was not previously set + void MaybeSetAddrName(const std::string& addrNameIn); }; -class CTransaction; -void RelayTransaction(const CTransaction& tx); -void RelayTransaction(const CTransaction& tx, const CDataStream& ss); -/** Access to the (IP) address database (peers.dat) */ -class CAddrDB -{ -private: - boost::filesystem::path pathAddr; -public: - CAddrDB(); - bool Write(const CAddrMan& addr); - bool Read(CAddrMan& addr); -}; + +/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */ +int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds); #endif // BITCOIN_NET_H |