-
+ 2A64CDCF7A06F0DBAC40F854A8925F6A65B3B5E599C77679B4B3E21E5CAEA3941D722E1BBA60DF17F69698947C4159397E75A42073C5F9D764FBD625E32FE0D4
bitcoin/src/net.h
(0 . 0)(1 . 732)
17539 // /****************************\
17540 // * EXPERIMENTAL BRANCH. *
17541 // * FOR LABORATORY USE ONLY. *
17542 // ********************************
17543 // ************
17544 // **************
17545 // ****************
17546 // **** **** ****
17547 // *** *** ***
17548 // *** *** ***
17549 // *** * * **
17550 // ******** ********
17551 // ******* ******
17552 // *** **
17553 // * ******* **
17554 // ** * * * * *
17555 // ** * * ***
17556 // **** * * * * ****
17557 // **** *** * * ** ***
17558 // **** ********* ******
17559 // ******* ***** *******
17560 // ********* ****** **
17561 // ** ****** ******
17562 // ** ******* **
17563 // ** ******* ***
17564 // **** ******** ************
17565 // ************ ************
17566 // ******** *******
17567 // ****** ****
17568 // *** ***
17569 // ********************************
17570 // Copyright (c) 2009-2010 Satoshi Nakamoto
17571 // Copyright (c) 2009-2012 The Bitcoin developers
17572 // Distributed under the MIT/X11 software license, see the accompanying
17573 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
17574 #ifndef BITCOIN_NET_H
17575 #define BITCOIN_NET_H
17576
17577 #include <deque>
17578 #include <boost/array.hpp>
17579 #include <boost/foreach.hpp>
17580 #include <openssl/rand.h>
17581
17582 #ifndef WIN32
17583 #include <arpa/inet.h>
17584 #endif
17585
17586 #include "protocol.h"
17587
17588 class CAddrDB;
17589 class CRequestTracker;
17590 class CNode;
17591 class CBlockIndex;
17592 extern int nBestHeight;
17593 extern int nConnectTimeout;
17594
17595
17596
17597 inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
17598 inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
17599 static const unsigned int PUBLISH_HOPS = 5;
17600
17601 bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout);
17602 bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
17603 bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
17604 bool GetMyExternalIP(unsigned int& ipRet);
17605 bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
17606 void AddressCurrentlyConnected(const CAddress& addr);
17607 CNode* FindNode(unsigned int ip);
17608 CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
17609 void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
17610 bool AnySubscribed(unsigned int nChannel);
17611 void MapPort(bool fMapPort);
17612 bool BindListenPort(std::string& strError=REF(std::string()));
17613 void StartNode(void* parg);
17614 bool StopNode();
17615
17616 enum
17617 {
17618 MSG_TX = 1,
17619 MSG_BLOCK,
17620 };
17621
17622 class CRequestTracker
17623 {
17624 public:
17625 void (*fn)(void*, CDataStream&);
17626 void* param1;
17627
17628 explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
17629 {
17630 fn = fnIn;
17631 param1 = param1In;
17632 }
17633
17634 bool IsNull()
17635 {
17636 return fn == NULL;
17637 }
17638 };
17639
17640
17641
17642
17643
17644 extern bool fClient;
17645 extern bool fAllowDNS;
17646 extern uint64 nLocalServices;
17647 extern CAddress addrLocalHost;
17648 extern uint64 nLocalHostNonce;
17649 extern boost::array<int, 10> vnThreadsRunning;
17650
17651 extern std::vector<CNode*> vNodes;
17652 extern CCriticalSection cs_vNodes;
17653 extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
17654 extern CCriticalSection cs_mapAddresses;
17655 extern std::map<CInv, CDataStream> mapRelay;
17656 extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
17657 extern CCriticalSection cs_mapRelay;
17658 extern std::map<CInv, int64> mapAlreadyAskedFor;
17659
17660 // Settings
17661 extern int fUseProxy;
17662 extern CAddress addrProxy;
17663
17664
17665
17666
17667
17668
17669 class CNode
17670 {
17671 public:
17672 // socket
17673 uint64 nServices;
17674 SOCKET hSocket;
17675 CDataStream vSend;
17676 CDataStream vRecv;
17677 CCriticalSection cs_vSend;
17678 CCriticalSection cs_vRecv;
17679 int64 nLastSend;
17680 int64 nLastRecv;
17681 int64 nLastSendEmpty;
17682 int64 nTimeConnected;
17683 unsigned int nHeaderStart;
17684 unsigned int nMessageStart;
17685 CAddress addr;
17686 int nVersion;
17687 std::string strSubVer;
17688 bool fClient;
17689 bool fInbound;
17690 bool fNetworkNode;
17691 bool fSuccessfullyConnected;
17692 bool fDisconnect;
17693 protected:
17694 int nRefCount;
17695
17696 // Denial-of-service detection/prevention
17697 // Key is ip address, value is banned-until-time
17698 static std::map<unsigned int, int64> setBanned;
17699 static CCriticalSection cs_setBanned;
17700 int nMisbehavior;
17701
17702 public:
17703 int64 nReleaseTime;
17704 std::map<uint256, CRequestTracker> mapRequests;
17705 CCriticalSection cs_mapRequests;
17706 uint256 hashContinue;
17707 CBlockIndex* pindexLastGetBlocksBegin;
17708 uint256 hashLastGetBlocksEnd;
17709 int nStartingHeight;
17710
17711 // flood relay
17712 std::vector<CAddress> vAddrToSend;
17713 std::set<CAddress> setAddrKnown;
17714 bool fGetAddr;
17715 std::set<uint256> setKnown;
17716
17717 // inventory based relay
17718 std::set<CInv> setInventoryKnown;
17719 std::vector<CInv> vInventoryToSend;
17720 CCriticalSection cs_inventory;
17721 std::multimap<int64, CInv> mapAskFor;
17722
17723 // publish and subscription
17724 std::vector<char> vfSubscribe;
17725
17726 CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
17727 {
17728 nServices = 0;
17729 hSocket = hSocketIn;
17730 vSend.SetType(SER_NETWORK);
17731 vSend.SetVersion(0);
17732 vRecv.SetType(SER_NETWORK);
17733 vRecv.SetVersion(0);
17734 // Version 0.2 obsoletes 20 Feb 2012
17735 if (GetTime() > 1329696000)
17736 {
17737 vSend.SetVersion(209);
17738 vRecv.SetVersion(209);
17739 }
17740 nLastSend = 0;
17741 nLastRecv = 0;
17742 nLastSendEmpty = GetTime();
17743 nTimeConnected = GetTime();
17744 nHeaderStart = -1;
17745 nMessageStart = -1;
17746 addr = addrIn;
17747 nVersion = 0;
17748 strSubVer = "";
17749 fClient = false; // set by version message
17750 fInbound = fInboundIn;
17751 fNetworkNode = false;
17752 fSuccessfullyConnected = false;
17753 fDisconnect = false;
17754 nRefCount = 0;
17755 nReleaseTime = 0;
17756 hashContinue = 0;
17757 pindexLastGetBlocksBegin = 0;
17758 hashLastGetBlocksEnd = 0;
17759 nStartingHeight = -1;
17760 fGetAddr = false;
17761 vfSubscribe.assign(256, false);
17762 nMisbehavior = 0;
17763
17764 // Be shy and don't send version until we hear
17765 if (!fInbound)
17766 PushVersion();
17767 }
17768
17769 ~CNode()
17770 {
17771 if (hSocket != INVALID_SOCKET)
17772 {
17773 closesocket(hSocket);
17774 hSocket = INVALID_SOCKET;
17775 }
17776 }
17777
17778 private:
17779 CNode(const CNode&);
17780 void operator=(const CNode&);
17781 public:
17782
17783
17784 int GetRefCount()
17785 {
17786 return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
17787 }
17788
17789 CNode* AddRef(int64 nTimeout=0)
17790 {
17791 if (nTimeout != 0)
17792 nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
17793 else
17794 nRefCount++;
17795 return this;
17796 }
17797
17798 void Release()
17799 {
17800 nRefCount--;
17801 }
17802
17803
17804
17805 void AddAddressKnown(const CAddress& addr)
17806 {
17807 setAddrKnown.insert(addr);
17808 }
17809
17810 void PushAddress(const CAddress& addr)
17811 {
17812 // Known checking here is only to save space from duplicates.
17813 // SendMessages will filter it again for knowns that were added
17814 // after addresses were pushed.
17815 if (addr.IsValid() && !setAddrKnown.count(addr))
17816 vAddrToSend.push_back(addr);
17817 }
17818
17819
17820 void AddInventoryKnown(const CInv& inv)
17821 {
17822 CRITICAL_BLOCK(cs_inventory)
17823 setInventoryKnown.insert(inv);
17824 }
17825
17826 void PushInventory(const CInv& inv)
17827 {
17828 CRITICAL_BLOCK(cs_inventory)
17829 if (!setInventoryKnown.count(inv))
17830 vInventoryToSend.push_back(inv);
17831 }
17832
17833 void AskFor(const CInv& inv)
17834 {
17835 // We're using mapAskFor as a priority queue,
17836 // the key is the earliest time the request can be sent
17837 int64& nRequestTime = mapAlreadyAskedFor[inv];
17838 printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
17839
17840 // Make sure not to reuse time indexes to keep things in the same order
17841 int64 nNow = (GetTime() - 1) * 1000000;
17842 static int64 nLastTime;
17843 ++nLastTime;
17844 nNow = std::max(nNow, nLastTime);
17845 nLastTime = nNow;
17846
17847 // Each retry is 2 minutes after the last
17848 nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
17849 mapAskFor.insert(std::make_pair(nRequestTime, inv));
17850 }
17851
17852
17853
17854 void BeginMessage(const char* pszCommand)
17855 {
17856 ENTER_CRITICAL_SECTION(cs_vSend);
17857 if (nHeaderStart != -1)
17858 AbortMessage();
17859 nHeaderStart = vSend.size();
17860 vSend << CMessageHeader(pszCommand, 0);
17861 nMessageStart = vSend.size();
17862 if (fDebug) {
17863 printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
17864 printf("sending: %s ", pszCommand);
17865 }
17866 }
17867
17868 void AbortMessage()
17869 {
17870 if (nHeaderStart == -1)
17871 return;
17872 vSend.resize(nHeaderStart);
17873 nHeaderStart = -1;
17874 nMessageStart = -1;
17875 LEAVE_CRITICAL_SECTION(cs_vSend);
17876
17877 if (fDebug)
17878 printf("(aborted)\n");
17879 }
17880
17881 void EndMessage()
17882 {
17883 if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
17884 {
17885 printf("dropmessages DROPPING SEND MESSAGE\n");
17886 AbortMessage();
17887 return;
17888 }
17889
17890 if (nHeaderStart == -1)
17891 return;
17892
17893 // Set the size
17894 unsigned int nSize = vSend.size() - nMessageStart;
17895 memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
17896
17897 // Set the checksum
17898 if (vSend.GetVersion() >= 209)
17899 {
17900 uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
17901 unsigned int nChecksum = 0;
17902 memcpy(&nChecksum, &hash, sizeof(nChecksum));
17903 assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
17904 memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
17905 }
17906
17907 if (fDebug) {
17908 printf("(%d bytes)\n", nSize);
17909 }
17910
17911 nHeaderStart = -1;
17912 nMessageStart = -1;
17913 LEAVE_CRITICAL_SECTION(cs_vSend);
17914 }
17915
17916 void EndMessageAbortIfEmpty()
17917 {
17918 if (nHeaderStart == -1)
17919 return;
17920 int nSize = vSend.size() - nMessageStart;
17921 if (nSize > 0)
17922 EndMessage();
17923 else
17924 AbortMessage();
17925 }
17926
17927
17928
17929 void PushVersion()
17930 {
17931 /// when NTP implemented, change to just nTime = GetAdjustedTime()
17932 int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
17933 CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
17934 CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress("0.0.0.0") : addrLocalHost);
17935 RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
17936 PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
17937 nLocalHostNonce, std::string(pszSubVer), nBestHeight);
17938 }
17939
17940
17941
17942
17943 void PushMessage(const char* pszCommand)
17944 {
17945 try
17946 {
17947 BeginMessage(pszCommand);
17948 EndMessage();
17949 }
17950 catch (...)
17951 {
17952 AbortMessage();
17953 throw;
17954 }
17955 }
17956
17957 template<typename T1>
17958 void PushMessage(const char* pszCommand, const T1& a1)
17959 {
17960 try
17961 {
17962 BeginMessage(pszCommand);
17963 vSend << a1;
17964 EndMessage();
17965 }
17966 catch (...)
17967 {
17968 AbortMessage();
17969 throw;
17970 }
17971 }
17972
17973 template<typename T1, typename T2>
17974 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
17975 {
17976 try
17977 {
17978 BeginMessage(pszCommand);
17979 vSend << a1 << a2;
17980 EndMessage();
17981 }
17982 catch (...)
17983 {
17984 AbortMessage();
17985 throw;
17986 }
17987 }
17988
17989 template<typename T1, typename T2, typename T3>
17990 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
17991 {
17992 try
17993 {
17994 BeginMessage(pszCommand);
17995 vSend << a1 << a2 << a3;
17996 EndMessage();
17997 }
17998 catch (...)
17999 {
18000 AbortMessage();
18001 throw;
18002 }
18003 }
18004
18005 template<typename T1, typename T2, typename T3, typename T4>
18006 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
18007 {
18008 try
18009 {
18010 BeginMessage(pszCommand);
18011 vSend << a1 << a2 << a3 << a4;
18012 EndMessage();
18013 }
18014 catch (...)
18015 {
18016 AbortMessage();
18017 throw;
18018 }
18019 }
18020
18021 template<typename T1, typename T2, typename T3, typename T4, typename T5>
18022 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
18023 {
18024 try
18025 {
18026 BeginMessage(pszCommand);
18027 vSend << a1 << a2 << a3 << a4 << a5;
18028 EndMessage();
18029 }
18030 catch (...)
18031 {
18032 AbortMessage();
18033 throw;
18034 }
18035 }
18036
18037 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
18038 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
18039 {
18040 try
18041 {
18042 BeginMessage(pszCommand);
18043 vSend << a1 << a2 << a3 << a4 << a5 << a6;
18044 EndMessage();
18045 }
18046 catch (...)
18047 {
18048 AbortMessage();
18049 throw;
18050 }
18051 }
18052
18053 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
18054 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)
18055 {
18056 try
18057 {
18058 BeginMessage(pszCommand);
18059 vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
18060 EndMessage();
18061 }
18062 catch (...)
18063 {
18064 AbortMessage();
18065 throw;
18066 }
18067 }
18068
18069 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
18070 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)
18071 {
18072 try
18073 {
18074 BeginMessage(pszCommand);
18075 vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
18076 EndMessage();
18077 }
18078 catch (...)
18079 {
18080 AbortMessage();
18081 throw;
18082 }
18083 }
18084
18085 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
18086 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)
18087 {
18088 try
18089 {
18090 BeginMessage(pszCommand);
18091 vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
18092 EndMessage();
18093 }
18094 catch (...)
18095 {
18096 AbortMessage();
18097 throw;
18098 }
18099 }
18100
18101
18102 void PushRequest(const char* pszCommand,
18103 void (*fn)(void*, CDataStream&), void* param1)
18104 {
18105 uint256 hashReply;
18106 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
18107
18108 CRITICAL_BLOCK(cs_mapRequests)
18109 mapRequests[hashReply] = CRequestTracker(fn, param1);
18110
18111 PushMessage(pszCommand, hashReply);
18112 }
18113
18114 template<typename T1>
18115 void PushRequest(const char* pszCommand, const T1& a1,
18116 void (*fn)(void*, CDataStream&), void* param1)
18117 {
18118 uint256 hashReply;
18119 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
18120
18121 CRITICAL_BLOCK(cs_mapRequests)
18122 mapRequests[hashReply] = CRequestTracker(fn, param1);
18123
18124 PushMessage(pszCommand, hashReply, a1);
18125 }
18126
18127 template<typename T1, typename T2>
18128 void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
18129 void (*fn)(void*, CDataStream&), void* param1)
18130 {
18131 uint256 hashReply;
18132 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
18133
18134 CRITICAL_BLOCK(cs_mapRequests)
18135 mapRequests[hashReply] = CRequestTracker(fn, param1);
18136
18137 PushMessage(pszCommand, hashReply, a1, a2);
18138 }
18139
18140
18141
18142 void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
18143 bool IsSubscribed(unsigned int nChannel);
18144 void Subscribe(unsigned int nChannel, unsigned int nHops=0);
18145 void CancelSubscribe(unsigned int nChannel);
18146 void CloseSocketDisconnect();
18147 void Cleanup();
18148
18149
18150 // Denial-of-service detection/prevention
18151 // The idea is to detect peers that are behaving
18152 // badly and disconnect/ban them, but do it in a
18153 // one-coding-mistake-won't-shatter-the-entire-network
18154 // way.
18155 // IMPORTANT: There should be nothing I can give a
18156 // node that it will forward on that will make that
18157 // node's peers drop it. If there is, an attacker
18158 // can isolate a node and/or try to split the network.
18159 // Dropping a node for sending stuff that is invalid
18160 // now but might be valid in a later version is also
18161 // dangerous, because it can cause a network split
18162 // between nodes running old code and nodes running
18163 // new code.
18164 static void ClearBanned(); // needed for unit testing
18165 static bool IsBanned(unsigned int ip);
18166 bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
18167 };
18168
18169
18170
18171
18172
18173
18174
18175
18176
18177
18178 inline void RelayInventory(const CInv& inv)
18179 {
18180 // Put on lists to offer to the other nodes
18181 CRITICAL_BLOCK(cs_vNodes)
18182 BOOST_FOREACH(CNode* pnode, vNodes)
18183 pnode->PushInventory(inv);
18184 }
18185
18186 template<typename T>
18187 void RelayMessage(const CInv& inv, const T& a)
18188 {
18189 CDataStream ss(SER_NETWORK);
18190 ss.reserve(10000);
18191 ss << a;
18192 RelayMessage(inv, ss);
18193 }
18194
18195 template<>
18196 inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
18197 {
18198 CRITICAL_BLOCK(cs_mapRelay)
18199 {
18200 // Expire old relay messages
18201 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
18202 {
18203 mapRelay.erase(vRelayExpiration.front().second);
18204 vRelayExpiration.pop_front();
18205 }
18206
18207 // Save original serialized message so newer versions are preserved
18208 mapRelay[inv] = ss;
18209 vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
18210 }
18211
18212 RelayInventory(inv);
18213 }
18214
18215
18216
18217
18218
18219
18220
18221
18222 //
18223 // Templates for the publish and subscription system.
18224 // The object being published as T& obj needs to have:
18225 // a set<unsigned int> setSources member
18226 // specializations of AdvertInsert and AdvertErase
18227 // Currently implemented for CTable and CProduct.
18228 //
18229
18230 template<typename T>
18231 void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
18232 {
18233 // Add to sources
18234 obj.setSources.insert(pfrom->addr.ip);
18235
18236 if (!AdvertInsert(obj))
18237 return;
18238
18239 // Relay
18240 CRITICAL_BLOCK(cs_vNodes)
18241 BOOST_FOREACH(CNode* pnode, vNodes)
18242 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
18243 pnode->PushMessage("publish", nChannel, nHops, obj);
18244 }
18245
18246 template<typename T>
18247 void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
18248 {
18249 uint256 hash = obj.GetHash();
18250
18251 CRITICAL_BLOCK(cs_vNodes)
18252 BOOST_FOREACH(CNode* pnode, vNodes)
18253 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
18254 pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
18255
18256 AdvertErase(obj);
18257 }
18258
18259 template<typename T>
18260 void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
18261 {
18262 // Remove a source
18263 obj.setSources.erase(pfrom->addr.ip);
18264
18265 // If no longer supported by any sources, cancel it
18266 if (obj.setSources.empty())
18267 AdvertStopPublish(pfrom, nChannel, nHops, obj);
18268 }
18269
18270 #endif