123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656 |
- // ECOin - Copyright (c) - 2014/2022 - GPLv3 - epsylon@riseup.net (https://03c8.net)
- #ifndef ECOIN_NET_H
- #define ECOIN_NET_H
- #include <deque>
- #include <boost/array.hpp>
- #include <boost/foreach.hpp>
- #include <openssl/rand.h>
- #ifndef WIN32
- #include <arpa/inet.h>
- #endif
- #include "mruset.h"
- #include "netbase.h"
- #include "protocol.h"
- #include "addrman.h"
- class CRequestTracker;
- class CNode;
- class CBlockIndex;
- extern int nBestHeight;
- inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
- inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
- 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 nTimeout=0);
- void MapPort();
- unsigned short GetListenPort();
- bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
- void StartNode(void* parg);
- bool StopNode();
- enum
- {
- LOCAL_NONE, // unknown
- LOCAL_IF, // address a local interface listens on
- LOCAL_BIND, // address explicit bound to
- LOCAL_UPNP, // address reported by UPnP
- 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_TX = 1,
- MSG_BLOCK,
- };
- class CRequestTracker
- {
- public:
- void (*fn)(void*, CDataStream&);
- void* param1;
- explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
- {
- fn = fnIn;
- param1 = param1In;
- }
- bool IsNull()
- {
- return fn == NULL;
- }
- };
- /** Thread types */
- enum threadId
- {
- THREAD_SOCKETHANDLER,
- THREAD_OPENCONNECTIONS,
- THREAD_MESSAGEHANDLER,
- THREAD_RPCLISTENER,
- THREAD_UPNP,
- THREAD_DNSSEED,
- THREAD_ADDEDCONNECTIONS,
- THREAD_DUMPADDRESS,
- THREAD_RPCHANDLER,
- THREAD_MINTER,
- THREAD_MAX
- };
- extern bool fClient;
- extern bool fDiscover;
- extern bool fUseUPnP;
- extern uint64 nLocalServices;
- extern uint64 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<CInv, CDataStream> mapRelay;
- extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
- extern CCriticalSection cs_mapRelay;
- extern std::map<CInv, int64> mapAlreadyAskedFor;
- class CNodeStats
- {
- public:
- uint64 nServices;
- int64 nLastSend;
- int64 nLastRecv;
- int64 nTimeConnected;
- std::string addrName;
- int nVersion;
- std::string strSubVer;
- bool fInbound;
- int64 nReleaseTime;
- int nStartingHeight;
- int nMisbehavior;
- };
- /** Information about a peer */
- class CNode
- {
- public:
- // socket
- uint64 nServices;
- SOCKET hSocket;
- CDataStream vSend;
- CDataStream vRecv;
- CCriticalSection cs_vSend;
- CCriticalSection cs_vRecv;
- int64 nLastSend;
- int64 nLastRecv;
- int64 nLastSendEmpty;
- int64 nTimeConnected;
- int nHeaderStart;
- unsigned int nMessageStart;
- CAddress addr;
- std::string addrName;
- CService addrLocal;
- int 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> setBanned;
- static CCriticalSection cs_setBanned;
- int nMisbehavior;
- public:
- int64 nReleaseTime;
- std::map<uint256, CRequestTracker> mapRequests;
- CCriticalSection cs_mapRequests;
- uint256 hashContinue;
- CBlockIndex* pindexLastGetBlocksBegin;
- uint256 hashLastGetBlocksEnd;
- int nStartingHeight;
- // flood relay
- std::vector<CAddress> vAddrToSend;
- std::set<CAddress> setAddrKnown;
- bool fGetAddr;
- std::set<uint256> setKnown;
- uint256 hashCheckpointKnown; // ecoin: known sent sync-checkpoint
- // inventory based relay
- mruset<CInv> setInventoryKnown;
- std::vector<CInv> vInventoryToSend;
- CCriticalSection cs_inventory;
- std::multimap<int64, CInv> mapAskFor;
- 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;
- nLastSend = 0;
- nLastRecv = 0;
- nLastSendEmpty = GetTime();
- nTimeConnected = GetTime();
- nHeaderStart = -1;
- nMessageStart = -1;
- addr = addrIn;
- addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
- nVersion = 0;
- strSubVer = "";
- fOneShot = false;
- fClient = false; // set by version message
- fInbound = fInboundIn;
- fNetworkNode = false;
- fSuccessfullyConnected = false;
- fDisconnect = false;
- nRefCount = 0;
- nReleaseTime = 0;
- hashContinue = 0;
- pindexLastGetBlocksBegin = 0;
- hashLastGetBlocksEnd = 0;
- nStartingHeight = -1;
- fGetAddr = false;
- nMisbehavior = 0;
- hashCheckpointKnown = 0;
- setInventoryKnown.max_size(SendBufferSize() / 1000);
- // Be shy and don't send version until we hear
- if (hSocket != INVALID_SOCKET && !fInbound)
- PushVersion();
- }
- ~CNode()
- {
- if (hSocket != INVALID_SOCKET)
- {
- closesocket(hSocket);
- hSocket = INVALID_SOCKET;
- }
- }
- private:
- CNode(const CNode&);
- void operator=(const CNode&);
- public:
- int GetRefCount()
- {
- return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
- }
- CNode* AddRef(int64 nTimeout=0)
- {
- if (nTimeout != 0)
- nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
- else
- nRefCount++;
- return this;
- }
- void Release()
- {
- nRefCount--;
- }
- void AddAddressKnown(const CAddress& addr)
- {
- setAddrKnown.insert(addr);
- }
- void PushAddress(const CAddress& addr)
- {
- // 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() && !setAddrKnown.count(addr))
- vAddrToSend.push_back(addr);
- }
- void AddInventoryKnown(const CInv& inv)
- {
- {
- LOCK(cs_inventory);
- setInventoryKnown.insert(inv);
- }
- }
- void PushInventory(const CInv& inv)
- {
- {
- 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];
- if (fDebugNet)
- printf("askfor %s %" PRI64d" (%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);
- nLastTime = nNow;
- // Each retry is 2 minutes after the last
- nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
- mapAskFor.insert(std::make_pair(nRequestTime, inv));
- }
- void BeginMessage(const char* pszCommand)
- {
- ENTER_CRITICAL_SECTION(cs_vSend);
- if (nHeaderStart != -1)
- AbortMessage();
- nHeaderStart = vSend.size();
- vSend << CMessageHeader(pszCommand, 0);
- nMessageStart = vSend.size();
- if (fDebug)
- printf("sending: %s ", pszCommand);
- }
- void AbortMessage()
- {
- if (nHeaderStart < 0)
- return;
- vSend.resize(nHeaderStart);
- nHeaderStart = -1;
- nMessageStart = -1;
- LEAVE_CRITICAL_SECTION(cs_vSend);
- if (fDebug)
- printf("(aborted)\n");
- }
- void EndMessage()
- {
- if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
- {
- printf("dropmessages DROPPING SEND MESSAGE\n");
- AbortMessage();
- return;
- }
- if (nHeaderStart < 0)
- return;
- // Set the size
- unsigned int nSize = vSend.size() - nMessageStart;
- memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::MESSAGE_SIZE_OFFSET, &nSize, sizeof(nSize));
- // Set the checksum
- uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
- unsigned int 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);
- }
- nHeaderStart = -1;
- nMessageStart = -1;
- LEAVE_CRITICAL_SECTION(cs_vSend);
- }
- void EndMessageAbortIfEmpty()
- {
- if (nHeaderStart < 0)
- return;
- int nSize = vSend.size() - nMessageStart;
- if (nSize > 0)
- EndMessage();
- else
- AbortMessage();
- }
- 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);
- vSend << a1;
- EndMessage();
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
- template<typename T1, typename T2>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
- {
- try
- {
- BeginMessage(pszCommand);
- vSend << 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);
- vSend << a1 << a2 << a3;
- EndMessage();
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
- 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);
- vSend << 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)
- {
- try
- {
- BeginMessage(pszCommand);
- vSend << a1 << a2 << a3 << a4 << a5;
- EndMessage();
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
- 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)
- {
- try
- {
- BeginMessage(pszCommand);
- vSend << a1 << a2 << a3 << a4 << a5 << a6;
- EndMessage();
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
- 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)
- {
- try
- {
- BeginMessage(pszCommand);
- vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
- EndMessage();
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
- 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)
- {
- try
- {
- BeginMessage(pszCommand);
- vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
- EndMessage();
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
- 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);
- vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
- EndMessage();
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
- void PushRequest(const char* pszCommand,
- void (*fn)(void*, CDataStream&), void* param1)
- {
- uint256 hashReply;
- RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- {
- LOCK(cs_mapRequests);
- mapRequests[hashReply] = CRequestTracker(fn, param1);
- }
- PushMessage(pszCommand, hashReply);
- }
- template<typename T1>
- void PushRequest(const char* pszCommand, const T1& a1,
- void (*fn)(void*, CDataStream&), void* param1)
- {
- uint256 hashReply;
- RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- {
- LOCK(cs_mapRequests);
- mapRequests[hashReply] = CRequestTracker(fn, param1);
- }
- PushMessage(pszCommand, hashReply, a1);
- }
- template<typename T1, typename T2>
- void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
- void (*fn)(void*, CDataStream&), void* param1)
- {
- uint256 hashReply;
- RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
- {
- LOCK(cs_mapRequests);
- mapRequests[hashReply] = CRequestTracker(fn, param1);
- }
- PushMessage(pszCommand, hashReply, a1, a2);
- }
- void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
- bool IsSubscribed(unsigned int nChannel);
- void Subscribe(unsigned int nChannel, unsigned int nHops=0);
- 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);
- };
- inline void RelayInventory(const CInv& inv)
- {
- // Put on lists to offer to the other nodes
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- pnode->PushInventory(inv);
- }
- }
- class CTransaction;
- void RelayTransaction(const CTransaction& tx, const uint256& hash);
- void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss);
- #endif
|