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