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