Projects : bitcoin : bitcoin_reorg_bounded_space

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 CNode;
17class CBlockIndex;
18extern int nBestHeight;
19extern int nConnectTimeout;
20
21
22
23inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
24inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
25
26bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout);
27bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, int portDefault = 0, bool fAllowPort = false);
28bool Lookup(const char *pszName, CAddress& addr, int nServices, int portDefault = 0, bool fAllowPort = false);
29bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
30void AddressCurrentlyConnected(const CAddress& addr);
31CNode* FindNode(unsigned int ip);
32CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
33void MapPort(bool fMapPort);
34bool BindListenPort(std::string& strError=REF(std::string()));
35void StartNode(void* parg);
36bool StopNode();
37
38enum
39{
40 MSG_TX = 1,
41 MSG_BLOCK,
42};
43
44extern bool fClient;
45extern bool fAllowDNS;
46extern uint64 nLocalServices;
47extern CAddress addrLocalHost;
48extern uint64 nLocalHostNonce;
49extern boost::array<int, 10> vnThreadsRunning;
50
51extern std::vector<CNode*> vNodes;
52extern CCriticalSection cs_vNodes;
53extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
54extern CCriticalSection cs_mapAddresses;
55extern std::map<CInv, CDataStream> mapRelay;
56extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
57extern CCriticalSection cs_mapRelay;
58extern std::map<CInv, int64> mapAlreadyAskedFor;
59
60// Settings
61extern int fUseProxy;
62extern CAddress addrProxy;
63
64// Duplicated from main.h, stupid code-in-header-files.
65extern int nClientVersionNum;
66extern std::string strClientVersionName;
67
68class peer_disconnected_error : public std::runtime_error
69{
70public:
71 explicit peer_disconnected_error() : std::runtime_error("write to disconnected peer") {}
72};
73
74
75
76
77
78class CNode
79{
80public:
81 // socket
82 uint64 nServices;
83 SOCKET hSocket;
84 CDataStream vSend;
85 CDataStream vRecv;
86 CCriticalSection cs_vSend;
87 CCriticalSection cs_vRecv;
88 int64 nLastSend;
89 int64 nLastRecv;
90 int64 nLastSendEmpty;
91 int64 nTimeConnected;
92 CAddress addr;
93 int nVersion;
94 std::string strSubVer;
95 bool fClient;
96 bool fInbound;
97 bool fNetworkNode;
98 bool fSuccessfullyConnected;
99 bool fDisconnect;
100protected:
101 int nRefCount;
102
103 // Denial-of-service detection/prevention
104 // Key is ip address, value is banned-until-time
105 static std::map<unsigned int, int64> setBanned;
106 static CCriticalSection cs_setBanned;
107 int nMisbehavior;
108
109public:
110 int64 nReleaseTime;
111 uint256 hashContinue;
112 int nStartingHeight;
113
114 // flood relay
115 std::vector<CAddress> vAddrToSend;
116 std::set<CAddress> setAddrKnown;
117 bool fGetAddr;
118 std::set<uint256> setKnown;
119
120 // inventory based relay
121 std::set<CInv> setInventoryKnown;
122 std::vector<CInv> vInventoryToSend;
123 CCriticalSection cs_inventory;
124 std::multimap<int64, CInv> mapAskFor;
125
126 CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
127 {
128 nServices = 0;
129 hSocket = hSocketIn;
130 // Version 0.2 obsoletes 20 Feb 2012
131 vSend.SetVersion(209);
132 vRecv.SetVersion(209);
133 nLastSend = 0;
134 nLastRecv = 0;
135 nLastSendEmpty = GetTime();
136 nTimeConnected = GetTime();
137 addr = addrIn;
138 nVersion = 0;
139 strSubVer = "";
140 fClient = false; // set by version message
141 fInbound = fInboundIn;
142 fNetworkNode = false;
143 fSuccessfullyConnected = false;
144 fDisconnect = false;
145 nRefCount = 0;
146 nReleaseTime = 0;
147 hashContinue = 0;
148 nStartingHeight = -1;
149 fGetAddr = false;
150 nMisbehavior = 0;
151
152 // Be shy and don't send version until we hear
153 if (!fInbound)
154 {
155 try
156 {
157 PushVersion();
158 }
159 catch (peer_disconnected_error& e)
160 {
161 // safe to ignore for this single message, and unclear that callers are prepared to handle
162 }
163 }
164 }
165
166 ~CNode()
167 {
168 if (hSocket != INVALID_SOCKET)
169 {
170 closesocket(hSocket);
171 hSocket = INVALID_SOCKET;
172 }
173 }
174
175private:
176 CNode(const CNode&);
177 void operator=(const CNode&);
178public:
179
180
181 int GetRefCount()
182 {
183 return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
184 }
185
186 CNode* AddRef(int64 nTimeout=0)
187 {
188 if (nTimeout != 0)
189 nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
190 else
191 nRefCount++;
192 return this;
193 }
194
195 void Release()
196 {
197 nRefCount--;
198 }
199
200
201
202 void AddAddressKnown(const CAddress& addr)
203 {
204 setAddrKnown.insert(addr);
205 }
206
207 void PushAddress(const CAddress& addr)
208 {
209 // Known checking here is only to save space from duplicates.
210 // SendMessages will filter it again for knowns that were added
211 // after addresses were pushed.
212 if (addr.IsValid() && !setAddrKnown.count(addr))
213 vAddrToSend.push_back(addr);
214 }
215
216
217 void AddInventoryKnown(const CInv& inv)
218 {
219 CRITICAL_BLOCK(cs_inventory)
220 setInventoryKnown.insert(inv);
221 }
222
223 void PushInventory(const CInv& inv)
224 {
225 CRITICAL_BLOCK(cs_inventory)
226 if (!setInventoryKnown.count(inv))
227 vInventoryToSend.push_back(inv);
228 }
229
230 void AskFor(const CInv& inv)
231 {
232 // We're using mapAskFor as a priority queue,
233 // the key is the earliest time the request can be sent
234 int64& nRequestTime = mapAlreadyAskedFor[inv];
235 printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
236
237 // Make sure not to reuse time indexes to keep things in the same order
238 int64 nNow = (GetTime() - 1) * 1000000;
239 static int64 nLastTime;
240 ++nLastTime;
241 nNow = std::max(nNow, nLastTime);
242 nLastTime = nNow;
243
244 // Each retry is 2 minutes after the last
245 nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
246 mapAskFor.insert(std::make_pair(nRequestTime, inv));
247 }
248
249 // Construct a compatible output stream for passing to PushMessage
250 CDataStream SendingStream()
251 {
252 return CDataStream(SER_NETWORK, vSend.GetVersion());
253 }
254
255 void PushVersion()
256 {
257 /// when NTP implemented, change to just nTime = GetAdjustedTime()
258 int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
259 CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
260 CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress("0.0.0.0") : addrLocalHost);
261 RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
262 PushMessage("version", SendingStream()
263 << nClientVersionNum
264 << nLocalServices
265 << nTime
266 << addrYou
267 << addrMe
268 << nLocalHostNonce
269 << FormatSubVersion(strClientVersionName, nClientVersionNum)
270 << nBestHeight);
271 }
272
273 void PushMessage(const char* pszCommand)
274 {
275 PushMessage(pszCommand, SendingStream());
276 }
277
278 void PushMessage(const char* pszCommand, const CDataStream& payload)
279 {
280 if (fDebug)
281 printf("send %s %s (%d B)\n", addr.ToString().c_str(), pszCommand, payload.size());
282 if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
283 {
284 printf("dropmessages DROPPING SEND MESSAGE %s %s\n", addr.ToString().c_str(), pszCommand);
285 return;
286 }
287
288 SCOPED_LOCK(cs_vSend);
289 if (fDisconnect)
290 // Keeping this check inside the lock seems preferable as it assures that past this point, the peer was not disconnected due to flood control (though it may still be for other reasons as fDisconnect isn't strictly guarded by cs_vSend).
291 throw peer_disconnected_error();
292
293 unsigned int nHeaderStart = vSend.size();
294 try
295 {
296 CMessageHeader header(pszCommand, payload.size());
297 uint256 hash = Hash(payload.begin(), payload.end());
298 memcpy(&(header.nChecksum), &hash, sizeof header.nChecksum);
299 // If the peer speaks an old protocol version (<209) as indicated by vSend.nVersion, header.nChecksum is excluded from serialization (see CMessageHeader); no need for special handling here as in prior revisions.
300 // The following may temporarily overflow the sending buffer size limit; that's OK because we rectify it before releasing cs_vSend.
301 vSend << header;
302 vSend += payload;
303 }
304 catch (...)
305 {
306 vSend.resize(nHeaderStart);
307 printf("aborted send %s %s\n", addr.ToString().c_str(), pszCommand);
308 throw;
309 }
310
311 if (vSend.size() > SendBufferSize())
312 {
313 printf("socket send flood control disconnect (%d B)\n", vSend.size());
314 vSend.clear();
315 CloseSocketDisconnect();
316 throw peer_disconnected_error();
317 }
318 }
319
320 void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
321 void CloseSocketDisconnect();
322
323
324 // Denial-of-service detection/prevention
325 // The idea is to detect peers that are behaving
326 // badly and disconnect/ban them, but do it in a
327 // one-coding-mistake-won't-shatter-the-entire-network
328 // way.
329 // IMPORTANT: There should be nothing I can give a
330 // node that it will forward on that will make that
331 // node's peers drop it. If there is, an attacker
332 // can isolate a node and/or try to split the network.
333 // Dropping a node for sending stuff that is invalid
334 // now but might be valid in a later version is also
335 // dangerous, because it can cause a network split
336 // between nodes running old code and nodes running
337 // new code.
338 static void ClearBanned(); // needed for unit testing
339 static bool IsBanned(unsigned int ip);
340 bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
341};
342
343
344
345
346
347
348
349
350
351
352inline void RelayInventory(const CInv& inv)
353{
354 // Put on lists to offer to the other nodes
355 SCOPED_LOCK(cs_vNodes);
356 BOOST_FOREACH(CNode* pnode, vNodes)
357 pnode->PushInventory(inv);
358}
359
360template<typename T>
361void RelayMessage(const CInv& inv, const T& a)
362{
363 CDataStream ss(SER_NETWORK);
364 ss.reserve(10000);
365 ss << a;
366 RelayMessage(inv, ss);
367}
368
369template<>
370inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
371{
372 CRITICAL_BLOCK(cs_mapRelay)
373 {
374 // Expire old relay messages
375 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
376 {
377 mapRelay.erase(vRelayExpiration.front().second);
378 vRelayExpiration.pop_front();
379 }
380
381 // Save original serialized message so newer versions are preserved
382 mapRelay[inv] = ss;
383 vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
384 }
385
386 RelayInventory(inv);
387}
388
389#endif