Limit response to getblocks to half of output buffer size
[novacoin.git] / src / net.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
4 #ifndef BITCOIN_NET_H
5 #define BITCOIN_NET_H
6
7 #include <deque>
8 #include <boost/array.hpp>
9 #include <openssl/rand.h>
10
11 #ifndef __WXMSW__
12 #include <arpa/inet.h>
13 #endif
14
15 class CMessageHeader;
16 class CAddress;
17 class CInv;
18 class CRequestTracker;
19 class CNode;
20 class CBlockIndex;
21 extern int nBestHeight;
22 extern int nConnectTimeout;
23
24
25
26 inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
27 inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
28 inline unsigned short GetDefaultPort() { return fTestNet ? 18333 : 8333; }
29 static const unsigned int PUBLISH_HOPS = 5;
30 enum
31 {
32     NODE_NETWORK = (1 << 0),
33 };
34
35
36
37
38 bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout);
39 bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
40 bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
41 bool GetMyExternalIP(unsigned int& ipRet);
42 bool AddAddress(CAddress addr, int64 nTimePenalty=0);
43 void AddressCurrentlyConnected(const CAddress& addr);
44 CNode* FindNode(unsigned int ip);
45 CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
46 void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
47 bool AnySubscribed(unsigned int nChannel);
48 void MapPort(bool fMapPort);
49 void DNSAddressSeed();
50 bool BindListenPort(std::string& strError=REF(std::string()));
51 void StartNode(void* parg);
52 bool StopNode();
53
54
55
56
57
58
59
60
61 //
62 // Message header
63 //  (4) message start
64 //  (12) command
65 //  (4) size
66 //  (4) checksum
67
68 extern char pchMessageStart[4];
69
70 class CMessageHeader
71 {
72 public:
73     enum { COMMAND_SIZE=12 };
74     char pchMessageStart[sizeof(::pchMessageStart)];
75     char pchCommand[COMMAND_SIZE];
76     unsigned int nMessageSize;
77     unsigned int nChecksum;
78
79     CMessageHeader()
80     {
81         memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
82         memset(pchCommand, 0, sizeof(pchCommand));
83         pchCommand[1] = 1;
84         nMessageSize = -1;
85         nChecksum = 0;
86     }
87
88     CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
89     {
90         memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
91         strncpy(pchCommand, pszCommand, COMMAND_SIZE);
92         nMessageSize = nMessageSizeIn;
93         nChecksum = 0;
94     }
95
96     IMPLEMENT_SERIALIZE
97     (
98         READWRITE(FLATDATA(pchMessageStart));
99         READWRITE(FLATDATA(pchCommand));
100         READWRITE(nMessageSize);
101         if (nVersion >= 209)
102             READWRITE(nChecksum);
103     )
104
105     std::string GetCommand()
106     {
107         if (pchCommand[COMMAND_SIZE-1] == 0)
108             return std::string(pchCommand, pchCommand + strlen(pchCommand));
109         else
110             return std::string(pchCommand, pchCommand + COMMAND_SIZE);
111     }
112
113     bool IsValid()
114     {
115         // Check start string
116         if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
117             return false;
118
119         // Check the command string for errors
120         for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
121         {
122             if (*p1 == 0)
123             {
124                 // Must be all zeros after the first zero
125                 for (; p1 < pchCommand + COMMAND_SIZE; p1++)
126                     if (*p1 != 0)
127                         return false;
128             }
129             else if (*p1 < ' ' || *p1 > 0x7E)
130                 return false;
131         }
132
133         // Message size
134         if (nMessageSize > MAX_SIZE)
135         {
136             printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize);
137             return false;
138         }
139
140         return true;
141     }
142 };
143
144
145
146
147
148
149 static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
150
151 class CAddress
152 {
153 public:
154     uint64 nServices;
155     unsigned char pchReserved[12];
156     unsigned int ip;
157     unsigned short port;
158
159     // disk and network only
160     unsigned int nTime;
161
162     // memory only
163     unsigned int nLastTry;
164
165     CAddress()
166     {
167         Init();
168     }
169
170     CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK)
171     {
172         Init();
173         ip = ipIn;
174         port = htons(portIn == 0 ? GetDefaultPort() : portIn);
175         nServices = nServicesIn;
176     }
177
178     explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK)
179     {
180         Init();
181         ip = sockaddr.sin_addr.s_addr;
182         port = sockaddr.sin_port;
183         nServices = nServicesIn;
184     }
185
186     explicit CAddress(const char* pszIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
187     {
188         Init();
189         Lookup(pszIn, *this, nServicesIn, fNameLookup, portIn);
190     }
191
192     explicit CAddress(const char* pszIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
193     {
194         Init();
195         Lookup(pszIn, *this, nServicesIn, fNameLookup, 0, true);
196     }
197
198     explicit CAddress(std::string strIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
199     {
200         Init();
201         Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, portIn);
202     }
203
204     explicit CAddress(std::string strIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK)
205     {
206         Init();
207         Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, 0, true);
208     }
209
210     void Init()
211     {
212         nServices = NODE_NETWORK;
213         memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
214         ip = INADDR_NONE;
215         port = htons(GetDefaultPort());
216         nTime = 100000000;
217         nLastTry = 0;
218     }
219
220     IMPLEMENT_SERIALIZE
221     (
222         if (fRead)
223             const_cast<CAddress*>(this)->Init();
224         if (nType & SER_DISK)
225             READWRITE(nVersion);
226         if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
227             READWRITE(nTime);
228         READWRITE(nServices);
229         READWRITE(FLATDATA(pchReserved)); // for IPv6
230         READWRITE(ip);
231         READWRITE(port);
232     )
233
234     friend inline bool operator==(const CAddress& a, const CAddress& b)
235     {
236         return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
237                 a.ip   == b.ip &&
238                 a.port == b.port);
239     }
240
241     friend inline bool operator!=(const CAddress& a, const CAddress& b)
242     {
243         return (!(a == b));
244     }
245
246     friend inline bool operator<(const CAddress& a, const CAddress& b)
247     {
248         int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
249         if (ret < 0)
250             return true;
251         else if (ret == 0)
252         {
253             if (ntohl(a.ip) < ntohl(b.ip))
254                 return true;
255             else if (a.ip == b.ip)
256                 return ntohs(a.port) < ntohs(b.port);
257         }
258         return false;
259     }
260
261     std::vector<unsigned char> GetKey() const
262     {
263         CDataStream ss;
264         ss.reserve(18);
265         ss << FLATDATA(pchReserved) << ip << port;
266
267         #if defined(_MSC_VER) && _MSC_VER < 1300
268         return std::vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
269         #else
270         return std::vector<unsigned char>(ss.begin(), ss.end());
271         #endif
272     }
273
274     struct sockaddr_in GetSockAddr() const
275     {
276         struct sockaddr_in sockaddr;
277         memset(&sockaddr, 0, sizeof(sockaddr));
278         sockaddr.sin_family = AF_INET;
279         sockaddr.sin_addr.s_addr = ip;
280         sockaddr.sin_port = port;
281         return sockaddr;
282     }
283
284     bool IsIPv4() const
285     {
286         return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
287     }
288
289     bool IsRFC1918() const
290     {
291       return IsIPv4() && (GetByte(3) == 10 ||
292         (GetByte(3) == 192 && GetByte(2) == 168) ||
293         (GetByte(3) == 172 &&
294           (GetByte(2) >= 16 && GetByte(2) <= 31)));
295     }
296
297     bool IsRFC3927() const
298     {
299       return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
300     }
301
302     bool IsLocal() const
303     {
304       return IsIPv4() && (GetByte(3) == 127 ||
305           GetByte(3) == 0);
306     }
307
308     bool IsRoutable() const
309     {
310         return IsValid() &&
311             !(IsRFC1918() || IsRFC3927() || IsLocal());
312     }
313
314     bool IsValid() const
315     {
316         // Clean up 3-byte shifted addresses caused by garbage in size field
317         // of addr messages from versions before 0.2.9 checksum.
318         // Two consecutive addr messages look like this:
319         // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
320         // so if the first length field is garbled, it reads the second batch
321         // of addr misaligned by 3 bytes.
322         if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
323             return false;
324
325         return (ip != 0 && ip != INADDR_NONE && port != htons(USHRT_MAX));
326     }
327
328     unsigned char GetByte(int n) const
329     {
330         return ((unsigned char*)&ip)[3-n];
331     }
332
333     std::string ToStringIPPort() const
334     {
335         return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
336     }
337
338     std::string ToStringIP() const
339     {
340         return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
341     }
342
343     std::string ToStringPort() const
344     {
345         return strprintf("%u", ntohs(port));
346     }
347
348     std::string ToString() const
349     {
350         return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
351     }
352
353     void print() const
354     {
355         printf("CAddress(%s)\n", ToString().c_str());
356     }
357 };
358
359
360
361
362
363
364
365 enum
366 {
367     MSG_TX = 1,
368     MSG_BLOCK,
369 };
370
371 static const char* ppszTypeName[] =
372 {
373     "ERROR",
374     "tx",
375     "block",
376 };
377
378 class CInv
379 {
380 public:
381     int type;
382     uint256 hash;
383
384     CInv()
385     {
386         type = 0;
387         hash = 0;
388     }
389
390     CInv(int typeIn, const uint256& hashIn)
391     {
392         type = typeIn;
393         hash = hashIn;
394     }
395
396     CInv(const std::string& strType, const uint256& hashIn)
397     {
398         int i;
399         for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
400         {
401             if (strType == ppszTypeName[i])
402             {
403                 type = i;
404                 break;
405             }
406         }
407         if (i == ARRAYLEN(ppszTypeName))
408             throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
409         hash = hashIn;
410     }
411
412     IMPLEMENT_SERIALIZE
413     (
414         READWRITE(type);
415         READWRITE(hash);
416     )
417
418     friend inline bool operator<(const CInv& a, const CInv& b)
419     {
420         return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
421     }
422
423     bool IsKnownType() const
424     {
425         return (type >= 1 && type < ARRAYLEN(ppszTypeName));
426     }
427
428     const char* GetCommand() const
429     {
430         if (!IsKnownType())
431             throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
432         return ppszTypeName[type];
433     }
434
435     std::string ToString() const
436     {
437         return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
438     }
439
440     void print() const
441     {
442         printf("CInv(%s)\n", ToString().c_str());
443     }
444 };
445
446
447
448
449
450 class CRequestTracker
451 {
452 public:
453     void (*fn)(void*, CDataStream&);
454     void* param1;
455
456     explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
457     {
458         fn = fnIn;
459         param1 = param1In;
460     }
461
462     bool IsNull()
463     {
464         return fn == NULL;
465     }
466 };
467
468
469
470
471
472 extern bool fClient;
473 extern bool fAllowDNS;
474 extern uint64 nLocalServices;
475 extern CAddress addrLocalHost;
476 extern CNode* pnodeLocalHost;
477 extern uint64 nLocalHostNonce;
478 extern boost::array<int, 10> vnThreadsRunning;
479 extern SOCKET hListenSocket;
480
481 extern std::vector<CNode*> vNodes;
482 extern CCriticalSection cs_vNodes;
483 extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
484 extern CCriticalSection cs_mapAddresses;
485 extern std::map<CInv, CDataStream> mapRelay;
486 extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
487 extern CCriticalSection cs_mapRelay;
488 extern std::map<CInv, int64> mapAlreadyAskedFor;
489
490 // Settings
491 extern int fUseProxy;
492 extern CAddress addrProxy;
493
494
495
496
497
498
499 class CNode
500 {
501 public:
502     // socket
503     uint64 nServices;
504     SOCKET hSocket;
505     CDataStream vSend;
506     CDataStream vRecv;
507     CCriticalSection cs_vSend;
508     CCriticalSection cs_vRecv;
509     int64 nLastSend;
510     int64 nLastRecv;
511     int64 nLastSendEmpty;
512     int64 nTimeConnected;
513     unsigned int nHeaderStart;
514     unsigned int nMessageStart;
515     CAddress addr;
516     int nVersion;
517     std::string strSubVer;
518     bool fClient;
519     bool fInbound;
520     bool fNetworkNode;
521     bool fSuccessfullyConnected;
522     bool fDisconnect;
523 protected:
524     int nRefCount;
525 public:
526     int64 nReleaseTime;
527     std::map<uint256, CRequestTracker> mapRequests;
528     CCriticalSection cs_mapRequests;
529     uint256 hashContinue;
530     CBlockIndex* pindexLastGetBlocksBegin;
531     uint256 hashLastGetBlocksEnd;
532     int nStartingHeight;
533
534     // flood relay
535     std::vector<CAddress> vAddrToSend;
536     std::set<CAddress> setAddrKnown;
537     bool fGetAddr;
538     std::set<uint256> setKnown;
539
540     // inventory based relay
541     std::set<CInv> setInventoryKnown;
542     std::vector<CInv> vInventoryToSend;
543     CCriticalSection cs_inventory;
544     std::multimap<int64, CInv> mapAskFor;
545
546     // publish and subscription
547     std::vector<char> vfSubscribe;
548
549
550     CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
551     {
552         nServices = 0;
553         hSocket = hSocketIn;
554         vSend.SetType(SER_NETWORK);
555         vSend.SetVersion(0);
556         vRecv.SetType(SER_NETWORK);
557         vRecv.SetVersion(0);
558         // Version 0.2 obsoletes 20 Feb 2012
559         if (GetTime() > 1329696000)
560         {
561             vSend.SetVersion(209);
562             vRecv.SetVersion(209);
563         }
564         nLastSend = 0;
565         nLastRecv = 0;
566         nLastSendEmpty = GetTime();
567         nTimeConnected = GetTime();
568         nHeaderStart = -1;
569         nMessageStart = -1;
570         addr = addrIn;
571         nVersion = 0;
572         strSubVer = "";
573         fClient = false; // set by version message
574         fInbound = fInboundIn;
575         fNetworkNode = false;
576         fSuccessfullyConnected = false;
577         fDisconnect = false;
578         nRefCount = 0;
579         nReleaseTime = 0;
580         hashContinue = 0;
581         pindexLastGetBlocksBegin = 0;
582         hashLastGetBlocksEnd = 0;
583         nStartingHeight = -1;
584         fGetAddr = false;
585         vfSubscribe.assign(256, false);
586
587         // Be shy and don't send version until we hear
588         if (!fInbound)
589             PushVersion();
590     }
591
592     ~CNode()
593     {
594         if (hSocket != INVALID_SOCKET)
595         {
596             closesocket(hSocket);
597             hSocket = INVALID_SOCKET;
598         }
599     }
600
601 private:
602     CNode(const CNode&);
603     void operator=(const CNode&);
604 public:
605
606
607     int GetRefCount()
608     {
609         return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
610     }
611
612     CNode* AddRef(int64 nTimeout=0)
613     {
614         if (nTimeout != 0)
615             nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
616         else
617             nRefCount++;
618         return this;
619     }
620
621     void Release()
622     {
623         nRefCount--;
624     }
625
626
627
628     void AddAddressKnown(const CAddress& addr)
629     {
630         setAddrKnown.insert(addr);
631     }
632
633     void PushAddress(const CAddress& addr)
634     {
635         // Known checking here is only to save space from duplicates.
636         // SendMessages will filter it again for knowns that were added
637         // after addresses were pushed.
638         if (addr.IsValid() && !setAddrKnown.count(addr))
639             vAddrToSend.push_back(addr);
640     }
641
642
643     void AddInventoryKnown(const CInv& inv)
644     {
645         CRITICAL_BLOCK(cs_inventory)
646             setInventoryKnown.insert(inv);
647     }
648
649     void PushInventory(const CInv& inv)
650     {
651         CRITICAL_BLOCK(cs_inventory)
652             if (!setInventoryKnown.count(inv))
653                 vInventoryToSend.push_back(inv);
654     }
655
656     void AskFor(const CInv& inv)
657     {
658         // We're using mapAskFor as a priority queue,
659         // the key is the earliest time the request can be sent
660         int64& nRequestTime = mapAlreadyAskedFor[inv];
661         printf("askfor %s   %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
662
663         // Make sure not to reuse time indexes to keep things in the same order
664         int64 nNow = (GetTime() - 1) * 1000000;
665         static int64 nLastTime;
666         nLastTime = nNow = std::max(nNow, ++nLastTime);
667
668         // Each retry is 2 minutes after the last
669         nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
670         mapAskFor.insert(std::make_pair(nRequestTime, inv));
671     }
672
673
674
675     void BeginMessage(const char* pszCommand)
676     {
677         cs_vSend.Enter();
678         if (nHeaderStart != -1)
679             AbortMessage();
680         nHeaderStart = vSend.size();
681         vSend << CMessageHeader(pszCommand, 0);
682         nMessageStart = vSend.size();
683         if (fDebug)
684             printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
685         printf("sending: %s ", pszCommand);
686     }
687
688     void AbortMessage()
689     {
690         if (nHeaderStart == -1)
691             return;
692         vSend.resize(nHeaderStart);
693         nHeaderStart = -1;
694         nMessageStart = -1;
695         cs_vSend.Leave();
696         printf("(aborted)\n");
697     }
698
699     void EndMessage()
700     {
701         if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
702         {
703             printf("dropmessages DROPPING SEND MESSAGE\n");
704             AbortMessage();
705             return;
706         }
707
708         if (nHeaderStart == -1)
709             return;
710
711         // Set the size
712         unsigned int nSize = vSend.size() - nMessageStart;
713         memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
714
715         // Set the checksum
716         if (vSend.GetVersion() >= 209)
717         {
718             uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
719             unsigned int nChecksum = 0;
720             memcpy(&nChecksum, &hash, sizeof(nChecksum));
721             assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
722             memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
723         }
724
725         printf("(%d bytes) ", nSize);
726         printf("\n");
727
728         nHeaderStart = -1;
729         nMessageStart = -1;
730         cs_vSend.Leave();
731     }
732
733     void EndMessageAbortIfEmpty()
734     {
735         if (nHeaderStart == -1)
736             return;
737         int nSize = vSend.size() - nMessageStart;
738         if (nSize > 0)
739             EndMessage();
740         else
741             AbortMessage();
742     }
743
744
745
746     void PushVersion()
747     {
748         /// when NTP implemented, change to just nTime = GetAdjustedTime()
749         int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
750         CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
751         CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
752         RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
753         PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
754                     nLocalHostNonce, std::string(pszSubVer), nBestHeight);
755     }
756
757
758
759
760     void PushMessage(const char* pszCommand)
761     {
762         try
763         {
764             BeginMessage(pszCommand);
765             EndMessage();
766         }
767         catch (...)
768         {
769             AbortMessage();
770             throw;
771         }
772     }
773
774     template<typename T1>
775     void PushMessage(const char* pszCommand, const T1& a1)
776     {
777         try
778         {
779             BeginMessage(pszCommand);
780             vSend << a1;
781             EndMessage();
782         }
783         catch (...)
784         {
785             AbortMessage();
786             throw;
787         }
788     }
789
790     template<typename T1, typename T2>
791     void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
792     {
793         try
794         {
795             BeginMessage(pszCommand);
796             vSend << a1 << a2;
797             EndMessage();
798         }
799         catch (...)
800         {
801             AbortMessage();
802             throw;
803         }
804     }
805
806     template<typename T1, typename T2, typename T3>
807     void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
808     {
809         try
810         {
811             BeginMessage(pszCommand);
812             vSend << a1 << a2 << a3;
813             EndMessage();
814         }
815         catch (...)
816         {
817             AbortMessage();
818             throw;
819         }
820     }
821
822     template<typename T1, typename T2, typename T3, typename T4>
823     void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
824     {
825         try
826         {
827             BeginMessage(pszCommand);
828             vSend << a1 << a2 << a3 << a4;
829             EndMessage();
830         }
831         catch (...)
832         {
833             AbortMessage();
834             throw;
835         }
836     }
837
838     template<typename T1, typename T2, typename T3, typename T4, typename T5>
839     void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
840     {
841         try
842         {
843             BeginMessage(pszCommand);
844             vSend << a1 << a2 << a3 << a4 << a5;
845             EndMessage();
846         }
847         catch (...)
848         {
849             AbortMessage();
850             throw;
851         }
852     }
853
854     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
855     void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
856     {
857         try
858         {
859             BeginMessage(pszCommand);
860             vSend << a1 << a2 << a3 << a4 << a5 << a6;
861             EndMessage();
862         }
863         catch (...)
864         {
865             AbortMessage();
866             throw;
867         }
868     }
869
870     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
871     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)
872     {
873         try
874         {
875             BeginMessage(pszCommand);
876             vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
877             EndMessage();
878         }
879         catch (...)
880         {
881             AbortMessage();
882             throw;
883         }
884     }
885
886     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
887     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)
888     {
889         try
890         {
891             BeginMessage(pszCommand);
892             vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
893             EndMessage();
894         }
895         catch (...)
896         {
897             AbortMessage();
898             throw;
899         }
900     }
901
902     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
903     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)
904     {
905         try
906         {
907             BeginMessage(pszCommand);
908             vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
909             EndMessage();
910         }
911         catch (...)
912         {
913             AbortMessage();
914             throw;
915         }
916     }
917
918
919     void PushRequest(const char* pszCommand,
920                      void (*fn)(void*, CDataStream&), void* param1)
921     {
922         uint256 hashReply;
923         RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
924
925         CRITICAL_BLOCK(cs_mapRequests)
926             mapRequests[hashReply] = CRequestTracker(fn, param1);
927
928         PushMessage(pszCommand, hashReply);
929     }
930
931     template<typename T1>
932     void PushRequest(const char* pszCommand, const T1& a1,
933                      void (*fn)(void*, CDataStream&), void* param1)
934     {
935         uint256 hashReply;
936         RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
937
938         CRITICAL_BLOCK(cs_mapRequests)
939             mapRequests[hashReply] = CRequestTracker(fn, param1);
940
941         PushMessage(pszCommand, hashReply, a1);
942     }
943
944     template<typename T1, typename T2>
945     void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
946                      void (*fn)(void*, CDataStream&), void* param1)
947     {
948         uint256 hashReply;
949         RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
950
951         CRITICAL_BLOCK(cs_mapRequests)
952             mapRequests[hashReply] = CRequestTracker(fn, param1);
953
954         PushMessage(pszCommand, hashReply, a1, a2);
955     }
956
957
958
959     void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
960     bool IsSubscribed(unsigned int nChannel);
961     void Subscribe(unsigned int nChannel, unsigned int nHops=0);
962     void CancelSubscribe(unsigned int nChannel);
963     void CloseSocketDisconnect();
964     void Cleanup();
965 };
966
967
968
969
970
971
972
973
974
975
976 inline void RelayInventory(const CInv& inv)
977 {
978     // Put on lists to offer to the other nodes
979     CRITICAL_BLOCK(cs_vNodes)
980         BOOST_FOREACH(CNode* pnode, vNodes)
981             pnode->PushInventory(inv);
982 }
983
984 template<typename T>
985 void RelayMessage(const CInv& inv, const T& a)
986 {
987     CDataStream ss(SER_NETWORK);
988     ss.reserve(10000);
989     ss << a;
990     RelayMessage(inv, ss);
991 }
992
993 template<>
994 inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
995 {
996     CRITICAL_BLOCK(cs_mapRelay)
997     {
998         // Expire old relay messages
999         while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
1000         {
1001             mapRelay.erase(vRelayExpiration.front().second);
1002             vRelayExpiration.pop_front();
1003         }
1004
1005         // Save original serialized message so newer versions are preserved
1006         mapRelay[inv] = ss;
1007         vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
1008     }
1009
1010     RelayInventory(inv);
1011 }
1012
1013
1014
1015
1016
1017
1018
1019
1020 //
1021 // Templates for the publish and subscription system.
1022 // The object being published as T& obj needs to have:
1023 //   a set<unsigned int> setSources member
1024 //   specializations of AdvertInsert and AdvertErase
1025 // Currently implemented for CTable and CProduct.
1026 //
1027
1028 template<typename T>
1029 void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1030 {
1031     // Add to sources
1032     obj.setSources.insert(pfrom->addr.ip);
1033
1034     if (!AdvertInsert(obj))
1035         return;
1036
1037     // Relay
1038     CRITICAL_BLOCK(cs_vNodes)
1039         BOOST_FOREACH(CNode* pnode, vNodes)
1040             if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
1041                 pnode->PushMessage("publish", nChannel, nHops, obj);
1042 }
1043
1044 template<typename T>
1045 void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1046 {
1047     uint256 hash = obj.GetHash();
1048
1049     CRITICAL_BLOCK(cs_vNodes)
1050         BOOST_FOREACH(CNode* pnode, vNodes)
1051             if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
1052                 pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
1053
1054     AdvertErase(obj);
1055 }
1056
1057 template<typename T>
1058 void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1059 {
1060     // Remove a source
1061     obj.setSources.erase(pfrom->addr.ip);
1062
1063     // If no longer supported by any sources, cancel it
1064     if (obj.setSources.empty())
1065         AdvertStopPublish(pfrom, nChannel, nHops, obj);
1066 }
1067
1068 #endif