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