]>
Commit | Line | Data |
---|---|---|
0a61b0df | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
57702541 | 2 | // Copyright (c) 2009-2014 The Bitcoin developers |
0a61b0df | 3 | // Distributed under the MIT/X11 software license, see the accompanying |
3a25a2b9 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
51ed9ec9 | 5 | |
223b6f1b WL |
6 | #ifndef BITCOIN_NET_H |
7 | #define BITCOIN_NET_H | |
8 | ||
51ed9ec9 BD |
9 | #include "bloom.h" |
10 | #include "compat.h" | |
11 | #include "hash.h" | |
12 | #include "limitedmap.h" | |
13 | #include "mruset.h" | |
14 | #include "netbase.h" | |
15 | #include "protocol.h" | |
16 | #include "sync.h" | |
17 | #include "uint256.h" | |
18 | #include "util.h" | |
19 | ||
223b6f1b | 20 | #include <deque> |
51ed9ec9 | 21 | #include <stdint.h> |
223b6f1b | 22 | |
6853e627 | 23 | #ifndef WIN32 |
223b6f1b WL |
24 | #include <arpa/inet.h> |
25 | #endif | |
0a61b0df | 26 | |
51ed9ec9 BD |
27 | #include <boost/foreach.hpp> |
28 | #include <boost/signals2/signal.hpp> | |
29 | #include <openssl/rand.h> | |
6e68524e | 30 | |
f1920e86 | 31 | |
51ed9ec9 | 32 | class CAddrMan; |
0a61b0df | 33 | class CBlockIndex; |
51ed9ec9 | 34 | class CNode; |
0a61b0df | 35 | |
51ed9ec9 BD |
36 | namespace boost { |
37 | class thread_group; | |
38 | } | |
0a61b0df | 39 | |
f1920e86 PW |
40 | /** Time between pings automatically sent out for latency probing and keepalive (in seconds). */ |
41 | static const int PING_INTERVAL = 2 * 60; | |
42 | /** Time after which to disconnect, after waiting for a ping response (or inactivity). */ | |
43 | static const int TIMEOUT_INTERVAL = 20 * 60; | |
51ed9ec9 BD |
44 | /** The maximum number of entries in an 'inv' protocol message */ |
45 | static const unsigned int MAX_INV_SZ = 50000; | |
56b07d2d PK |
46 | /** -listen default */ |
47 | static const bool DEFAULT_LISTEN = true; | |
d4e1c612 PK |
48 | /** -upnp default */ |
49 | #ifdef USE_UPNP | |
50 | static const bool DEFAULT_UPNP = USE_UPNP; | |
51 | #else | |
52 | static const bool DEFAULT_UPNP = false; | |
53 | #endif | |
0a61b0df | 54 | |
607dbfde | 55 | inline unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } |
6d6c2afb | 56 | inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } |
0a61b0df | 57 | |
478b01d9 | 58 | void AddOneShot(std::string strDest); |
a3342d09 | 59 | bool RecvLine(SOCKET hSocket, std::string& strLine); |
67a42f92 | 60 | bool GetMyExternalIP(CNetAddr& ipRet); |
67a42f92 PW |
61 | void AddressCurrentlyConnected(const CService& addr); |
62 | CNode* FindNode(const CNetAddr& ip); | |
63 | CNode* FindNode(const CService& ip); | |
5bd6c31b | 64 | CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL); |
b641c9cd | 65 | bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); |
21eb5ada | 66 | void MapPort(bool fUseUPnP); |
5a3cb32e | 67 | unsigned short GetListenPort(); |
5bd6c31b | 68 | bool BindListenPort(const CService &bindAddr, std::string& strError); |
b31499ec | 69 | void StartNode(boost::thread_group& threadGroup); |
0a61b0df | 70 | bool StopNode(); |
b9ff2970 | 71 | void SocketSendData(CNode *pnode); |
0a61b0df | 72 | |
b2864d2f PW |
73 | typedef int NodeId; |
74 | ||
501da250 EL |
75 | // Signals for message handling |
76 | struct CNodeSignals | |
77 | { | |
4c6d41b8 | 78 | boost::signals2::signal<int ()> GetHeight; |
501da250 EL |
79 | boost::signals2::signal<bool (CNode*)> ProcessMessages; |
80 | boost::signals2::signal<bool (CNode*, bool)> SendMessages; | |
b2864d2f PW |
81 | boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode; |
82 | boost::signals2::signal<void (NodeId)> FinalizeNode; | |
501da250 EL |
83 | }; |
84 | ||
b2864d2f | 85 | |
501da250 | 86 | CNodeSignals& GetNodeSignals(); |
663224c2 | 87 | |
663224c2 | 88 | |
39857190 PW |
89 | enum |
90 | { | |
7fa4443f PW |
91 | LOCAL_NONE, // unknown |
92 | LOCAL_IF, // address a local interface listens on | |
8f10a288 | 93 | LOCAL_BIND, // address explicit bound to |
7fa4443f | 94 | LOCAL_UPNP, // address reported by UPnP |
814efd6f | 95 | LOCAL_HTTP, // address reported by whatismyip.com and similar |
7fa4443f | 96 | LOCAL_MANUAL, // address explicitly specified (-externalip=) |
19b6958c PW |
97 | |
98 | LOCAL_MAX | |
39857190 PW |
99 | }; |
100 | ||
457754d2 | 101 | void SetLimited(enum Network net, bool fLimited = true); |
0f1707de | 102 | bool IsLimited(enum Network net); |
457754d2 | 103 | bool IsLimited(const CNetAddr& addr); |
7fa4443f | 104 | bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); |
5a3cb32e | 105 | bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); |
7fa4443f PW |
106 | bool SeenLocal(const CService& addr); |
107 | bool IsLocal(const CService& addr); | |
108 | bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); | |
090e5b40 | 109 | bool IsReachable(const CNetAddr &addr); |
54ce3bad | 110 | void SetReachable(enum Network net, bool fFlag = true); |
39857190 PW |
111 | CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); |
112 | ||
090e5b40 | 113 | |
587f929c | 114 | extern bool fDiscover; |
53a08815 | 115 | extern bool fListen; |
51ed9ec9 BD |
116 | extern uint64_t nLocalServices; |
117 | extern uint64_t nLocalHostNonce; | |
5fee401f | 118 | extern CAddrMan addrman; |
ba29a559 | 119 | extern int nMaxConnections; |
0a61b0df | 120 | |
223b6f1b | 121 | extern std::vector<CNode*> vNodes; |
0a61b0df | 122 | extern CCriticalSection cs_vNodes; |
223b6f1b | 123 | extern std::map<CInv, CDataStream> mapRelay; |
51ed9ec9 | 124 | extern std::deque<std::pair<int64_t, CInv> > vRelayExpiration; |
0a61b0df | 125 | extern CCriticalSection cs_mapRelay; |
51ed9ec9 | 126 | extern limitedmap<CInv, int64_t> mapAlreadyAskedFor; |
0a61b0df | 127 | |
74088e86 MC |
128 | extern std::vector<std::string> vAddedNodes; |
129 | extern CCriticalSection cs_vAddedNodes; | |
130 | ||
b2864d2f PW |
131 | extern NodeId nLastNodeId; |
132 | extern CCriticalSection cs_nLastNodeId; | |
0a61b0df | 133 | |
d387b8ec WL |
134 | struct LocalServiceInfo { |
135 | int nScore; | |
136 | int nPort; | |
137 | }; | |
138 | ||
139 | extern CCriticalSection cs_mapLocalHost; | |
2871889e | 140 | extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost; |
0a61b0df | 141 | |
1006f070 JG |
142 | class CNodeStats |
143 | { | |
144 | public: | |
b2864d2f | 145 | NodeId nodeid; |
51ed9ec9 BD |
146 | uint64_t nServices; |
147 | int64_t nLastSend; | |
148 | int64_t nLastRecv; | |
149 | int64_t nTimeConnected; | |
1006f070 JG |
150 | std::string addrName; |
151 | int nVersion; | |
a946aa8d | 152 | std::string cleanSubVer; |
1006f070 | 153 | bool fInbound; |
1006f070 | 154 | int nStartingHeight; |
51ed9ec9 BD |
155 | uint64_t nSendBytes; |
156 | uint64_t nRecvBytes; | |
86648a8d | 157 | bool fSyncNode; |
971bb3e9 JL |
158 | double dPingTime; |
159 | double dPingWait; | |
547c61f8 | 160 | std::string addrLocal; |
1006f070 JG |
161 | }; |
162 | ||
163 | ||
164 | ||
0a61b0df | 165 | |
607dbfde JG |
166 | class CNetMessage { |
167 | public: | |
168 | bool in_data; // parsing header (false) or data (true) | |
169 | ||
170 | CDataStream hdrbuf; // partially received header | |
171 | CMessageHeader hdr; // complete header | |
172 | unsigned int nHdrPos; | |
173 | ||
174 | CDataStream vRecv; // received message data | |
175 | unsigned int nDataPos; | |
176 | ||
177 | CNetMessage(int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), vRecv(nTypeIn, nVersionIn) { | |
178 | hdrbuf.resize(24); | |
179 | in_data = false; | |
180 | nHdrPos = 0; | |
181 | nDataPos = 0; | |
182 | } | |
183 | ||
184 | bool complete() const | |
185 | { | |
186 | if (!in_data) | |
187 | return false; | |
188 | return (hdr.nMessageSize == nDataPos); | |
189 | } | |
190 | ||
191 | void SetVersion(int nVersionIn) | |
192 | { | |
193 | hdrbuf.SetVersion(nVersionIn); | |
194 | vRecv.SetVersion(nVersionIn); | |
195 | } | |
196 | ||
197 | int readHeader(const char *pch, unsigned int nBytes); | |
198 | int readData(const char *pch, unsigned int nBytes); | |
199 | }; | |
200 | ||
201 | ||
202 | ||
203 | ||
0a61b0df | 204 | |
6b8de05d | 205 | /** Information about a peer */ |
0a61b0df | 206 | class CNode |
207 | { | |
208 | public: | |
209 | // socket | |
51ed9ec9 | 210 | uint64_t nServices; |
0a61b0df | 211 | SOCKET hSocket; |
41b052ad PW |
212 | CDataStream ssSend; |
213 | size_t nSendSize; // total size of all vSendMsg entries | |
214 | size_t nSendOffset; // offset inside the first vSendMsg already sent | |
51ed9ec9 | 215 | uint64_t nSendBytes; |
41b052ad | 216 | std::deque<CSerializeData> vSendMsg; |
0a61b0df | 217 | CCriticalSection cs_vSend; |
607dbfde | 218 | |
c7f039b6 | 219 | std::deque<CInv> vRecvGetData; |
967f2459 | 220 | std::deque<CNetMessage> vRecvMsg; |
607dbfde | 221 | CCriticalSection cs_vRecvMsg; |
51ed9ec9 | 222 | uint64_t nRecvBytes; |
607dbfde JG |
223 | int nRecvVersion; |
224 | ||
51ed9ec9 BD |
225 | int64_t nLastSend; |
226 | int64_t nLastRecv; | |
51ed9ec9 | 227 | int64_t nTimeConnected; |
0a61b0df | 228 | CAddress addr; |
9bab521d | 229 | std::string addrName; |
7fa4443f | 230 | CService addrLocal; |
0a61b0df | 231 | int nVersion; |
c037531d | 232 | // strSubVer is whatever byte array we read from the wire. However, this field is intended |
a946aa8d MH |
233 | // to be printed out, displayed to humans in various forms and so on. So we sanitize it and |
234 | // store the sanitized version in cleanSubVer. The original should be used when dealing with | |
235 | // the network or wire types and the cleaned string used when displayed or logged. | |
236 | std::string strSubVer, cleanSubVer; | |
478b01d9 | 237 | bool fOneShot; |
0a61b0df | 238 | bool fClient; |
239 | bool fInbound; | |
240 | bool fNetworkNode; | |
241 | bool fSuccessfullyConnected; | |
242 | bool fDisconnect; | |
4c8fc1a5 MC |
243 | // We use fRelayTxes for two purposes - |
244 | // a) it allows us to not relay tx invs before receiving the peer's version message | |
245 | // b) the peer may tell us in their version message that we should not relay tx invs | |
246 | // until they have initialized their bloom filter. | |
247 | bool fRelayTxes; | |
c59abe25 | 248 | CSemaphoreGrant grantOutbound; |
422d1225 MC |
249 | CCriticalSection cs_filter; |
250 | CBloomFilter* pfilter; | |
0a61b0df | 251 | int nRefCount; |
b2864d2f | 252 | NodeId id; |
cedaa714 | 253 | protected: |
15f3ad4d GA |
254 | |
255 | // Denial-of-service detection/prevention | |
814efd6f | 256 | // Key is IP address, value is banned-until-time |
51ed9ec9 | 257 | static std::map<CNetAddr, int64_t> setBanned; |
15f3ad4d | 258 | static CCriticalSection cs_setBanned; |
15f3ad4d | 259 | |
9038b18f GA |
260 | // Basic fuzz-testing |
261 | void Fuzz(int nChance); // modifies ssSend | |
262 | ||
0a61b0df | 263 | public: |
0a61b0df | 264 | uint256 hashContinue; |
265 | CBlockIndex* pindexLastGetBlocksBegin; | |
266 | uint256 hashLastGetBlocksEnd; | |
267 | int nStartingHeight; | |
6ed71b5e | 268 | bool fStartSync; |
0a61b0df | 269 | |
270 | // flood relay | |
223b6f1b | 271 | std::vector<CAddress> vAddrToSend; |
5823449e | 272 | mruset<CAddress> setAddrKnown; |
0a61b0df | 273 | bool fGetAddr; |
223b6f1b | 274 | std::set<uint256> setKnown; |
0a61b0df | 275 | |
276 | // inventory based relay | |
c4341fa6 | 277 | mruset<CInv> setInventoryKnown; |
223b6f1b | 278 | std::vector<CInv> vInventoryToSend; |
0a61b0df | 279 | CCriticalSection cs_inventory; |
51ed9ec9 | 280 | std::multimap<int64_t, CInv> mapAskFor; |
0a61b0df | 281 | |
f1920e86 PW |
282 | // Ping time measurement: |
283 | // The pong reply we're expecting, or 0 if no pong expected. | |
51ed9ec9 | 284 | uint64_t nPingNonceSent; |
f1920e86 | 285 | // Time (in usec) the last ping was sent, or 0 if no ping was ever sent. |
51ed9ec9 | 286 | int64_t nPingUsecStart; |
f1920e86 | 287 | // Last measured round-trip time. |
51ed9ec9 | 288 | int64_t nPingUsecTime; |
f1920e86 | 289 | // Whether a ping is requested. |
971bb3e9 | 290 | bool fPingQueued; |
c037531d | 291 | |
5823449e | 292 | CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000) |
0a61b0df | 293 | { |
294 | nServices = 0; | |
295 | hSocket = hSocketIn; | |
1ce41892 | 296 | nRecvVersion = INIT_PROTO_VERSION; |
0a61b0df | 297 | nLastSend = 0; |
298 | nLastRecv = 0; | |
86648a8d PW |
299 | nSendBytes = 0; |
300 | nRecvBytes = 0; | |
0a61b0df | 301 | nTimeConnected = GetTime(); |
0a61b0df | 302 | addr = addrIn; |
9bab521d | 303 | addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; |
0a61b0df | 304 | nVersion = 0; |
305 | strSubVer = ""; | |
478b01d9 | 306 | fOneShot = false; |
0a61b0df | 307 | fClient = false; // set by version message |
308 | fInbound = fInboundIn; | |
309 | fNetworkNode = false; | |
310 | fSuccessfullyConnected = false; | |
311 | fDisconnect = false; | |
312 | nRefCount = 0; | |
41b052ad PW |
313 | nSendSize = 0; |
314 | nSendOffset = 0; | |
0a61b0df | 315 | hashContinue = 0; |
316 | pindexLastGetBlocksBegin = 0; | |
317 | hashLastGetBlocksEnd = 0; | |
318 | nStartingHeight = -1; | |
6ed71b5e | 319 | fStartSync = false; |
0a61b0df | 320 | fGetAddr = false; |
4c8fc1a5 | 321 | fRelayTxes = false; |
c4341fa6 | 322 | setInventoryKnown.max_size(SendBufferSize() / 1000); |
37c6389c | 323 | pfilter = new CBloomFilter(); |
971bb3e9 JL |
324 | nPingNonceSent = 0; |
325 | nPingUsecStart = 0; | |
326 | nPingUsecTime = 0; | |
327 | fPingQueued = false; | |
0a61b0df | 328 | |
b2864d2f PW |
329 | { |
330 | LOCK(cs_nLastNodeId); | |
331 | id = nLastNodeId++; | |
332 | } | |
333 | ||
cbc920d4 | 334 | // Be shy and don't send version until we hear |
788064dd | 335 | if (hSocket != INVALID_SOCKET && !fInbound) |
cbc920d4 | 336 | PushVersion(); |
b2864d2f PW |
337 | |
338 | GetNodeSignals().InitializeNode(GetId(), this); | |
0a61b0df | 339 | } |
340 | ||
341 | ~CNode() | |
342 | { | |
343 | if (hSocket != INVALID_SOCKET) | |
344 | { | |
345 | closesocket(hSocket); | |
346 | hSocket = INVALID_SOCKET; | |
347 | } | |
422d1225 MC |
348 | if (pfilter) |
349 | delete pfilter; | |
b2864d2f | 350 | GetNodeSignals().FinalizeNode(GetId()); |
0a61b0df | 351 | } |
352 | ||
353 | private: | |
ce14345a SE |
354 | // Network usage totals |
355 | static CCriticalSection cs_totalBytesRecv; | |
356 | static CCriticalSection cs_totalBytesSent; | |
51ed9ec9 BD |
357 | static uint64_t nTotalBytesRecv; |
358 | static uint64_t nTotalBytesSent; | |
ce14345a | 359 | |
0a61b0df | 360 | CNode(const CNode&); |
361 | void operator=(const CNode&); | |
ce14345a | 362 | |
0a61b0df | 363 | public: |
364 | ||
b2864d2f PW |
365 | NodeId GetId() const { |
366 | return id; | |
367 | } | |
0a61b0df | 368 | |
369 | int GetRefCount() | |
370 | { | |
cedaa714 PW |
371 | assert(nRefCount >= 0); |
372 | return nRefCount; | |
0a61b0df | 373 | } |
374 | ||
607dbfde JG |
375 | // requires LOCK(cs_vRecvMsg) |
376 | unsigned int GetTotalRecvSize() | |
377 | { | |
378 | unsigned int total = 0; | |
96b9603c | 379 | BOOST_FOREACH(const CNetMessage &msg, vRecvMsg) |
967f2459 | 380 | total += msg.vRecv.size() + 24; |
607dbfde JG |
381 | return total; |
382 | } | |
383 | ||
384 | // requires LOCK(cs_vRecvMsg) | |
385 | bool ReceiveMsgBytes(const char *pch, unsigned int nBytes); | |
386 | ||
387 | // requires LOCK(cs_vRecvMsg) | |
388 | void SetRecvVersion(int nVersionIn) | |
389 | { | |
390 | nRecvVersion = nVersionIn; | |
967f2459 PW |
391 | BOOST_FOREACH(CNetMessage &msg, vRecvMsg) |
392 | msg.SetVersion(nVersionIn); | |
607dbfde JG |
393 | } |
394 | ||
cedaa714 | 395 | CNode* AddRef() |
0a61b0df | 396 | { |
cedaa714 | 397 | nRefCount++; |
0a61b0df | 398 | return this; |
399 | } | |
400 | ||
401 | void Release() | |
402 | { | |
403 | nRefCount--; | |
404 | } | |
405 | ||
406 | ||
407 | ||
408 | void AddAddressKnown(const CAddress& addr) | |
409 | { | |
410 | setAddrKnown.insert(addr); | |
411 | } | |
412 | ||
413 | void PushAddress(const CAddress& addr) | |
414 | { | |
415 | // Known checking here is only to save space from duplicates. | |
416 | // SendMessages will filter it again for knowns that were added | |
417 | // after addresses were pushed. | |
418 | if (addr.IsValid() && !setAddrKnown.count(addr)) | |
419 | vAddrToSend.push_back(addr); | |
420 | } | |
421 | ||
422 | ||
423 | void AddInventoryKnown(const CInv& inv) | |
424 | { | |
f8dcd5ca PW |
425 | { |
426 | LOCK(cs_inventory); | |
0a61b0df | 427 | setInventoryKnown.insert(inv); |
f8dcd5ca | 428 | } |
0a61b0df | 429 | } |
430 | ||
431 | void PushInventory(const CInv& inv) | |
432 | { | |
f8dcd5ca PW |
433 | { |
434 | LOCK(cs_inventory); | |
0a61b0df | 435 | if (!setInventoryKnown.count(inv)) |
436 | vInventoryToSend.push_back(inv); | |
f8dcd5ca | 437 | } |
0a61b0df | 438 | } |
439 | ||
440 | void AskFor(const CInv& inv) | |
441 | { | |
442 | // We're using mapAskFor as a priority queue, | |
443 | // the key is the earliest time the request can be sent | |
51ed9ec9 BD |
444 | int64_t nRequestTime; |
445 | limitedmap<CInv, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv); | |
b5afda67 MC |
446 | if (it != mapAlreadyAskedFor.end()) |
447 | nRequestTime = it->second; | |
448 | else | |
449 | nRequestTime = 0; | |
79d06dc6 | 450 | LogPrint("net", "askfor %s %d (%s)\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str()); |
0a61b0df | 451 | |
452 | // Make sure not to reuse time indexes to keep things in the same order | |
f59d8f0b | 453 | int64_t nNow = GetTimeMicros() - 1000000; |
51ed9ec9 | 454 | static int64_t nLastTime; |
a1de57a0 GA |
455 | ++nLastTime; |
456 | nNow = std::max(nNow, nLastTime); | |
457 | nLastTime = nNow; | |
0a61b0df | 458 | |
459 | // Each retry is 2 minutes after the last | |
223b6f1b | 460 | nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); |
b5afda67 MC |
461 | if (it != mapAlreadyAskedFor.end()) |
462 | mapAlreadyAskedFor.update(it, nRequestTime); | |
463 | else | |
464 | mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime)); | |
223b6f1b | 465 | mapAskFor.insert(std::make_pair(nRequestTime, inv)); |
0a61b0df | 466 | } |
467 | ||
468 | ||
469 | ||
25511af4 AK |
470 | // TODO: Document the postcondition of this function. Is cs_vSend locked? |
471 | void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) | |
0a61b0df | 472 | { |
88bc5f94 | 473 | ENTER_CRITICAL_SECTION(cs_vSend); |
41b052ad PW |
474 | assert(ssSend.size() == 0); |
475 | ssSend << CMessageHeader(pszCommand, 0); | |
881a85a2 | 476 | LogPrint("net", "sending: %s ", pszCommand); |
0a61b0df | 477 | } |
478 | ||
25511af4 AK |
479 | // TODO: Document the precondition of this function. Is cs_vSend locked? |
480 | void AbortMessage() UNLOCK_FUNCTION(cs_vSend) | |
0a61b0df | 481 | { |
41b052ad PW |
482 | ssSend.clear(); |
483 | ||
88bc5f94 | 484 | LEAVE_CRITICAL_SECTION(cs_vSend); |
e674680d | 485 | |
881a85a2 | 486 | LogPrint("net", "(aborted)\n"); |
0a61b0df | 487 | } |
488 | ||
25511af4 AK |
489 | // TODO: Document the precondition of this function. Is cs_vSend locked? |
490 | void EndMessage() UNLOCK_FUNCTION(cs_vSend) | |
0a61b0df | 491 | { |
9038b18f GA |
492 | // The -*messagestest options are intentionally not documented in the help message, |
493 | // since they are only used during development to debug the networking code and are | |
494 | // not intended for end-users. | |
495 | if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0) | |
0a61b0df | 496 | { |
881a85a2 | 497 | LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n"); |
0a61b0df | 498 | AbortMessage(); |
499 | return; | |
500 | } | |
9038b18f GA |
501 | if (mapArgs.count("-fuzzmessagestest")) |
502 | Fuzz(GetArg("-fuzzmessagestest", 10)); | |
0a61b0df | 503 | |
41b052ad | 504 | if (ssSend.size() == 0) |
0a61b0df | 505 | return; |
506 | ||
507 | // Set the size | |
41b052ad PW |
508 | unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; |
509 | memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize)); | |
0a61b0df | 510 | |
511 | // Set the checksum | |
41b052ad | 512 | uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); |
18c0fa97 PW |
513 | unsigned int nChecksum = 0; |
514 | memcpy(&nChecksum, &hash, sizeof(nChecksum)); | |
41b052ad PW |
515 | assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); |
516 | memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum)); | |
0a61b0df | 517 | |
881a85a2 | 518 | LogPrint("net", "(%d bytes)\n", nSize); |
0a61b0df | 519 | |
41b052ad PW |
520 | std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData()); |
521 | ssSend.GetAndClear(*it); | |
522 | nSendSize += (*it).size(); | |
523 | ||
b9ff2970 | 524 | // If write queue empty, attempt "optimistic write" |
41b052ad | 525 | if (it == vSendMsg.begin()) |
b9ff2970 JG |
526 | SocketSendData(this); |
527 | ||
88bc5f94 | 528 | LEAVE_CRITICAL_SECTION(cs_vSend); |
0a61b0df | 529 | } |
530 | ||
f8ded588 | 531 | void PushVersion(); |
cbc920d4 | 532 | |
0a61b0df | 533 | |
534 | void PushMessage(const char* pszCommand) | |
535 | { | |
536 | try | |
537 | { | |
538 | BeginMessage(pszCommand); | |
539 | EndMessage(); | |
540 | } | |
541 | catch (...) | |
542 | { | |
543 | AbortMessage(); | |
544 | throw; | |
545 | } | |
546 | } | |
547 | ||
548 | template<typename T1> | |
549 | void PushMessage(const char* pszCommand, const T1& a1) | |
550 | { | |
551 | try | |
552 | { | |
553 | BeginMessage(pszCommand); | |
41b052ad | 554 | ssSend << a1; |
0a61b0df | 555 | EndMessage(); |
556 | } | |
557 | catch (...) | |
558 | { | |
559 | AbortMessage(); | |
560 | throw; | |
561 | } | |
562 | } | |
563 | ||
564 | template<typename T1, typename T2> | |
565 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2) | |
566 | { | |
567 | try | |
568 | { | |
569 | BeginMessage(pszCommand); | |
41b052ad | 570 | ssSend << a1 << a2; |
0a61b0df | 571 | EndMessage(); |
572 | } | |
573 | catch (...) | |
574 | { | |
575 | AbortMessage(); | |
576 | throw; | |
577 | } | |
578 | } | |
579 | ||
580 | template<typename T1, typename T2, typename T3> | |
581 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3) | |
582 | { | |
583 | try | |
584 | { | |
585 | BeginMessage(pszCommand); | |
41b052ad | 586 | ssSend << a1 << a2 << a3; |
0a61b0df | 587 | EndMessage(); |
588 | } | |
589 | catch (...) | |
590 | { | |
591 | AbortMessage(); | |
592 | throw; | |
593 | } | |
594 | } | |
595 | ||
596 | template<typename T1, typename T2, typename T3, typename T4> | |
597 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4) | |
598 | { | |
599 | try | |
600 | { | |
601 | BeginMessage(pszCommand); | |
41b052ad | 602 | ssSend << a1 << a2 << a3 << a4; |
0a61b0df | 603 | EndMessage(); |
604 | } | |
605 | catch (...) | |
606 | { | |
607 | AbortMessage(); | |
608 | throw; | |
609 | } | |
610 | } | |
611 | ||
612 | template<typename T1, typename T2, typename T3, typename T4, typename T5> | |
613 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5) | |
614 | { | |
615 | try | |
616 | { | |
617 | BeginMessage(pszCommand); | |
41b052ad | 618 | ssSend << a1 << a2 << a3 << a4 << a5; |
0a61b0df | 619 | EndMessage(); |
620 | } | |
621 | catch (...) | |
622 | { | |
623 | AbortMessage(); | |
624 | throw; | |
625 | } | |
626 | } | |
627 | ||
628 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> | |
629 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6) | |
630 | { | |
631 | try | |
632 | { | |
633 | BeginMessage(pszCommand); | |
41b052ad | 634 | ssSend << a1 << a2 << a3 << a4 << a5 << a6; |
0a61b0df | 635 | EndMessage(); |
636 | } | |
637 | catch (...) | |
638 | { | |
639 | AbortMessage(); | |
640 | throw; | |
641 | } | |
642 | } | |
643 | ||
644 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> | |
645 | 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) | |
646 | { | |
647 | try | |
648 | { | |
649 | BeginMessage(pszCommand); | |
41b052ad | 650 | ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; |
0a61b0df | 651 | EndMessage(); |
652 | } | |
653 | catch (...) | |
654 | { | |
655 | AbortMessage(); | |
656 | throw; | |
657 | } | |
658 | } | |
659 | ||
660 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> | |
661 | 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) | |
662 | { | |
663 | try | |
664 | { | |
665 | BeginMessage(pszCommand); | |
41b052ad | 666 | ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; |
0a61b0df | 667 | EndMessage(); |
668 | } | |
669 | catch (...) | |
670 | { | |
671 | AbortMessage(); | |
672 | throw; | |
673 | } | |
674 | } | |
675 | ||
676 | template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> | |
677 | 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) | |
678 | { | |
679 | try | |
680 | { | |
681 | BeginMessage(pszCommand); | |
41b052ad | 682 | ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; |
0a61b0df | 683 | EndMessage(); |
684 | } | |
685 | catch (...) | |
686 | { | |
687 | AbortMessage(); | |
688 | throw; | |
689 | } | |
690 | } | |
691 | ||
0a61b0df | 692 | bool IsSubscribed(unsigned int nChannel); |
693 | void Subscribe(unsigned int nChannel, unsigned int nHops=0); | |
694 | void CancelSubscribe(unsigned int nChannel); | |
695 | void CloseSocketDisconnect(); | |
696 | void Cleanup(); | |
15f3ad4d GA |
697 | |
698 | ||
699 | // Denial-of-service detection/prevention | |
700 | // The idea is to detect peers that are behaving | |
701 | // badly and disconnect/ban them, but do it in a | |
702 | // one-coding-mistake-won't-shatter-the-entire-network | |
703 | // way. | |
704 | // IMPORTANT: There should be nothing I can give a | |
705 | // node that it will forward on that will make that | |
706 | // node's peers drop it. If there is, an attacker | |
707 | // can isolate a node and/or try to split the network. | |
708 | // Dropping a node for sending stuff that is invalid | |
709 | // now but might be valid in a later version is also | |
710 | // dangerous, because it can cause a network split | |
711 | // between nodes running old code and nodes running | |
712 | // new code. | |
713 | static void ClearBanned(); // needed for unit testing | |
67a42f92 | 714 | static bool IsBanned(CNetAddr ip); |
b2864d2f | 715 | static bool Ban(const CNetAddr &ip); |
1006f070 | 716 | void copyStats(CNodeStats &stats); |
ce14345a SE |
717 | |
718 | // Network stats | |
51ed9ec9 BD |
719 | static void RecordBytesRecv(uint64_t bytes); |
720 | static void RecordBytesSent(uint64_t bytes); | |
ce14345a | 721 | |
51ed9ec9 BD |
722 | static uint64_t GetTotalBytesRecv(); |
723 | static uint64_t GetTotalBytesSent(); | |
0a61b0df | 724 | }; |
725 | ||
726 | ||
727 | ||
269d9c64 MC |
728 | class CTransaction; |
729 | void RelayTransaction(const CTransaction& tx, const uint256& hash); | |
730 | void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss); | |
0a61b0df | 731 | |
d004d727 WL |
732 | /** Access to the (IP) address database (peers.dat) */ |
733 | class CAddrDB | |
734 | { | |
735 | private: | |
736 | boost::filesystem::path pathAddr; | |
737 | public: | |
738 | CAddrDB(); | |
739 | bool Write(const CAddrMan& addr); | |
740 | bool Read(CAddrMan& addr); | |
741 | }; | |
742 | ||
223b6f1b | 743 | #endif |