Projects : bitcoin : bitcoin_getblockindex_etc

bitcoin/src/net.h

Dir - Raw

1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2012 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#include "protocol.h"
14
15class CAddrDB;
16class CRequestTracker;
17class CNode;
18class CBlockIndex;
19extern int nBestHeight;
20extern int nConnectTimeout;
21
22
23
24inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
25inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
26static const unsigned int PUBLISH_HOPS = 5;
27
28bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout);
29bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, int portDefault = 0, bool fAllowPort = false);
30bool Lookup(const char *pszName, CAddress& addr, int nServices, int portDefault = 0, bool fAllowPort = false);
31bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
32void AddressCurrentlyConnected(const CAddress& addr);
33CNode* FindNode(unsigned int ip);
34CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
35void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
36bool AnySubscribed(unsigned int nChannel);
37void MapPort(bool fMapPort);
38bool BindListenPort(std::string& strError=REF(std::string()));
39void StartNode(void* parg);
40bool StopNode();
41
42enum
43{
44 MSG_TX = 1,
45 MSG_BLOCK,
46};
47
48class CRequestTracker
49{
50public:
51 void (*fn)(void*, CDataStream&);
52 void* param1;
53
54 explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
55 {
56 fn = fnIn;
57 param1 = param1In;
58 }
59
60 bool IsNull()
61 {
62 return fn == NULL;
63 }
64};
65
66
67
68
69
70extern bool fClient;
71extern bool fAllowDNS;
72extern uint64 nLocalServices;
73extern CAddress addrLocalHost;
74extern uint64 nLocalHostNonce;
75extern boost::array<int, 10> vnThreadsRunning;
76
77extern std::vector<CNode*> vNodes;
78extern CCriticalSection cs_vNodes;
79extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
80extern CCriticalSection cs_mapAddresses;
81extern std::map<CInv, CDataStream> mapRelay;
82extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
83extern CCriticalSection cs_mapRelay;
84extern std::map<CInv, int64> mapAlreadyAskedFor;
85
86// Settings
87extern int fUseProxy;
88extern CAddress addrProxy;
89
90
91
92
93
94
95class CNode
96{
97public:
98 // socket
99 uint64 nServices;
100 SOCKET hSocket;
101 CDataStream vSend;
102 CDataStream vRecv;
103 CCriticalSection cs_vSend;
104 CCriticalSection cs_vRecv;
105 int64 nLastSend;
106 int64 nLastRecv;
107 int64 nLastSendEmpty;
108 int64 nTimeConnected;
109 unsigned int nHeaderStart;
110 unsigned int nMessageStart;
111 CAddress addr;
112 int nVersion;
113 std::string strSubVer;
114 bool fClient;
115 bool fInbound;
116 bool fNetworkNode;
117 bool fSuccessfullyConnected;
118 bool fDisconnect;
119protected:
120 int nRefCount;
121
122 // Denial-of-service detection/prevention
123 // Key is ip address, value is banned-until-time
124 static std::map<unsigned int, int64> setBanned;
125 static CCriticalSection cs_setBanned;
126 int nMisbehavior;
127
128public:
129 int64 nReleaseTime;
130 std::map<uint256, CRequestTracker> mapRequests;
131 CCriticalSection cs_mapRequests;
132 uint256 hashContinue;
133 int nStartingHeight;
134
135 // flood relay
136 std::vector<CAddress> vAddrToSend;
137 std::set<CAddress> setAddrKnown;
138 bool fGetAddr;
139 std::set<uint256> setKnown;
140
141 // inventory based relay
142 std::set<CInv> setInventoryKnown;
143 std::vector<CInv> vInventoryToSend;
144 CCriticalSection cs_inventory;
145 std::multimap<int64, CInv> mapAskFor;
146
147 // publish and subscription
148 std::vector<char> vfSubscribe;
149
150 CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
151 {
152 nServices = 0;
153 hSocket = hSocketIn;
154 vSend.SetType(SER_NETWORK);
155 vSend.SetVersion(0);
156 vRecv.SetType(SER_NETWORK);
157 vRecv.SetVersion(0);
158 // Version 0.2 obsoletes 20 Feb 2012
159 if (GetTime() > 1329696000)
160 {
161 vSend.SetVersion(209);
162 vRecv.SetVersion(209);
163 }
164 nLastSend = 0;
165 nLastRecv = 0;
166 nLastSendEmpty = GetTime();
167 nTimeConnected = GetTime();
168 nHeaderStart = -1;
169 nMessageStart = -1;
170 addr = addrIn;
171 nVersion = 0;
172 strSubVer = "";
173 fClient = false; // set by version message
174 fInbound = fInboundIn;
175 fNetworkNode = false;
176 fSuccessfullyConnected = false;
177 fDisconnect = false;
178 nRefCount = 0;
179 nReleaseTime = 0;
180 hashContinue = 0;
181 nStartingHeight = -1;
182 fGetAddr = false;
183 vfSubscribe.assign(256, false);
184 nMisbehavior = 0;
185
186 // Be shy and don't send version until we hear
187 if (!fInbound)
188 PushVersion();
189 }
190
191 ~CNode()
192 {
193 if (hSocket != INVALID_SOCKET)
194 {
195 closesocket(hSocket);
196 hSocket = INVALID_SOCKET;
197 }
198 }
199
200private:
201 CNode(const CNode&);
202 void operator=(const CNode&);
203public:
204
205
206 int GetRefCount()
207 {
208 return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
209 }
210
211 CNode* AddRef(int64 nTimeout=0)
212 {
213 if (nTimeout != 0)
214 nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
215 else
216 nRefCount++;
217 return this;
218 }
219
220 void Release()
221 {
222 nRefCount--;
223 }
224
225
226
227 void AddAddressKnown(const CAddress& addr)
228 {
229 setAddrKnown.insert(addr);
230 }
231
232 void PushAddress(const CAddress& addr)
233 {
234 // Known checking here is only to save space from duplicates.
235 // SendMessages will filter it again for knowns that were added
236 // after addresses were pushed.
237 if (addr.IsValid() && !setAddrKnown.count(addr))
238 vAddrToSend.push_back(addr);
239 }
240
241
242 void AddInventoryKnown(const CInv& inv)
243 {
244 CRITICAL_BLOCK(cs_inventory)
245 setInventoryKnown.insert(inv);
246 }
247
248 void PushInventory(const CInv& inv)
249 {
250 CRITICAL_BLOCK(cs_inventory)
251 if (!setInventoryKnown.count(inv))
252 vInventoryToSend.push_back(inv);
253 }
254
255 void AskFor(const CInv& inv)
256 {
257 // We're using mapAskFor as a priority queue,
258 // the key is the earliest time the request can be sent
259 int64& nRequestTime = mapAlreadyAskedFor[inv];
260 printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
261
262 // Make sure not to reuse time indexes to keep things in the same order
263 int64 nNow = (GetTime() - 1) * 1000000;
264 static int64 nLastTime;
265 ++nLastTime;
266 nNow = std::max(nNow, nLastTime);
267 nLastTime = nNow;
268
269 // Each retry is 2 minutes after the last
270 nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
271 mapAskFor.insert(std::make_pair(nRequestTime, inv));
272 }
273
274
275
276 void BeginMessage(const char* pszCommand)
277 {
278 ENTER_CRITICAL_SECTION(cs_vSend);
279 if (nHeaderStart != -1)
280 AbortMessage();
281 nHeaderStart = vSend.size();
282 vSend << CMessageHeader(pszCommand, 0);
283 nMessageStart = vSend.size();
284 if (fDebug) {
285 printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
286 printf("sending: %s ", pszCommand);
287 }
288 }
289
290 void AbortMessage()
291 {
292 if (nHeaderStart == -1)
293 return;
294 vSend.resize(nHeaderStart);
295 nHeaderStart = -1;
296 nMessageStart = -1;
297 LEAVE_CRITICAL_SECTION(cs_vSend);
298
299 if (fDebug)
300 printf("(aborted)\n");
301 }
302
303 void EndMessage()
304 {
305 if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
306 {
307 printf("dropmessages DROPPING SEND MESSAGE\n");
308 AbortMessage();
309 return;
310 }
311
312 if (nHeaderStart == -1)
313 return;
314
315 // Set the size
316 unsigned int nSize = vSend.size() - nMessageStart;
317 memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
318
319 // Set the checksum
320 if (vSend.GetVersion() >= 209)
321 {
322 uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
323 unsigned int nChecksum = 0;
324 memcpy(&nChecksum, &hash, sizeof(nChecksum));
325 assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
326 memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
327 }
328
329 if (fDebug) {
330 printf("(%d bytes)\n", nSize);
331 }
332
333 nHeaderStart = -1;
334 nMessageStart = -1;
335 LEAVE_CRITICAL_SECTION(cs_vSend);
336 }
337
338 void EndMessageAbortIfEmpty()
339 {
340 if (nHeaderStart == -1)
341 return;
342 int nSize = vSend.size() - nMessageStart;
343 if (nSize > 0)
344 EndMessage();
345 else
346 AbortMessage();
347 }
348
349
350
351 void PushVersion()
352 {
353 /// when NTP implemented, change to just nTime = GetAdjustedTime()
354 int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
355 CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
356 CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress("0.0.0.0") : addrLocalHost);
357 RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
358 PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
359 nLocalHostNonce, FormatSubVersion(CLIENT_NAME, VERSION), nBestHeight);
360 }
361
362
363
364
365 void PushMessage(const char* pszCommand)
366 {
367 try
368 {
369 BeginMessage(pszCommand);
370 EndMessage();
371 }
372 catch (...)
373 {
374 AbortMessage();
375 throw;
376 }
377 }
378
379 template<typename T1>
380 void PushMessage(const char* pszCommand, const T1& a1)
381 {
382 try
383 {
384 BeginMessage(pszCommand);
385 vSend << a1;
386 EndMessage();
387 }
388 catch (...)
389 {
390 AbortMessage();
391 throw;
392 }
393 }
394
395 template<typename T1, typename T2>
396 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
397 {
398 try
399 {
400 BeginMessage(pszCommand);
401 vSend << a1 << a2;
402 EndMessage();
403 }
404 catch (...)
405 {
406 AbortMessage();
407 throw;
408 }
409 }
410
411 template<typename T1, typename T2, typename T3>
412 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
413 {
414 try
415 {
416 BeginMessage(pszCommand);
417 vSend << a1 << a2 << a3;
418 EndMessage();
419 }
420 catch (...)
421 {
422 AbortMessage();
423 throw;
424 }
425 }
426
427 template<typename T1, typename T2, typename T3, typename T4>
428 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
429 {
430 try
431 {
432 BeginMessage(pszCommand);
433 vSend << a1 << a2 << a3 << a4;
434 EndMessage();
435 }
436 catch (...)
437 {
438 AbortMessage();
439 throw;
440 }
441 }
442
443 template<typename T1, typename T2, typename T3, typename T4, typename T5>
444 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
445 {
446 try
447 {
448 BeginMessage(pszCommand);
449 vSend << a1 << a2 << a3 << a4 << a5;
450 EndMessage();
451 }
452 catch (...)
453 {
454 AbortMessage();
455 throw;
456 }
457 }
458
459 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
460 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
461 {
462 try
463 {
464 BeginMessage(pszCommand);
465 vSend << a1 << a2 << a3 << a4 << a5 << a6;
466 EndMessage();
467 }
468 catch (...)
469 {
470 AbortMessage();
471 throw;
472 }
473 }
474
475 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
476 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)
477 {
478 try
479 {
480 BeginMessage(pszCommand);
481 vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
482 EndMessage();
483 }
484 catch (...)
485 {
486 AbortMessage();
487 throw;
488 }
489 }
490
491 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
492 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)
493 {
494 try
495 {
496 BeginMessage(pszCommand);
497 vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
498 EndMessage();
499 }
500 catch (...)
501 {
502 AbortMessage();
503 throw;
504 }
505 }
506
507 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
508 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)
509 {
510 try
511 {
512 BeginMessage(pszCommand);
513 vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
514 EndMessage();
515 }
516 catch (...)
517 {
518 AbortMessage();
519 throw;
520 }
521 }
522
523
524 void PushRequest(const char* pszCommand,
525 void (*fn)(void*, CDataStream&), void* param1)
526 {
527 uint256 hashReply;
528 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
529
530 CRITICAL_BLOCK(cs_mapRequests)
531 mapRequests[hashReply] = CRequestTracker(fn, param1);
532
533 PushMessage(pszCommand, hashReply);
534 }
535
536 template<typename T1>
537 void PushRequest(const char* pszCommand, const T1& a1,
538 void (*fn)(void*, CDataStream&), void* param1)
539 {
540 uint256 hashReply;
541 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
542
543 CRITICAL_BLOCK(cs_mapRequests)
544 mapRequests[hashReply] = CRequestTracker(fn, param1);
545
546 PushMessage(pszCommand, hashReply, a1);
547 }
548
549 template<typename T1, typename T2>
550 void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
551 void (*fn)(void*, CDataStream&), void* param1)
552 {
553 uint256 hashReply;
554 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
555
556 CRITICAL_BLOCK(cs_mapRequests)
557 mapRequests[hashReply] = CRequestTracker(fn, param1);
558
559 PushMessage(pszCommand, hashReply, a1, a2);
560 }
561
562
563
564 void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
565 bool IsSubscribed(unsigned int nChannel);
566 void Subscribe(unsigned int nChannel, unsigned int nHops=0);
567 void CancelSubscribe(unsigned int nChannel);
568 void CloseSocketDisconnect();
569 void Cleanup();
570
571
572 // Denial-of-service detection/prevention
573 // The idea is to detect peers that are behaving
574 // badly and disconnect/ban them, but do it in a
575 // one-coding-mistake-won't-shatter-the-entire-network
576 // way.
577 // IMPORTANT: There should be nothing I can give a
578 // node that it will forward on that will make that
579 // node's peers drop it. If there is, an attacker
580 // can isolate a node and/or try to split the network.
581 // Dropping a node for sending stuff that is invalid
582 // now but might be valid in a later version is also
583 // dangerous, because it can cause a network split
584 // between nodes running old code and nodes running
585 // new code.
586 static void ClearBanned(); // needed for unit testing
587 static bool IsBanned(unsigned int ip);
588 bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
589};
590
591
592
593
594
595
596
597
598
599
600inline void RelayInventory(const CInv& inv)
601{
602 // Put on lists to offer to the other nodes
603 CRITICAL_BLOCK(cs_vNodes)
604 BOOST_FOREACH(CNode* pnode, vNodes)
605 pnode->PushInventory(inv);
606}
607
608template<typename T>
609void RelayMessage(const CInv& inv, const T& a)
610{
611 CDataStream ss(SER_NETWORK);
612 ss.reserve(10000);
613 ss << a;
614 RelayMessage(inv, ss);
615}
616
617template<>
618inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
619{
620 CRITICAL_BLOCK(cs_mapRelay)
621 {
622 // Expire old relay messages
623 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
624 {
625 mapRelay.erase(vRelayExpiration.front().second);
626 vRelayExpiration.pop_front();
627 }
628
629 // Save original serialized message so newer versions are preserved
630 mapRelay[inv] = ss;
631 vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
632 }
633
634 RelayInventory(inv);
635}
636
637
638
639
640
641
642
643
644//
645// Templates for the publish and subscription system.
646// The object being published as T& obj needs to have:
647// a set<unsigned int> setSources member
648// specializations of AdvertInsert and AdvertErase
649// Currently implemented for CTable and CProduct.
650//
651
652template<typename T>
653void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
654{
655 // Add to sources
656 obj.setSources.insert(pfrom->addr.ip);
657
658 if (!AdvertInsert(obj))
659 return;
660
661 // Relay
662 CRITICAL_BLOCK(cs_vNodes)
663 BOOST_FOREACH(CNode* pnode, vNodes)
664 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
665 pnode->PushMessage("publish", nChannel, nHops, obj);
666}
667
668template<typename T>
669void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
670{
671 uint256 hash = obj.GetHash();
672
673 CRITICAL_BLOCK(cs_vNodes)
674 BOOST_FOREACH(CNode* pnode, vNodes)
675 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
676 pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
677
678 AdvertErase(obj);
679}
680
681template<typename T>
682void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
683{
684 // Remove a source
685 obj.setSources.erase(pfrom->addr.ip);
686
687 // If no longer supported by any sources, cancel it
688 if (obj.setSources.empty())
689 AdvertStopPublish(pfrom, nChannel, nHops, obj);
690}
691
692#endif