X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fnet.h;h=65118a4574f4551302c4c4dcce546adad3f59fe1;hp=d1ded872322400a2c830ccdc6542f617512cd42c;hb=e10622d1297e638109bbf58c35ad008f7acbae7c;hpb=482cb6569058423ca952076459f1539a88d70074 diff --git a/src/net.h b/src/net.h index d1ded87..65118a4 100644 --- a/src/net.h +++ b/src/net.h @@ -1,20 +1,25 @@ // 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 #include +#include #include -#ifndef __WXMSW__ +#ifndef WIN32 #include #endif -class CMessageHeader; -class CAddress; -class CInv; +#include "mruset.h" +#include "netbase.h" +#include "protocol.h" +#include "addrman.h" + +class CAddrDB; class CRequestTracker; class CNode; class CBlockIndex; @@ -22,428 +27,26 @@ extern int nBestHeight; -inline unsigned short GetDefaultPort() { return fTestNet ? 18333 : 8333; } -static const unsigned int PUBLISH_HOPS = 5; -enum -{ - NODE_NETWORK = (1 << 0), -}; - - - +inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); } +inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); } -bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet); -bool Lookup(const char *pszName, std::vector& 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); -void AddressCurrentlyConnected(const CAddress& addr); -CNode* FindNode(unsigned int ip); +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, 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 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 -{ -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(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 GetKey() const - { - CDataStream ss; - ss.reserve(18); - ss << FLATDATA(pchReserved) << ip << port; - - #if defined(_MSC_VER) && _MSC_VER < 1300 - return std::vector((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]); - #else - return std::vector(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()); - } -}; - - - - - - - enum { MSG_TX = 1, 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: @@ -463,36 +66,43 @@ public: }; - - +/** Thread types */ +enum threadId +{ + THREAD_SOCKETHANDLER, + THREAD_OPENCONNECTIONS, + THREAD_MESSAGEHANDLER, + THREAD_MINER, + THREAD_RPCSERVER, + THREAD_UPNP, + THREAD_DNSSEED, + THREAD_ADDEDCONNECTIONS, + THREAD_DUMPADDRESS, + + THREAD_MAX +}; extern bool fClient; extern bool fAllowDNS; extern uint64 nLocalServices; extern CAddress addrLocalHost; -extern CNode* pnodeLocalHost; extern uint64 nLocalHostNonce; -extern boost::array vnThreadsRunning; -extern SOCKET hListenSocket; +extern boost::array vnThreadsRunning; +extern CAddrMan addrman; extern std::vector vNodes; extern CCriticalSection cs_vNodes; -extern std::map, CAddress> mapAddresses; -extern CCriticalSection cs_mapAddresses; extern std::map mapRelay; extern std::deque > vRelayExpiration; extern CCriticalSection cs_mapRelay; extern std::map mapAlreadyAskedFor; -// Settings -extern int fUseProxy; -extern CAddress addrProxy; - +/** Information about a peer */ class CNode { public: @@ -507,7 +117,7 @@ public: int64 nLastRecv; int64 nLastSendEmpty; int64 nTimeConnected; - unsigned int nHeaderStart; + int nHeaderStart; unsigned int nMessageStart; CAddress addr; int nVersion; @@ -517,8 +127,16 @@ public: bool fNetworkNode; bool fSuccessfullyConnected; bool fDisconnect; + bool fHasGrant; // whether to call semOutbound.post() at disconnect protected: int nRefCount; + + // Denial-of-service detection/prevention + // Key is ip address, value is banned-until-time + static std::map setBanned; + static CCriticalSection cs_setBanned; + int nMisbehavior; + public: int64 nReleaseTime; std::map mapRequests; @@ -535,29 +153,15 @@ public: std::set setKnown; // inventory based relay - std::set setInventoryKnown; + mruset setInventoryKnown; std::vector vInventoryToSend; CCriticalSection cs_inventory; std::multimap mapAskFor; - // publish and subscription - std::vector vfSubscribe; - - - CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) + CNode(SOCKET hSocketIn, CAddress addrIn, 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; nLastSendEmpty = GetTime(); @@ -568,6 +172,7 @@ public: nVersion = 0; strSubVer = ""; fClient = false; // set by version message + fHasGrant = false; fInbound = fInboundIn; fNetworkNode = false; fSuccessfullyConnected = false; @@ -579,7 +184,8 @@ public: hashLastGetBlocksEnd = 0; nStartingHeight = -1; fGetAddr = false; - vfSubscribe.assign(256, false); + nMisbehavior = 0; + setInventoryKnown.max_size(SendBufferSize() / 1000); // Be shy and don't send version until we hear if (!fInbound) @@ -639,15 +245,19 @@ public: 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) @@ -660,7 +270,9 @@ public: // 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 = std::max(nNow, nLastTime); + nLastTime = nNow; // Each retry is 2 minutes after the last nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); @@ -671,26 +283,29 @@ public: void BeginMessage(const char* pszCommand) { - cs_vSend.Enter(); + ENTER_CRITICAL_SECTION(cs_vSend); if (nHeaderStart != -1) AbortMessage(); nHeaderStart = vSend.size(); vSend << CMessageHeader(pszCommand, 0); nMessageStart = vSend.size(); - if (fDebug) + 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"); + LEAVE_CRITICAL_SECTION(cs_vSend); + + if (fDebug) + printf("(aborted)\n"); } void EndMessage() @@ -702,7 +317,7 @@ public: return; } - if (nHeaderStart == -1) + if (nHeaderStart < 0) return; // Set the size @@ -710,26 +325,24 @@ public: memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &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()); + 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)); + + if (fDebug) { + printf("(%d bytes)\n", nSize); } - printf("(%d bytes) ", nSize); - printf("\n"); - nHeaderStart = -1; nMessageStart = -1; - cs_vSend.Leave(); + LEAVE_CRITICAL_SECTION(cs_vSend); } void EndMessageAbortIfEmpty() { - if (nHeaderStart == -1) + if (nHeaderStart < 0) return; int nSize = vSend.size() - nMessageStart; if (nSize > 0) @@ -740,18 +353,7 @@ public: - 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) @@ -919,8 +521,10 @@ public: uint256 hashReply; RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); - CRITICAL_BLOCK(cs_mapRequests) + { + LOCK(cs_mapRequests); mapRequests[hashReply] = CRequestTracker(fn, param1); + } PushMessage(pszCommand, hashReply); } @@ -932,8 +536,10 @@ public: 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); } @@ -945,8 +551,10 @@ public: 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); } @@ -959,6 +567,25 @@ public: 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 }; @@ -973,15 +600,17 @@ public: 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 void RelayMessage(const CInv& inv, const T& a) { - CDataStream ss(SER_NETWORK); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(10000); ss << a; RelayMessage(inv, ss); @@ -990,8 +619,8 @@ void RelayMessage(const CInv& inv, const T& a) template<> inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) { - CRITICAL_BLOCK(cs_mapRelay) { + LOCK(cs_mapRelay); // Expire old relay messages while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) { @@ -1000,7 +629,7 @@ inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) } // Save original serialized message so newer versions are preserved - mapRelay[inv] = ss; + mapRelay.insert(std::make_pair(inv, ss)); vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); } @@ -1008,58 +637,4 @@ inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) } - - - - - - -// -// Templates for the publish and subscription system. -// The object being published as T& obj needs to have: -// a set setSources member -// specializations of AdvertInsert and AdvertErase -// Currently implemented for CTable and CProduct. -// - -template -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 -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 -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