// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
+#include <limits>
#include <deque>
+#ifndef Q_MOC_RUN
#include <boost/array.hpp>
#include <boost/foreach.hpp>
+#endif
#include <openssl/rand.h>
-#ifndef __WXMSW__
+#ifndef WIN32
#include <arpa/inet.h>
#endif
-class CMessageHeader;
-class CAddress;
-class CAddrDB;
-class CInv;
+#include "mruset.h"
+#include "netbase.h"
+#include "protocol.h"
+#include "addrman.h"
+#include "hash.h"
+
class CRequestTracker;
class CNode;
class CBlockIndex;
extern int nBestHeight;
-extern int nConnectTimeout;
-
-
-
-inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
-inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
-inline unsigned short GetDefaultPort() { return fTestNet ? 18333 : 8333; }
-static const unsigned int PUBLISH_HOPS = 5;
-enum
-{
- NODE_NETWORK = (1 << 0),
-};
+const uint16_t nSocksDefault = 9050;
+const uint16_t nPortZero = 0;
+inline uint64_t ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
+inline uint64_t SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
-bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout);
-bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
-bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
-bool GetMyExternalIP(unsigned int& ipRet);
-bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
-void AddressCurrentlyConnected(const CAddress& addr);
-CNode* FindNode(unsigned int ip);
-CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
-void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
-bool AnySubscribed(unsigned int nChannel);
-void MapPort(bool fMapPort);
-void DNSAddressSeed();
-bool BindListenPort(std::string& strError=REF(std::string()));
+void AddOneShot(std::string strDest);
+bool RecvLine(SOCKET hSocket, std::string& strLine);
+bool GetMyExternalIP(CNetAddr& ipRet);
+void AddressCurrentlyConnected(const CService& addr);
+CNode* FindNode(const CNetAddr& ip);
+CNode* FindNode(const CService& ip);
+CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64_t nTimeout=0);
+bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
+void MapPort();
+unsigned short GetListenPort();
+bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
void StartNode(void* parg);
bool StopNode();
-
-
-
-
-
-
-
-//
-// Message header
-// (4) message start
-// (12) command
-// (4) size
-// (4) checksum
-
-extern char pchMessageStart[4];
-
-class CMessageHeader
-{
-public:
- enum { COMMAND_SIZE=12 };
- char pchMessageStart[sizeof(::pchMessageStart)];
- char pchCommand[COMMAND_SIZE];
- unsigned int nMessageSize;
- unsigned int nChecksum;
-
- CMessageHeader()
- {
- memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
- memset(pchCommand, 0, sizeof(pchCommand));
- pchCommand[1] = 1;
- nMessageSize = -1;
- nChecksum = 0;
- }
-
- CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
- {
- memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
- strncpy(pchCommand, pszCommand, COMMAND_SIZE);
- nMessageSize = nMessageSizeIn;
- nChecksum = 0;
- }
-
- IMPLEMENT_SERIALIZE
- (
- READWRITE(FLATDATA(pchMessageStart));
- READWRITE(FLATDATA(pchCommand));
- READWRITE(nMessageSize);
- if (nVersion >= 209)
- READWRITE(nChecksum);
- )
-
- std::string GetCommand()
- {
- if (pchCommand[COMMAND_SIZE-1] == 0)
- return std::string(pchCommand, pchCommand + strlen(pchCommand));
- else
- return std::string(pchCommand, pchCommand + COMMAND_SIZE);
- }
-
- bool IsValid()
- {
- // Check start string
- if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
- return false;
-
- // Check the command string for errors
- for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
- {
- if (*p1 == 0)
- {
- // Must be all zeros after the first zero
- for (; p1 < pchCommand + COMMAND_SIZE; p1++)
- if (*p1 != 0)
- return false;
- }
- else if (*p1 < ' ' || *p1 > 0x7E)
- return false;
- }
-
- // Message size
- if (nMessageSize > MAX_SIZE)
- {
- printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize);
- return false;
- }
-
- return true;
- }
-};
-
-
-
-
-
-
-static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
-
-class CAddress
+enum
{
-public:
- uint64 nServices;
- unsigned char pchReserved[12];
- unsigned int ip;
- unsigned short port;
-
- // disk and network only
- unsigned int nTime;
-
- // memory only
- unsigned int nLastTry;
-
- CAddress()
- {
- Init();
- }
-
- CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK)
- {
- Init();
- ip = ipIn;
- port = htons(portIn == 0 ? GetDefaultPort() : portIn);
- nServices = nServicesIn;
- }
-
- explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK)
- {
- Init();
- ip = sockaddr.sin_addr.s_addr;
- port = sockaddr.sin_port;
- nServices = nServicesIn;
- }
-
- explicit CAddress(const char* pszIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
- {
- Init();
- Lookup(pszIn, *this, nServicesIn, fNameLookup, portIn);
- }
-
- explicit CAddress(const char* pszIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
- {
- Init();
- Lookup(pszIn, *this, nServicesIn, fNameLookup, 0, true);
- }
-
- explicit CAddress(std::string strIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
- {
- Init();
- Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, portIn);
- }
-
- explicit CAddress(std::string strIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
- {
- Init();
- Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, 0, true);
- }
-
- void Init()
- {
- nServices = NODE_NETWORK;
- memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
- ip = INADDR_NONE;
- port = htons(GetDefaultPort());
- nTime = 100000000;
- nLastTry = 0;
- }
-
- IMPLEMENT_SERIALIZE
- (
- if (fRead)
- const_cast<CAddress*>(this)->Init();
- if (nType & SER_DISK)
- READWRITE(nVersion);
- if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
- READWRITE(nTime);
- READWRITE(nServices);
- READWRITE(FLATDATA(pchReserved)); // for IPv6
- READWRITE(ip);
- READWRITE(port);
- )
-
- friend inline bool operator==(const CAddress& a, const CAddress& b)
- {
- return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
- a.ip == b.ip &&
- a.port == b.port);
- }
-
- friend inline bool operator!=(const CAddress& a, const CAddress& b)
- {
- return (!(a == b));
- }
-
- friend inline bool operator<(const CAddress& a, const CAddress& b)
- {
- int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
- if (ret < 0)
- return true;
- else if (ret == 0)
- {
- if (ntohl(a.ip) < ntohl(b.ip))
- return true;
- else if (a.ip == b.ip)
- return ntohs(a.port) < ntohs(b.port);
- }
- return false;
- }
-
- std::vector<unsigned char> GetKey() const
- {
- CDataStream ss;
- ss.reserve(18);
- ss << FLATDATA(pchReserved) << ip << port;
-
- #if defined(_MSC_VER) && _MSC_VER < 1300
- return std::vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
- #else
- return std::vector<unsigned char>(ss.begin(), ss.end());
- #endif
- }
-
- struct sockaddr_in GetSockAddr() const
- {
- struct sockaddr_in sockaddr;
- memset(&sockaddr, 0, sizeof(sockaddr));
- sockaddr.sin_family = AF_INET;
- sockaddr.sin_addr.s_addr = ip;
- sockaddr.sin_port = port;
- return sockaddr;
- }
-
- bool IsIPv4() const
- {
- return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
- }
-
- bool IsRFC1918() const
- {
- return IsIPv4() && (GetByte(3) == 10 ||
- (GetByte(3) == 192 && GetByte(2) == 168) ||
- (GetByte(3) == 172 &&
- (GetByte(2) >= 16 && GetByte(2) <= 31)));
- }
-
- bool IsRFC3927() const
- {
- return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
- }
-
- bool IsLocal() const
- {
- return IsIPv4() && (GetByte(3) == 127 ||
- GetByte(3) == 0);
- }
-
- bool IsRoutable() const
- {
- return IsValid() &&
- !(IsRFC1918() || IsRFC3927() || IsLocal());
- }
-
- bool IsValid() const
- {
- // Clean up 3-byte shifted addresses caused by garbage in size field
- // of addr messages from versions before 0.2.9 checksum.
- // Two consecutive addr messages look like this:
- // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
- // so if the first length field is garbled, it reads the second batch
- // of addr misaligned by 3 bytes.
- if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
- return false;
-
- return (ip != 0 && ip != INADDR_NONE && port != htons(USHRT_MAX));
- }
-
- unsigned char GetByte(int n) const
- {
- return ((unsigned char*)&ip)[3-n];
- }
-
- std::string ToStringIPPort() const
- {
- return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
- }
-
- std::string ToStringIP() const
- {
- return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
- }
-
- std::string ToStringPort() const
- {
- return strprintf("%u", ntohs(port));
- }
-
- std::string ToString() const
- {
- return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
- }
-
- void print() const
- {
- printf("CAddress(%s)\n", ToString().c_str());
- }
+ LOCAL_NONE, // unknown
+ LOCAL_IF, // address a local interface listens on
+ LOCAL_BIND, // address explicit bound to
+ LOCAL_IRC, // address reported by IRC (deprecated)
+ LOCAL_HTTP, // address reported by whatismyip.com and similar
+ LOCAL_MANUAL, // address explicitly specified (-externalip=)
+
+ LOCAL_MAX
};
-
-
-
-
+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 SeenLocal(const CService& addr);
+bool IsLocal(const CService& addr);
+bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
+bool IsReachable(const CNetAddr &addr);
+void SetReachable(enum Network net, bool fFlag = true);
+CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
enum
MSG_BLOCK,
};
-static const char* ppszTypeName[] =
-{
- "ERROR",
- "tx",
- "block",
-};
-
-class CInv
-{
-public:
- int type;
- uint256 hash;
-
- CInv()
- {
- type = 0;
- hash = 0;
- }
-
- CInv(int typeIn, const uint256& hashIn)
- {
- type = typeIn;
- hash = hashIn;
- }
-
- CInv(const std::string& strType, const uint256& hashIn)
- {
- int i;
- for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
- {
- if (strType == ppszTypeName[i])
- {
- type = i;
- break;
- }
- }
- if (i == ARRAYLEN(ppszTypeName))
- throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
- hash = hashIn;
- }
-
- IMPLEMENT_SERIALIZE
- (
- READWRITE(type);
- READWRITE(hash);
- )
-
- friend inline bool operator<(const CInv& a, const CInv& b)
- {
- return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
- }
-
- bool IsKnownType() const
- {
- return (type >= 1 && type < ARRAYLEN(ppszTypeName));
- }
-
- const char* GetCommand() const
- {
- if (!IsKnownType())
- throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
- return ppszTypeName[type];
- }
-
- std::string ToString() const
- {
- return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
- }
-
- void print() const
- {
- printf("CInv(%s)\n", ToString().c_str());
- }
-};
-
-
-
-
-
class CRequestTracker
{
public:
};
-
-
+/** Thread types */
+enum threadId
+{
+ THREAD_SOCKETHANDLER,
+ THREAD_OPENCONNECTIONS,
+ THREAD_MESSAGEHANDLER,
+ THREAD_RPCLISTENER,
+ THREAD_DNSSEED,
+ THREAD_ADDEDCONNECTIONS,
+ THREAD_DUMPADDRESS,
+ THREAD_RPCHANDLER,
+ THREAD_MINTER,
+ THREAD_SCRIPTCHECK,
+ THREAD_NTP,
+
+ THREAD_MAX
+};
extern bool fClient;
-extern bool fAllowDNS;
-extern uint64 nLocalServices;
-extern CAddress addrLocalHost;
-extern CNode* pnodeLocalHost;
-extern uint64 nLocalHostNonce;
-extern boost::array<int, 10> vnThreadsRunning;
-extern SOCKET hListenSocket;
+extern bool fDiscover;
+extern uint64_t nLocalServices;
+extern uint64_t nLocalHostNonce;
+extern CAddress addrSeenByPeer;
+extern boost::array<int, THREAD_MAX> vnThreadsRunning;
+extern CAddrMan addrman;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
-extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
-extern CCriticalSection cs_mapAddresses;
+extern std::vector<std::string> vAddedNodes;
+extern CCriticalSection cs_vAddedNodes;
extern std::map<CInv, CDataStream> mapRelay;
-extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
+extern std::deque<std::pair<int64_t, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
-extern std::map<CInv, int64> mapAlreadyAskedFor;
+extern std::map<CInv, int64_t> mapAlreadyAskedFor;
-// Settings
-extern int fUseProxy;
-extern CAddress addrProxy;
+class CNodeStats
+{
+public:
+ uint64_t nServices;
+ int64_t nLastSend;
+ int64_t nLastRecv;
+ int64_t nTimeConnected;
+ std::string addrName;
+ int32_t nVersion;
+ std::string strSubVer;
+ bool fInbound;
+ int64_t nReleaseTime;
+ int32_t nStartingHeight;
+ int32_t nMisbehavior;
+ uint64_t nSendBytes;
+ uint64_t nRecvBytes;
+ bool fSyncNode;
+};
+
+
+/** Information about a peer */
class CNode
{
public:
// socket
- uint64 nServices;
+ uint64_t nServices;
SOCKET hSocket;
CDataStream vSend;
CDataStream vRecv;
+ uint64_t nSendBytes;
+ uint64_t nRecvBytes;
CCriticalSection cs_vSend;
CCriticalSection cs_vRecv;
- int64 nLastSend;
- int64 nLastRecv;
- int64 nLastSendEmpty;
- int64 nTimeConnected;
- unsigned int nHeaderStart;
- unsigned int nMessageStart;
+ int64_t nLastSend;
+ int64_t nLastRecv;
+ int64_t nLastSendEmpty;
+ int64_t nTimeConnected;
+ int32_t nHeaderStart;
+ uint32_t nMessageStart;
CAddress addr;
- int nVersion;
+ std::string addrName;
+ CService addrLocal;
+ int32_t nVersion;
std::string strSubVer;
+ bool fOneShot;
bool fClient;
bool fInbound;
bool fNetworkNode;
bool fSuccessfullyConnected;
bool fDisconnect;
+ CSemaphoreGrant grantOutbound;
protected:
int nRefCount;
+
+ // 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;
+ int nMisbehavior;
+
public:
- int64 nReleaseTime;
+ int64_t nReleaseTime;
std::map<uint256, CRequestTracker> mapRequests;
CCriticalSection cs_mapRequests;
uint256 hashContinue;
CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd;
- int nStartingHeight;
+ int32_t nStartingHeight;
+ bool fStartSync;
// flood relay
std::vector<CAddress> vAddrToSend;
std::set<CAddress> setAddrKnown;
bool fGetAddr;
std::set<uint256> setKnown;
+ uint256 hashCheckpointKnown; // ppcoin: known sent sync-checkpoint
// inventory based relay
- std::set<CInv> setInventoryKnown;
+ mruset<CInv> setInventoryKnown;
std::vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory;
- std::multimap<int64, CInv> mapAskFor;
-
- // publish and subscription
- std::vector<char> vfSubscribe;
+ std::multimap<int64_t, CInv> mapAskFor;
-
- CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
+ CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION)
{
nServices = 0;
hSocket = hSocketIn;
- vSend.SetType(SER_NETWORK);
- vSend.SetVersion(0);
- vRecv.SetType(SER_NETWORK);
- vRecv.SetVersion(0);
- // Version 0.2 obsoletes 20 Feb 2012
- if (GetTime() > 1329696000)
- {
- vSend.SetVersion(209);
- vRecv.SetVersion(209);
- }
nLastSend = 0;
nLastRecv = 0;
+ nSendBytes = 0;
+ nRecvBytes = 0;
nLastSendEmpty = GetTime();
nTimeConnected = GetTime();
nHeaderStart = -1;
- nMessageStart = -1;
+ nMessageStart = std::numeric_limits<uint32_t>::max();
addr = addrIn;
+ addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0;
strSubVer = "";
+ fOneShot = false;
fClient = false; // set by version message
fInbound = fInboundIn;
fNetworkNode = false;
pindexLastGetBlocksBegin = 0;
hashLastGetBlocksEnd = 0;
nStartingHeight = -1;
+ fStartSync = false;
fGetAddr = false;
- vfSubscribe.assign(256, false);
+ nMisbehavior = 0;
+ hashCheckpointKnown = 0;
+ setInventoryKnown.max_size((size_t)SendBufferSize() / 1000);
// Be shy and don't send version until we hear
- if (!fInbound)
+ if (hSocket != INVALID_SOCKET && !fInbound)
PushVersion();
}
{
if (hSocket != INVALID_SOCKET)
{
- closesocket(hSocket);
- hSocket = INVALID_SOCKET;
+ CloseSocket(hSocket);
}
}
+
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&);
public:
return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
}
- CNode* AddRef(int64 nTimeout=0)
+ CNode* AddRef(int64_t nTimeout=0)
{
if (nTimeout != 0)
nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
void AddInventoryKnown(const CInv& inv)
{
- CRITICAL_BLOCK(cs_inventory)
+ {
+ LOCK(cs_inventory);
setInventoryKnown.insert(inv);
+ }
}
void PushInventory(const CInv& inv)
{
- CRITICAL_BLOCK(cs_inventory)
+ {
+ LOCK(cs_inventory);
if (!setInventoryKnown.count(inv))
vInventoryToSend.push_back(inv);
+ }
}
void AskFor(const CInv& inv)
{
// We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent
- int64& nRequestTime = mapAlreadyAskedFor[inv];
- printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
+ int64_t& nRequestTime = mapAlreadyAskedFor[inv];
+ if (fDebugNet)
+ printf("askfor %s %" PRId64 " (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str());
// Make sure not to reuse time indexes to keep things in the same order
- int64 nNow = (GetTime() - 1) * 1000000;
- static int64 nLastTime;
- nLastTime = nNow = std::max(nNow, ++nLastTime);
+ int64_t nNow = (GetTime() - 1) * 1000000;
+ static int64_t nLastTime;
+ ++nLastTime;
+ nNow = std::max(nNow, nLastTime);
+ nLastTime = nNow;
// Each retry is 2 minutes after the last
nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
void BeginMessage(const char* pszCommand)
{
- cs_vSend.Enter();
+ ENTER_CRITICAL_SECTION(cs_vSend);
if (nHeaderStart != -1)
AbortMessage();
- nHeaderStart = vSend.size();
+ nHeaderStart = (int32_t)vSend.size();
vSend << CMessageHeader(pszCommand, 0);
- nMessageStart = vSend.size();
+ nMessageStart = (uint32_t)vSend.size();
if (fDebug)
- printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
- printf("sending: %s ", pszCommand);
+ printf("sending: %s ", pszCommand);
}
void AbortMessage()
{
- if (nHeaderStart == -1)
+ if (nHeaderStart < 0)
return;
vSend.resize(nHeaderStart);
nHeaderStart = -1;
- nMessageStart = -1;
- cs_vSend.Leave();
- printf("(aborted)\n");
+ nMessageStart = std::numeric_limits<uint32_t>::max();
+ LEAVE_CRITICAL_SECTION(cs_vSend);
+
+ if (fDebug)
+ printf("(aborted)\n");
}
void EndMessage()
return;
}
- if (nHeaderStart == -1)
+ if (nHeaderStart < 0)
return;
// Set the size
- unsigned int nSize = vSend.size() - nMessageStart;
- memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
+ uint32_t nSize = (uint32_t) vSend.size() - nMessageStart;
+ memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::MESSAGE_SIZE_OFFSET, &nSize, sizeof(nSize));
// Set the checksum
- if (vSend.GetVersion() >= 209)
- {
- uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
- unsigned int nChecksum = 0;
- memcpy(&nChecksum, &hash, sizeof(nChecksum));
- assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
- memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
+ uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
+ uint32_t nChecksum = 0;
+ memcpy(&nChecksum, &hash, sizeof(nChecksum));
+ assert(nMessageStart - nHeaderStart >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
+ memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::CHECKSUM_OFFSET, &nChecksum, sizeof(nChecksum));
+
+ if (fDebug) {
+ printf("(%d bytes)\n", nSize);
}
- printf("(%d bytes) ", nSize);
- printf("\n");
-
nHeaderStart = -1;
- nMessageStart = -1;
- cs_vSend.Leave();
+ nMessageStart = std::numeric_limits<uint32_t>::max();
+ LEAVE_CRITICAL_SECTION(cs_vSend);
}
void EndMessageAbortIfEmpty()
{
- if (nHeaderStart == -1)
+ if (nHeaderStart < 0)
return;
- int nSize = vSend.size() - nMessageStart;
+ int nSize = (int) vSend.size() - nMessageStart;
if (nSize > 0)
EndMessage();
else
- void PushVersion()
- {
- /// when NTP implemented, change to just nTime = GetAdjustedTime()
- int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
- CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
- CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
- RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
- PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
- nLocalHostNonce, std::string(pszSubVer), nBestHeight);
- }
-
-
+ void PushVersion();
void PushMessage(const char* pszCommand)
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- CRITICAL_BLOCK(cs_mapRequests)
+ {
+ LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
+ }
PushMessage(pszCommand, hashReply);
}
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- CRITICAL_BLOCK(cs_mapRequests)
+ {
+ LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
+ }
PushMessage(pszCommand, hashReply, a1);
}
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- CRITICAL_BLOCK(cs_mapRequests)
+ {
+ LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
+ }
PushMessage(pszCommand, hashReply, a1, a2);
}
void CancelSubscribe(unsigned int nChannel);
void CloseSocketDisconnect();
void Cleanup();
-};
-
-
-
-
-
-
-
+ // 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);
+ bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
+ 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();
+};
inline void RelayInventory(const CInv& inv)
{
// Put on lists to offer to the other nodes
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushInventory(inv);
-}
-
-template<typename T>
-void RelayMessage(const CInv& inv, const T& a)
-{
- CDataStream ss(SER_NETWORK);
- ss.reserve(10000);
- ss << a;
- RelayMessage(inv, ss);
-}
-
-template<>
-inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
-{
- CRITICAL_BLOCK(cs_mapRelay)
- {
- // Expire old relay messages
- while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
- {
- mapRelay.erase(vRelayExpiration.front().second);
- vRelayExpiration.pop_front();
- }
-
- // Save original serialized message so newer versions are preserved
- mapRelay[inv] = ss;
- vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
}
-
- RelayInventory(inv);
}
+class CTransaction;
+void RelayTransaction(const CTransaction& tx, const uint256& hash);
+void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss);
-
-
-
-
-
-//
-// Templates for the publish and subscription system.
-// The object being published as T& obj needs to have:
-// a set<unsigned int> setSources member
-// specializations of AdvertInsert and AdvertErase
-// Currently implemented for CTable and CProduct.
-//
-
-template<typename T>
-void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
-{
- // Add to sources
- obj.setSources.insert(pfrom->addr.ip);
-
- if (!AdvertInsert(obj))
- return;
-
- // Relay
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
- pnode->PushMessage("publish", nChannel, nHops, obj);
-}
-
-template<typename T>
-void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
-{
- uint256 hash = obj.GetHash();
-
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
- pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
-
- AdvertErase(obj);
-}
-
-template<typename T>
-void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
-{
- // Remove a source
- obj.setSources.erase(pfrom->addr.ip);
-
- // If no longer supported by any sources, cancel it
- if (obj.setSources.empty())
- AdvertStopPublish(pfrom, nChannel, nHops, obj);
-}
-
#endif