]> Git Repo - VerusCoin.git/blame - src/net.cpp
Merge branch 'dev' of github.com:miketout/VerusCoin into dev
[VerusCoin.git] / src / net.cpp
CommitLineData
0a61b0df 1// Copyright (c) 2009-2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2014 The Bitcoin Core developers
78253fcb 3// Distributed under the MIT software license, see the accompanying
3a25a2b9 4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
0a61b0df 5
35b8af92 6#if defined(HAVE_CONFIG_H)
f3967bcc 7#include "config/bitcoin-config.h"
35b8af92
CF
8#endif
9
72b21929 10#include "main.h"
40c2614e 11#include "net.h"
51ed9ec9 12
5fee401f 13#include "addrman.h"
51ed9ec9 14#include "chainparams.h"
71697f97 15#include "clientversion.h"
d2270111 16#include "primitives/transaction.h"
9a1dcea2 17#include "scheduler.h"
ed6d0b5f 18#include "ui_interface.h"
dec84cae 19#include "crypto/common.h"
51ed9ec9 20
9cb1ec9c 21#ifdef _WIN32
013df1cc 22#include <string.h>
51ed9ec9 23#else
98148a71 24#include <fcntl.h>
25#endif
26
a486abd4 27#include <boost/filesystem.hpp>
ad49c256 28#include <boost/thread.hpp>
a486abd4 29
c43da3f1
PW
30// Dump addresses to peers.dat every 15 minutes (900s)
31#define DUMP_ADDRESSES_INTERVAL 900
51ed9ec9
BD
32
33#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
35b8af92
CF
34#define MSG_NOSIGNAL 0
35#endif
c43da3f1 36
9e9ca2b6
PK
37// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
38// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
9cb1ec9c 39#ifdef _WIN32
9e9ca2b6
PK
40#ifndef PROTECTION_LEVEL_UNRESTRICTED
41#define PROTECTION_LEVEL_UNRESTRICTED 10
42#endif
43#ifndef IPV6_PROTECTION_LEVEL
44#define IPV6_PROTECTION_LEVEL 23
45#endif
46#endif
47
611116d4 48using namespace std;
223b6f1b 49
dc942e6f 50namespace {
3b02f606 51 const int MAX_OUTBOUND_CONNECTIONS = 5;
0ba20651 52 const int MAX_INBOUND_FROMIP = 3;
dc942e6f
PW
53
54 struct ListenSocket {
55 SOCKET socket;
56 bool whitelisted;
57
58 ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {}
59 };
60}
0a61b0df 61
0a61b0df 62//
63// Global state variables
64//
0ba20651 65extern uint16_t ASSETCHAINS_P2PPORT;
b2a98c42
MT
66extern std::string NOTARY_PUBKEY;
67extern int32_t USE_EXTERNAL_PUBKEY;
0ba20651 68
587f929c 69bool fDiscover = true;
53a08815 70bool fListen = true;
70352e11 71uint64_t nLocalServices = NODE_NETWORK;
d387b8ec
WL
72CCriticalSection cs_mapLocalHost;
73map<CNetAddr, LocalServiceInfo> mapLocalHost;
457754d2 74static bool vfLimited[NET_MAX] = {};
99860de3 75static CNode* pnodeLocalHost = NULL;
51ed9ec9 76uint64_t nLocalHostNonce = 0;
dc942e6f 77static std::vector<ListenSocket> vhListenSocket;
5fee401f 78CAddrMan addrman;
8a5ae3c7 79int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
94064710 80bool fAddressesInitialized = false;
2bc62dc4 81std::string strSubVersion;
0a61b0df 82
83vector<CNode*> vNodes;
84CCriticalSection cs_vNodes;
0a61b0df 85map<CInv, CDataStream> mapRelay;
51ed9ec9 86deque<pair<int64_t, CInv> > vRelayExpiration;
0a61b0df 87CCriticalSection cs_mapRelay;
51ed9ec9 88limitedmap<CInv, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
0a61b0df 89
478b01d9 90static deque<string> vOneShots;
39d2e9e0 91static CCriticalSection cs_vOneShots;
0a61b0df 92
39d2e9e0
PG
93static set<CNetAddr> setservAddNodeAddresses;
94static CCriticalSection cs_setservAddNodeAddresses;
b24e6e4d 95
74088e86
MC
96vector<std::string> vAddedNodes;
97CCriticalSection cs_vAddedNodes;
98
b2864d2f
PW
99NodeId nLastNodeId = 0;
100CCriticalSection cs_nLastNodeId;
101
c59abe25 102static CSemaphore *semOutbound = NULL;
39d2e9e0 103static boost::condition_variable messageHandlerCondition;
0a61b0df 104
501da250
EL
105// Signals for message handling
106static CNodeSignals g_signals;
107CNodeSignals& GetNodeSignals() { return g_signals; }
663224c2 108
db954a65 109void AddOneShot(const std::string& strDest)
478b01d9
PW
110{
111 LOCK(cs_vOneShots);
112 vOneShots.push_back(strDest);
113}
114
00bcfe0b
GA
115unsigned short GetListenPort()
116{
3fca36b0 117 //printf("Listenport.%u\n",Params().GetDefaultPort());
0e4b3175 118 return (unsigned short)(GetArg("-port", Params().GetDefaultPort()));
00bcfe0b 119}
0a61b0df 120
39857190 121// find 'best' local address for a particular peer
7fa4443f 122bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
39857190 123{
53a08815 124 if (!fListen)
39857190 125 return false;
0a61b0df 126
139d2f7c 127 int nBestScore = -1;
39857190
PW
128 int nBestReachability = -1;
129 {
130 LOCK(cs_mapLocalHost);
139d2f7c 131 for (map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
39857190 132 {
139d2f7c 133 int nScore = (*it).second.nScore;
39857190 134 int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
139d2f7c 135 if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
39857190 136 {
139d2f7c 137 addr = CService((*it).first, (*it).second.nPort);
39857190 138 nBestReachability = nReachability;
139d2f7c 139 nBestScore = nScore;
39857190
PW
140 }
141 }
142 }
139d2f7c 143 return nBestScore >= 0;
39857190 144}
0a61b0df 145
739d6155
CF
146//! Convert the pnSeeds6 array into usable address objects.
147static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn)
148{
149 // It'll only connect to one or two seed nodes because once it connects,
150 // it'll get a pile of addresses with newer timestamps.
151 // Seed nodes are given a random 'last seen time' of between one and two
152 // weeks ago.
153 const int64_t nOneWeek = 7*24*60*60;
154 std::vector<CAddress> vSeedsOut;
155 vSeedsOut.reserve(vSeedsIn.size());
156 for (std::vector<SeedSpec6>::const_iterator i(vSeedsIn.begin()); i != vSeedsIn.end(); ++i)
157 {
158 struct in6_addr ip;
159 memcpy(&ip, i->addr, sizeof(ip));
160 CAddress addr(CService(ip, i->port));
161 addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;
162 vSeedsOut.push_back(addr);
163 }
164 return vSeedsOut;
165}
166
39857190 167// get best local address for a particular peer as a CAddress
845c86d1
GM
168// Otherwise, return the unroutable 0.0.0.0 but filled in with
169// the normal parameters, since the IP may be changed to a useful
170// one by discovery.
39857190
PW
171CAddress GetLocalAddress(const CNetAddr *paddrPeer)
172{
845c86d1 173 CAddress ret(CService("0.0.0.0",GetListenPort()),0);
7fa4443f 174 CService addr;
39857190
PW
175 if (GetLocal(addr, paddrPeer))
176 {
7fa4443f 177 ret = CAddress(addr);
39857190 178 }
845c86d1
GM
179 ret.nServices = nLocalServices;
180 ret.nTime = GetAdjustedTime();
39857190
PW
181 return ret;
182}
0a61b0df 183
845c86d1 184int GetnScore(const CService& addr)
39857190 185{
845c86d1
GM
186 LOCK(cs_mapLocalHost);
187 if (mapLocalHost.count(addr) == LOCAL_NONE)
188 return 0;
189 return mapLocalHost[addr].nScore;
190}
191
192// Is our peer's addrLocal potentially useful as an external IP source?
193bool IsPeerAddrLocalGood(CNode *pnode)
194{
195 return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() &&
196 !IsLimited(pnode->addrLocal.GetNetwork());
197}
198
199// pushes our own address to a peer
200void AdvertizeLocal(CNode *pnode)
201{
202 if (fListen && pnode->fSuccessfullyConnected)
39857190 203 {
845c86d1
GM
204 CAddress addrLocal = GetLocalAddress(&pnode->addr);
205 // If discovery is enabled, sometimes give our peer the address it
206 // tells us that it sees us as in case it has a better idea of our
207 // address than we do.
208 if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
209 GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
39857190 210 {
845c86d1
GM
211 addrLocal.SetIP(pnode->addrLocal);
212 }
213 if (addrLocal.IsRoutable())
214 {
eb5f63fe 215 LogPrintf("AdvertizeLocal: advertizing address %s\n", addrLocal.ToString());
845c86d1 216 pnode->PushAddress(addrLocal);
39857190
PW
217 }
218 }
219}
220
221// learn a new local address
7fa4443f 222bool AddLocal(const CService& addr, int nScore)
39857190
PW
223{
224 if (!addr.IsRoutable())
225 return false;
226
587f929c 227 if (!fDiscover && nScore < LOCAL_MANUAL)
af4006b3
PW
228 return false;
229
09b4e26a 230 if (IsLimited(addr))
1653f97c
PW
231 return false;
232
7d9d134b 233 LogPrintf("AddLocal(%s,%i)\n", addr.ToString(), nScore);
39857190
PW
234
235 {
236 LOCK(cs_mapLocalHost);
139d2f7c
PW
237 bool fAlready = mapLocalHost.count(addr) > 0;
238 LocalServiceInfo &info = mapLocalHost[addr];
239 if (!fAlready || nScore >= info.nScore) {
af4da4be
PW
240 info.nScore = nScore + (fAlready ? 1 : 0);
241 info.nPort = addr.GetPort();
139d2f7c 242 }
39857190
PW
243 }
244
39857190
PW
245 return true;
246}
247
5a3cb32e 248bool AddLocal(const CNetAddr &addr, int nScore)
7fa4443f 249{
5a3cb32e 250 return AddLocal(CService(addr, GetListenPort()), nScore);
7fa4443f
PW
251}
252
975dc649
WL
253bool RemoveLocal(const CService& addr)
254{
255 LOCK(cs_mapLocalHost);
256 LogPrintf("RemoveLocal(%s)\n", addr.ToString());
257 mapLocalHost.erase(addr);
258 return true;
259}
260
457754d2
PW
261/** Make a particular network entirely off-limits (no automatic connects to it) */
262void SetLimited(enum Network net, bool fLimited)
263{
0f1707de
PW
264 if (net == NET_UNROUTABLE)
265 return;
457754d2
PW
266 LOCK(cs_mapLocalHost);
267 vfLimited[net] = fLimited;
268}
269
0f1707de 270bool IsLimited(enum Network net)
457754d2
PW
271{
272 LOCK(cs_mapLocalHost);
0f1707de
PW
273 return vfLimited[net];
274}
275
276bool IsLimited(const CNetAddr &addr)
277{
278 return IsLimited(addr.GetNetwork());
457754d2
PW
279}
280
281/** vote for a local address */
7fa4443f 282bool SeenLocal(const CService& addr)
39857190
PW
283{
284 {
285 LOCK(cs_mapLocalHost);
286 if (mapLocalHost.count(addr) == 0)
287 return false;
139d2f7c 288 mapLocalHost[addr].nScore++;
39857190 289 }
39857190
PW
290 return true;
291}
292
845c86d1 293
457754d2 294/** check whether a given address is potentially local */
7fa4443f 295bool IsLocal(const CService& addr)
39857190
PW
296{
297 LOCK(cs_mapLocalHost);
298 return mapLocalHost.count(addr) > 0;
299}
0a61b0df 300
c91a9471
WL
301/** check whether a given network is one we can probably connect to */
302bool IsReachable(enum Network net)
303{
304 LOCK(cs_mapLocalHost);
a05be280 305 return !vfLimited[net];
c91a9471
WL
306}
307
457754d2 308/** check whether a given address is in a network we can probably connect to */
090e5b40
PW
309bool IsReachable(const CNetAddr& addr)
310{
457754d2 311 enum Network net = addr.GetNetwork();
c91a9471 312 return IsReachable(net);
090e5b40 313}
0a61b0df 314
67a42f92 315void AddressCurrentlyConnected(const CService& addr)
0a61b0df 316{
5fee401f 317 addrman.Connected(addr);
0a61b0df 318}
319
320
51ed9ec9
BD
321uint64_t CNode::nTotalBytesRecv = 0;
322uint64_t CNode::nTotalBytesSent = 0;
ce14345a
SE
323CCriticalSection CNode::cs_totalBytesRecv;
324CCriticalSection CNode::cs_totalBytesSent;
0a61b0df 325
67a42f92 326CNode* FindNode(const CNetAddr& ip)
0a61b0df 327{
b001c871
PK
328 LOCK(cs_vNodes);
329 BOOST_FOREACH(CNode* pnode, vNodes)
330 if ((CNetAddr)pnode->addr == ip)
331 return (pnode);
0a61b0df 332 return NULL;
333}
334
e5219399
JS
335CNode* FindNode(const CSubNet& subNet)
336{
337 LOCK(cs_vNodes);
338 BOOST_FOREACH(CNode* pnode, vNodes)
339 if (subNet.Match((CNetAddr)pnode->addr))
340 return (pnode);
341 return NULL;
342}
343
0430c30a 344CNode* FindNode(const std::string& addrName)
9bab521d
PW
345{
346 LOCK(cs_vNodes);
347 BOOST_FOREACH(CNode* pnode, vNodes)
348 if (pnode->addrName == addrName)
349 return (pnode);
350 return NULL;
351}
352
67a42f92 353CNode* FindNode(const CService& addr)
0a61b0df 354{
b001c871
PK
355 LOCK(cs_vNodes);
356 BOOST_FOREACH(CNode* pnode, vNodes)
357 if ((CService)pnode->addr == addr)
358 return (pnode);
0a61b0df 359 return NULL;
360}
361
cedaa714 362CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
0a61b0df 363{
478b01d9 364 if (pszDest == NULL) {
39857190 365 if (IsLocal(addrConnect))
9bab521d 366 return NULL;
0a61b0df 367
9bab521d
PW
368 // Look for an existing connection
369 CNode* pnode = FindNode((CService)addrConnect);
370 if (pnode)
371 {
cedaa714 372 pnode->AddRef();
9bab521d
PW
373 return pnode;
374 }
0a61b0df 375 }
376
377 /// debug print
881a85a2 378 LogPrint("net", "trying connection %s lastseen=%.1fhrs\n",
7d9d134b 379 pszDest ? pszDest : addrConnect.ToString(),
5bd6c31b 380 pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
0a61b0df 381
382 // Connect
383 SOCKET hSocket;
35e408f8
WL
384 bool proxyConnectionFailed = false;
385 if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) :
386 ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed))
0a61b0df 387 {
0095b9a1
PW
388 if (!IsSelectableSocket(hSocket)) {
389 LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
390 CloseSocket(hSocket);
391 return NULL;
392 }
393
9bab521d
PW
394 addrman.Attempt(addrConnect);
395
0a61b0df 396 // Add node
9bab521d 397 CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
cedaa714 398 pnode->AddRef();
9bab521d 399
f8dcd5ca
PW
400 {
401 LOCK(cs_vNodes);
0a61b0df 402 vNodes.push_back(pnode);
f8dcd5ca 403 }
0a61b0df 404
405 pnode->nTimeConnected = GetTime();
2e36866f 406
0a61b0df 407 return pnode;
35e408f8
WL
408 } else if (!proxyConnectionFailed) {
409 // If connecting to the node failed, and failure is not caused by a problem connecting to
410 // the proxy, mark this as an attempt.
411 addrman.Attempt(addrConnect);
0a61b0df 412 }
5bd6c31b
PK
413
414 return NULL;
0a61b0df 415}
416
417void CNode::CloseSocketDisconnect()
418{
419 fDisconnect = true;
420 if (hSocket != INVALID_SOCKET)
421 {
2e36866f 422 LogPrint("net", "disconnecting peer=%d\n", id);
43f510d3 423 CloseSocket(hSocket);
0a61b0df 424 }
6ed71b5e
PW
425
426 // in case this fails, we'll empty the recv buffer when the CNode is deleted
427 TRY_LOCK(cs_vRecvMsg, lockRecv);
428 if (lockRecv)
429 vRecvMsg.clear();
0a61b0df 430}
431
f8ded588
GA
432void CNode::PushVersion()
433{
4c6d41b8
PW
434 int nBestHeight = g_signals.GetHeight().get_value_or(0);
435
51ed9ec9 436 int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
587f929c 437 CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
39857190 438 CAddress addrMe = GetLocalAddress(&addr);
001a53d7 439 GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
2e36866f
B
440 if (fLogIPs)
441 LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id);
442 else
443 LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
b2a98c42 444
5d5737c1 445 if (CConstVerusSolutionVector::activationHeight.ActiveVersion(nBestHeight + 1) >= CConstVerusSolutionVector::activationHeight.SOLUTION_VERUSV3)
b2a98c42
MT
446 {
447 CKeyID nodePaymentAddress;
448 if (USE_EXTERNAL_PUBKEY)
449 {
30bb5afd
MT
450 CPubKey pubKey = CPubKey(ParseHex(NOTARY_PUBKEY));
451 if (pubKey.IsFullyValid())
452 {
453 nodePaymentAddress = pubKey.GetID();
454 }
b2a98c42
MT
455 LogPrint("net", "send PBaaS node payment pubkey hash -- pubkey: %s, hash: %s\n", NOTARY_PUBKEY, nodePaymentAddress.ToString());
456 }
457 PushMessage("version", PROTOCOL_VERSION > MIN_PBAAS_VERSION ? PROTOCOL_VERSION : MIN_PBAAS_VERSION,
458 nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, nodePaymentAddress, strSubVersion, nBestHeight, true);
459 }
460 else
461 {
462 PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, strSubVersion, nBestHeight, true);
463 }
f8ded588
GA
464}
465
466
467
468
469
e5219399 470std::map<CSubNet, int64_t> CNode::setBanned;
15f3ad4d
GA
471CCriticalSection CNode::cs_setBanned;
472
473void CNode::ClearBanned()
474{
0382246b 475 LOCK(cs_setBanned);
15f3ad4d
GA
476 setBanned.clear();
477}
478
67a42f92 479bool CNode::IsBanned(CNetAddr ip)
15f3ad4d
GA
480{
481 bool fResult = false;
15f3ad4d 482 {
f8dcd5ca 483 LOCK(cs_setBanned);
e5219399
JS
484 for (std::map<CSubNet, int64_t>::iterator it = setBanned.begin(); it != setBanned.end(); it++)
485 {
486 CSubNet subNet = (*it).first;
487 int64_t t = (*it).second;
488
489 if(subNet.Match(ip) && GetTime() < t)
490 fResult = true;
491 }
492 }
493 return fResult;
494}
495
496bool CNode::IsBanned(CSubNet subnet)
497{
498 bool fResult = false;
499 {
500 LOCK(cs_setBanned);
501 std::map<CSubNet, int64_t>::iterator i = setBanned.find(subnet);
15f3ad4d
GA
502 if (i != setBanned.end())
503 {
51ed9ec9 504 int64_t t = (*i).second;
15f3ad4d
GA
505 if (GetTime() < t)
506 fResult = true;
507 }
508 }
509 return fResult;
510}
511
fcc8920f 512void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset, bool sinceUnixEpoch) {
e5219399 513 CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128"));
fcc8920f 514 Ban(subNet, bantimeoffset, sinceUnixEpoch);
e5219399
JS
515}
516
fcc8920f 517void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoch) {
b2864d2f 518 int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
99782971 519 if (bantimeoffset > 0)
fcc8920f 520 banTime = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
99782971
JS
521
522 LOCK(cs_setBanned);
e5219399
JS
523 if (setBanned[subNet] < banTime)
524 setBanned[subNet] = banTime;
15f3ad4d
GA
525}
526
99782971 527bool CNode::Unban(const CNetAddr &addr) {
e5219399
JS
528 CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128"));
529 return Unban(subNet);
530}
531
532bool CNode::Unban(const CSubNet &subNet) {
99782971 533 LOCK(cs_setBanned);
e5219399 534 if (setBanned.erase(subNet))
99782971
JS
535 return true;
536 return false;
537}
538
e5219399 539void CNode::GetBanned(std::map<CSubNet, int64_t> &banMap)
99782971
JS
540{
541 LOCK(cs_setBanned);
542 banMap = setBanned; //create a thread safe copy
15f3ad4d
GA
543}
544
dc942e6f
PW
545
546std::vector<CSubNet> CNode::vWhitelistedRange;
547CCriticalSection CNode::cs_vWhitelistedRange;
548
549bool CNode::IsWhitelistedRange(const CNetAddr &addr) {
550 LOCK(cs_vWhitelistedRange);
551 BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) {
552 if (subnet.Match(addr))
553 return true;
554 }
555 return false;
556}
557
558void CNode::AddWhitelistedRange(const CSubNet &subnet) {
559 LOCK(cs_vWhitelistedRange);
560 vWhitelistedRange.push_back(subnet);
561}
562
1006f070
JG
563void CNode::copyStats(CNodeStats &stats)
564{
b2864d2f 565 stats.nodeid = this->GetId();
7e9d662e
S
566 stats.nServices = nServices;
567 stats.nLastSend = nLastSend;
568 stats.nLastRecv = nLastRecv;
569 stats.nTimeConnected = nTimeConnected;
570 stats.nTimeOffset = nTimeOffset;
571 stats.addrName = addrName;
572 stats.nVersion = nVersion;
573 stats.cleanSubVer = cleanSubVer;
574 stats.fInbound = fInbound;
575 stats.nStartingHeight = nStartingHeight;
576 stats.nSendBytes = nSendBytes;
577 stats.nRecvBytes = nRecvBytes;
578 stats.fWhitelisted = fWhitelisted;
fabba0e6 579
971bb3e9
JL
580 // It is common for nodes with good ping times to suddenly become lagged,
581 // due to a new block arriving or other large transfer.
582 // Merely reporting pingtime might fool the caller into thinking the node was still responsive,
583 // since pingtime does not update until the ping is complete, which might take a while.
584 // So, if a ping is taking an unusually long time in flight,
585 // the caller can immediately detect that this is happening.
51ed9ec9 586 int64_t nPingUsecWait = 0;
971bb3e9
JL
587 if ((0 != nPingNonceSent) && (0 != nPingUsecStart)) {
588 nPingUsecWait = GetTimeMicros() - nPingUsecStart;
589 }
fabba0e6 590
971bb3e9
JL
591 // Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
592 stats.dPingTime = (((double)nPingUsecTime) / 1e6);
593 stats.dPingWait = (((double)nPingUsecWait) / 1e6);
fabba0e6 594
547c61f8
JL
595 // Leave string empty if addrLocal invalid (not filled in yet)
596 stats.addrLocal = addrLocal.IsValid() ? addrLocal.ToString() : "";
1006f070 597}
0a61b0df 598
607dbfde
JG
599// requires LOCK(cs_vRecvMsg)
600bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
601{
602 while (nBytes > 0) {
603
604 // get current incomplete message, or create a new one
967f2459 605 if (vRecvMsg.empty() ||
607dbfde 606 vRecvMsg.back().complete())
eec37136 607 vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, nRecvVersion));
607dbfde
JG
608
609 CNetMessage& msg = vRecvMsg.back();
610
611 // absorb network data
612 int handled;
613 if (!msg.in_data)
614 handled = msg.readHeader(pch, nBytes);
615 else
616 handled = msg.readData(pch, nBytes);
617
618 if (handled < 0)
619 return false;
620
ba04c4a7 621 if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {
e0020d4c 622 LogPrint("net", "Oversized message from peer=%i, disconnecting\n", GetId());
ba04c4a7
PW
623 return false;
624 }
625
607dbfde
JG
626 pch += handled;
627 nBytes -= handled;
9f4da19b 628
351593b9 629 if (msg.complete()) {
9f4da19b 630 msg.nTime = GetTimeMicros();
351593b9 631 messageHandlerCondition.notify_one();
632 }
607dbfde
JG
633 }
634
635 return true;
636}
637
638int CNetMessage::readHeader(const char *pch, unsigned int nBytes)
639{
640 // copy data to temporary parsing buffer
641 unsigned int nRemaining = 24 - nHdrPos;
642 unsigned int nCopy = std::min(nRemaining, nBytes);
643
644 memcpy(&hdrbuf[nHdrPos], pch, nCopy);
645 nHdrPos += nCopy;
646
647 // if header incomplete, exit
648 if (nHdrPos < 24)
649 return nCopy;
650
651 // deserialize to CMessageHeader
652 try {
653 hdrbuf >> hdr;
654 }
27df4123 655 catch (const std::exception&) {
607dbfde
JG
656 return -1;
657 }
658
659 // reject messages larger than MAX_SIZE
660 if (hdr.nMessageSize > MAX_SIZE)
661 return -1;
662
663 // switch state to reading message data
664 in_data = true;
607dbfde
JG
665
666 return nCopy;
667}
668
669int CNetMessage::readData(const char *pch, unsigned int nBytes)
670{
671 unsigned int nRemaining = hdr.nMessageSize - nDataPos;
672 unsigned int nCopy = std::min(nRemaining, nBytes);
673
806fd19e
PW
674 if (vRecv.size() < nDataPos + nCopy) {
675 // Allocate up to 256 KiB ahead, but never more than the total message size.
676 vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
677 }
678
607dbfde
JG
679 memcpy(&vRecv[nDataPos], pch, nCopy);
680 nDataPos += nCopy;
681
682 return nCopy;
683}
684
0a61b0df 685
686
687
688
689
690
691
692
bc2f5aa7
JG
693// requires LOCK(cs_vSend)
694void SocketSendData(CNode *pnode)
695{
41b052ad
PW
696 std::deque<CSerializeData>::iterator it = pnode->vSendMsg.begin();
697
698 while (it != pnode->vSendMsg.end()) {
699 const CSerializeData &data = *it;
700 assert(data.size() > pnode->nSendOffset);
701 int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
702 if (nBytes > 0) {
703 pnode->nLastSend = GetTime();
86648a8d 704 pnode->nSendBytes += nBytes;
41b052ad 705 pnode->nSendOffset += nBytes;
ce14345a 706 pnode->RecordBytesSent(nBytes);
41b052ad
PW
707 if (pnode->nSendOffset == data.size()) {
708 pnode->nSendOffset = 0;
709 pnode->nSendSize -= data.size();
710 it++;
711 } else {
712 // could not send full message; stop sending more
713 break;
714 }
715 } else {
716 if (nBytes < 0) {
717 // error
718 int nErr = WSAGetLastError();
719 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
720 {
a60838d0 721 LogPrintf("socket send error %s\n", NetworkErrorString(nErr));
41b052ad
PW
722 pnode->CloseSocketDisconnect();
723 }
724 }
725 // couldn't send anything at all
726 break;
bc2f5aa7
JG
727 }
728 }
41b052ad
PW
729
730 if (it == pnode->vSendMsg.end()) {
731 assert(pnode->nSendOffset == 0);
732 assert(pnode->nSendSize == 0);
733 }
734 pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it);
bc2f5aa7 735}
0a61b0df 736
3427517d
PW
737static list<CNode*> vNodesDisconnected;
738
6e966f67
PS
739class CNodeRef {
740public:
f1e7e371
PS
741 CNodeRef(CNode *pnode) : _pnode(pnode) {
742 LOCK(cs_vNodes);
743 _pnode->AddRef();
744 }
745
746 ~CNodeRef() {
747 LOCK(cs_vNodes);
748 _pnode->Release();
749 }
6e966f67
PS
750
751 CNode& operator *() const {return *_pnode;};
752 CNode* operator ->() const {return _pnode;};
75c0598c
PS
753
754 CNodeRef& operator =(const CNodeRef& other)
755 {
756 if (this != &other) {
f1e7e371
PS
757 LOCK(cs_vNodes);
758
75c0598c
PS
759 _pnode->Release();
760 _pnode = other._pnode;
761 _pnode->AddRef();
762 }
763 return *this;
764 }
765
766 CNodeRef(const CNodeRef& other):
767 _pnode(other._pnode)
768 {
f1e7e371 769 LOCK(cs_vNodes);
75c0598c
PS
770 _pnode->AddRef();
771 }
6e966f67
PS
772private:
773 CNode *_pnode;
774};
775
776static bool ReverseCompareNodeMinPingTime(const CNodeRef &a, const CNodeRef &b)
2fa41ff9
PS
777{
778 return a->nMinPingUsecTime > b->nMinPingUsecTime;
779}
780
6e966f67 781static bool ReverseCompareNodeTimeConnected(const CNodeRef &a, const CNodeRef &b)
2fa41ff9
PS
782{
783 return a->nTimeConnected > b->nTimeConnected;
784}
785
786class CompareNetGroupKeyed
787{
788 std::vector<unsigned char> vchSecretKey;
789public:
790 CompareNetGroupKeyed()
791 {
792 vchSecretKey.resize(32, 0);
793 GetRandBytes(vchSecretKey.data(), vchSecretKey.size());
794 }
795
6e966f67 796 bool operator()(const CNodeRef &a, const CNodeRef &b)
2fa41ff9
PS
797 {
798 std::vector<unsigned char> vchGroupA, vchGroupB;
799 CSHA256 hashA, hashB;
800 std::vector<unsigned char> vchA(32), vchB(32);
801
802 vchGroupA = a->addr.GetGroup();
803 vchGroupB = b->addr.GetGroup();
804
805 hashA.Write(begin_ptr(vchGroupA), vchGroupA.size());
806 hashB.Write(begin_ptr(vchGroupB), vchGroupB.size());
807
808 hashA.Write(begin_ptr(vchSecretKey), vchSecretKey.size());
809 hashB.Write(begin_ptr(vchSecretKey), vchSecretKey.size());
810
811 hashA.Finalize(begin_ptr(vchA));
812 hashB.Finalize(begin_ptr(vchB));
813
814 return vchA < vchB;
815 }
816};
817
dd99be0f 818static bool AttemptToEvictConnection(bool fPreferNewConnection) {
6e966f67 819 std::vector<CNodeRef> vEvictionCandidates;
2fa41ff9
PS
820 {
821 LOCK(cs_vNodes);
822
823 BOOST_FOREACH(CNode *node, vNodes) {
824 if (node->fWhitelisted)
825 continue;
826 if (!node->fInbound)
827 continue;
828 if (node->fDisconnect)
829 continue;
6e966f67 830 vEvictionCandidates.push_back(CNodeRef(node));
2fa41ff9
PS
831 }
832 }
833
ce94413e
PS
834 if (vEvictionCandidates.empty()) return false;
835
2fa41ff9 836 // Protect connections with certain characteristics
396bd999 837
72b21929
S
838 // Check version of eviction candidates and prioritize nodes which do not support network upgrade.
839 std::vector<CNodeRef> vTmpEvictionCandidates;
840 int height;
841 {
842 LOCK(cs_main);
843 height = chainActive.Height();
844 }
845
846 const Consensus::Params& params = Params().GetConsensus();
feee210a
JG
847 auto nextEpoch = NextEpoch(height, params);
848 if (nextEpoch) {
849 auto idx = nextEpoch.get();
850 int nActivationHeight = params.vUpgrades[idx].nActivationHeight;
851
852 if (nActivationHeight > 0 &&
853 height < nActivationHeight &&
854 height >= nActivationHeight - NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD)
855 {
856 // Find any nodes which don't support the protocol version for the next upgrade
857 for (const CNodeRef &node : vEvictionCandidates) {
858 if (node->nVersion < params.vUpgrades[idx].nProtocolVersion) {
859 vTmpEvictionCandidates.push_back(node);
860 }
72b21929 861 }
72b21929 862
feee210a
JG
863 // Prioritize these nodes by replacing eviction set with them
864 if (vTmpEvictionCandidates.size() > 0) {
865 vEvictionCandidates = vTmpEvictionCandidates;
866 }
72b21929
S
867 }
868 }
869
396bd999
PS
870 // Deterministically select 4 peers to protect by netgroup.
871 // An attacker cannot predict which netgroups will be protected.
2fa41ff9
PS
872 static CompareNetGroupKeyed comparerNetGroupKeyed;
873 std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed);
874 vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
875
ce94413e
PS
876 if (vEvictionCandidates.empty()) return false;
877
396bd999
PS
878 // Protect the 8 nodes with the best ping times.
879 // An attacker cannot manipulate this metric without physically moving nodes closer to the target.
2fa41ff9
PS
880 std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
881 vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
882
ce94413e
PS
883 if (vEvictionCandidates.empty()) return false;
884
b63e75ae 885 // Protect the half of the remaining nodes which have been connected the longest.
396bd999 886 // This replicates the existing implicit behavior.
2fa41ff9 887 std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
ce94413e 888 vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end());
2fa41ff9 889
ce94413e 890 if (vEvictionCandidates.empty()) return false;
2fa41ff9 891
f28a87b4
GM
892 // Identify the network group with the most connections and youngest member.
893 // (vEvictionCandidates is already sorted by reverse connect time)
85e84f5e 894 std::vector<unsigned char> naMostConnections;
2fa41ff9 895 unsigned int nMostConnections = 0;
f28a87b4 896 int64_t nMostConnectionsTime = 0;
85e84f5e 897 std::map<std::vector<unsigned char>, std::vector<CNodeRef> > mapAddrCounts;
6e966f67 898 BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) {
85e84f5e 899 mapAddrCounts[node->addr.GetGroup()].push_back(node);
f28a87b4
GM
900 int64_t grouptime = mapAddrCounts[node->addr.GetGroup()][0]->nTimeConnected;
901 size_t groupsize = mapAddrCounts[node->addr.GetGroup()].size();
2fa41ff9 902
f28a87b4
GM
903 if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
904 nMostConnections = groupsize;
905 nMostConnectionsTime = grouptime;
85e84f5e 906 naMostConnections = node->addr.GetGroup();
2fa41ff9
PS
907 }
908 }
909
85e84f5e 910 // Reduce to the network group with the most connections
2fa41ff9
PS
911 vEvictionCandidates = mapAddrCounts[naMostConnections];
912
f28a87b4 913 // Do not disconnect peers if there is only one unprotected connection from their network group.
2fa41ff9 914 if (vEvictionCandidates.size() <= 1)
dd99be0f
PS
915 // unless we prefer the new connection (for whitelisted peers)
916 if (!fPreferNewConnection)
917 return false;
2fa41ff9 918
f28a87b4 919 // Disconnect from the network group with the most connections
2fa41ff9
PS
920 vEvictionCandidates[0]->fDisconnect = true;
921
922 return true;
923}
924
057d6078
PS
925static void AcceptConnection(const ListenSocket& hListenSocket) {
926 struct sockaddr_storage sockaddr;
927 socklen_t len = sizeof(sockaddr);
928 SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
929 CAddress addr;
930 int nInbound = 0;
931 int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
932
933 if (hSocket != INVALID_SOCKET)
934 if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
935 LogPrintf("Warning: Unknown socket family\n");
936
937 bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
0ba20651
MT
938 int nInboundThisIP = 0;
939
057d6078
PS
940 {
941 LOCK(cs_vNodes);
0ba20651
MT
942 struct sockaddr_storage tmpsockaddr;
943 socklen_t tmplen = sizeof(sockaddr);
057d6078 944 BOOST_FOREACH(CNode* pnode, vNodes)
0ba20651 945 {
057d6078 946 if (pnode->fInbound)
0ba20651 947 {
057d6078 948 nInbound++;
0ba20651
MT
949 if (pnode->addr.GetSockAddr((struct sockaddr*)&tmpsockaddr, &tmplen) && (tmplen == len) && (memcmp(&sockaddr, &tmpsockaddr, tmplen) == 0))
950 nInboundThisIP++;
951 }
952 }
057d6078
PS
953 }
954
955 if (hSocket == INVALID_SOCKET)
956 {
957 int nErr = WSAGetLastError();
958 if (nErr != WSAEWOULDBLOCK)
959 LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
12005016 960 return;
057d6078 961 }
12005016
PS
962
963 if (!IsSelectableSocket(hSocket))
057d6078
PS
964 {
965 LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString());
966 CloseSocket(hSocket);
12005016 967 return;
057d6078 968 }
12005016 969
bd80ec0d 970 if (CNode::IsBanned(addr) && !whitelisted)
057d6078 971 {
bd80ec0d 972 LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
057d6078 973 CloseSocket(hSocket);
12005016 974 return;
057d6078 975 }
12005016 976
bd80ec0d 977 if (nInbound >= nMaxInbound)
057d6078 978 {
dd99be0f 979 if (!AttemptToEvictConnection(whitelisted)) {
2fa41ff9
PS
980 // No connection to evict, disconnect the new connection
981 LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n");
982 CloseSocket(hSocket);
983 return;
984 }
057d6078 985 }
12005016 986
0ba20651
MT
987 if (nInboundThisIP >= MAX_INBOUND_FROMIP)
988 {
989 // No connection to evict, disconnect the new connection
990 LogPrint("net", "too many connections from %s, connection refused\n", addr.ToString());
991 CloseSocket(hSocket);
992 return;
993 }
994
12005016
PS
995 // According to the internet TCP_NODELAY is not carried into accepted sockets
996 // on all platforms. Set it again here just to be sure.
997 int set = 1;
9cb1ec9c 998#ifdef _WIN32
12005016 999 setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
057d6078 1000#else
12005016 1001 setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
057d6078
PS
1002#endif
1003
12005016
PS
1004 CNode* pnode = new CNode(hSocket, addr, "", true);
1005 pnode->AddRef();
1006 pnode->fWhitelisted = whitelisted;
057d6078 1007
12005016 1008 LogPrint("net", "connection from %s accepted\n", addr.ToString());
057d6078 1009
12005016
PS
1010 {
1011 LOCK(cs_vNodes);
1012 vNodes.push_back(pnode);
057d6078
PS
1013 }
1014}
1015
21eb5ada 1016void ThreadSocketHandler()
0a61b0df 1017{
735a6069 1018 unsigned int nPrevNodeCount = 0;
050d2e95 1019 while (true)
0a61b0df 1020 {
1021 //
1022 // Disconnect nodes
1023 //
0a61b0df 1024 {
f8dcd5ca 1025 LOCK(cs_vNodes);
0a61b0df 1026 // Disconnect unused nodes
1027 vector<CNode*> vNodesCopy = vNodes;
223b6f1b 1028 BOOST_FOREACH(CNode* pnode, vNodesCopy)
0a61b0df 1029 {
1030 if (pnode->fDisconnect ||
41b052ad 1031 (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty()))
0a61b0df 1032 {
1033 // remove from vNodes
1034 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
1035
c59abe25
PW
1036 // release outbound grant (if any)
1037 pnode->grantOutbound.Release();
092631f0 1038
0a61b0df 1039 // close socket and cleanup
1040 pnode->CloseSocketDisconnect();
0a61b0df 1041
1042 // hold in disconnected pool until all refs are released
0a61b0df 1043 if (pnode->fNetworkNode || pnode->fInbound)
1044 pnode->Release();
1045 vNodesDisconnected.push_back(pnode);
1046 }
1047 }
49d754d9
PW
1048 }
1049 {
0a61b0df 1050 // Delete disconnected nodes
1051 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
223b6f1b 1052 BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
0a61b0df 1053 {
1054 // wait until threads are done using it
1055 if (pnode->GetRefCount() <= 0)
1056 {
1057 bool fDelete = false;
f8dcd5ca
PW
1058 {
1059 TRY_LOCK(pnode->cs_vSend, lockSend);
1060 if (lockSend)
1061 {
607dbfde 1062 TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
f8dcd5ca
PW
1063 if (lockRecv)
1064 {
529a4d48
WL
1065 TRY_LOCK(pnode->cs_inventory, lockInv);
1066 if (lockInv)
1067 fDelete = true;
f8dcd5ca
PW
1068 }
1069 }
1070 }
0a61b0df 1071 if (fDelete)
1072 {
1073 vNodesDisconnected.remove(pnode);
1074 delete pnode;
1075 }
1076 }
1077 }
1078 }
ce14345a 1079 if(vNodes.size() != nPrevNodeCount) {
0a61b0df 1080 nPrevNodeCount = vNodes.size();
ce14345a 1081 uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
0a61b0df 1082 }
1083
0a61b0df 1084 //
1085 // Find which sockets have data to receive
1086 //
1087 struct timeval timeout;
1088 timeout.tv_sec = 0;
1089 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
1090
1091 fd_set fdsetRecv;
1092 fd_set fdsetSend;
1093 fd_set fdsetError;
1094 FD_ZERO(&fdsetRecv);
1095 FD_ZERO(&fdsetSend);
1096 FD_ZERO(&fdsetError);
1097 SOCKET hSocketMax = 0;
23879447 1098 bool have_fds = false;
5f88e888 1099
dc942e6f
PW
1100 BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) {
1101 FD_SET(hListenSocket.socket, &fdsetRecv);
1102 hSocketMax = max(hSocketMax, hListenSocket.socket);
23879447 1103 have_fds = true;
8f10a288 1104 }
5d599212 1105
0a61b0df 1106 {
f8dcd5ca 1107 LOCK(cs_vNodes);
223b6f1b 1108 BOOST_FOREACH(CNode* pnode, vNodes)
0a61b0df 1109 {
d7f1d200 1110 if (pnode->hSocket == INVALID_SOCKET)
0a61b0df 1111 continue;
a9d9f0f5
PW
1112 FD_SET(pnode->hSocket, &fdsetError);
1113 hSocketMax = max(hSocketMax, pnode->hSocket);
1114 have_fds = true;
1115
1116 // Implement the following logic:
1117 // * If there is data to send, select() for sending data. As this only
1118 // happens when optimistic write failed, we choose to first drain the
1119 // write buffer in this case before receiving more. This avoids
1120 // needlessly queueing received data, if the remote peer is not themselves
c938fb1f 1121 // receiving data. This means properly utilizing TCP flow control signaling.
a9d9f0f5
PW
1122 // * Otherwise, if there is no (complete) message in the receive buffer,
1123 // or there is space left in the buffer, select() for receiving data.
1124 // * (if neither of the above applies, there is certainly one message
1125 // in the receiver buffer ready to be processed).
1126 // Together, that means that at least one of the following is always possible,
1127 // so we don't deadlock:
1128 // * We send some data.
1129 // * We wait for data to be received (and disconnect after timeout).
1130 // * We process a message in the buffer (message handler thread).
f8dcd5ca
PW
1131 {
1132 TRY_LOCK(pnode->cs_vSend, lockSend);
a9d9f0f5
PW
1133 if (lockSend && !pnode->vSendMsg.empty()) {
1134 FD_SET(pnode->hSocket, &fdsetSend);
1135 continue;
b9ff2970 1136 }
f8dcd5ca 1137 }
a9d9f0f5
PW
1138 {
1139 TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
1140 if (lockRecv && (
1141 pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() ||
1142 pnode->GetTotalRecvSize() <= ReceiveFloodSize()))
1143 FD_SET(pnode->hSocket, &fdsetRecv);
1144 }
0a61b0df 1145 }
1146 }
1147
23879447
JG
1148 int nSelect = select(have_fds ? hSocketMax + 1 : 0,
1149 &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
21eb5ada
GA
1150 boost::this_thread::interruption_point();
1151
0a61b0df 1152 if (nSelect == SOCKET_ERROR)
1153 {
23879447 1154 if (have_fds)
c6710c7a 1155 {
23879447 1156 int nErr = WSAGetLastError();
a60838d0 1157 LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
c376ac35 1158 for (unsigned int i = 0; i <= hSocketMax; i++)
c6710c7a
MC
1159 FD_SET(i, &fdsetRecv);
1160 }
0a61b0df 1161 FD_ZERO(&fdsetSend);
1162 FD_ZERO(&fdsetError);
1b43bf0d 1163 MilliSleep(timeout.tv_usec/1000);
0a61b0df 1164 }
1165
0a61b0df 1166 //
1167 // Accept new connections
1168 //
dc942e6f 1169 BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket)
0a61b0df 1170 {
dc942e6f 1171 if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
f8dcd5ca 1172 {
057d6078 1173 AcceptConnection(hListenSocket);
0a61b0df 1174 }
1175 }
1176
0a61b0df 1177 //
1178 // Service each socket
1179 //
1180 vector<CNode*> vNodesCopy;
0a61b0df 1181 {
f8dcd5ca 1182 LOCK(cs_vNodes);
0a61b0df 1183 vNodesCopy = vNodes;
223b6f1b 1184 BOOST_FOREACH(CNode* pnode, vNodesCopy)
0a61b0df 1185 pnode->AddRef();
1186 }
223b6f1b 1187 BOOST_FOREACH(CNode* pnode, vNodesCopy)
0a61b0df 1188 {
21eb5ada 1189 boost::this_thread::interruption_point();
0a61b0df 1190
1191 //
1192 // Receive
1193 //
1194 if (pnode->hSocket == INVALID_SOCKET)
1195 continue;
1196 if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
1197 {
607dbfde 1198 TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
f8dcd5ca 1199 if (lockRecv)
0a61b0df 1200 {
a9d9f0f5 1201 {
9cbae55a
GA
1202 // typical socket buffer is 8K-64K
1203 char pchBuf[0x10000];
1204 int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
1205 if (nBytes > 0)
0a61b0df 1206 {
607dbfde
JG
1207 if (!pnode->ReceiveMsgBytes(pchBuf, nBytes))
1208 pnode->CloseSocketDisconnect();
9cbae55a 1209 pnode->nLastRecv = GetTime();
86648a8d 1210 pnode->nRecvBytes += nBytes;
ce14345a 1211 pnode->RecordBytesRecv(nBytes);
9cbae55a
GA
1212 }
1213 else if (nBytes == 0)
1214 {
1215 // socket closed gracefully
0a61b0df 1216 if (!pnode->fDisconnect)
881a85a2 1217 LogPrint("net", "socket closed\n");
0a61b0df 1218 pnode->CloseSocketDisconnect();
1219 }
9cbae55a
GA
1220 else if (nBytes < 0)
1221 {
1222 // error
1223 int nErr = WSAGetLastError();
1224 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
1225 {
1226 if (!pnode->fDisconnect)
a60838d0 1227 LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
9cbae55a
GA
1228 pnode->CloseSocketDisconnect();
1229 }
1230 }
0a61b0df 1231 }
1232 }
1233 }
1234
1235 //
1236 // Send
1237 //
1238 if (pnode->hSocket == INVALID_SOCKET)
1239 continue;
1240 if (FD_ISSET(pnode->hSocket, &fdsetSend))
1241 {
f8dcd5ca
PW
1242 TRY_LOCK(pnode->cs_vSend, lockSend);
1243 if (lockSend)
bc2f5aa7 1244 SocketSendData(pnode);
0a61b0df 1245 }
1246
1247 //
1248 // Inactivity checking
1249 //
f1920e86
PW
1250 int64_t nTime = GetTime();
1251 if (nTime - pnode->nTimeConnected > 60)
0a61b0df 1252 {
1253 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
1254 {
2e36866f 1255 LogPrint("net", "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->id);
0a61b0df 1256 pnode->fDisconnect = true;
1257 }
f1920e86 1258 else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
0a61b0df 1259 {
f1920e86 1260 LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
0a61b0df 1261 pnode->fDisconnect = true;
1262 }
f1920e86 1263 else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
0a61b0df 1264 {
f1920e86
PW
1265 LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
1266 pnode->fDisconnect = true;
1267 }
1268 else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())
1269 {
1270 LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
0a61b0df 1271 pnode->fDisconnect = true;
1272 }
1273 }
1274 }
0a61b0df 1275 {
f8dcd5ca 1276 LOCK(cs_vNodes);
223b6f1b 1277 BOOST_FOREACH(CNode* pnode, vNodesCopy)
0a61b0df 1278 pnode->Release();
1279 }
0a61b0df 1280 }
1281}
1282
1283
21eb5ada 1284void ThreadDNSAddressSeed()
2bc6cece 1285{
2e7009d6
JG
1286 // goal: only query DNS seeds if address need is acute
1287 if ((addrman.size() > 0) &&
1288 (!GetBoolArg("-forcednsseed", false))) {
1289 MilliSleep(11 * 1000);
1290
1291 LOCK(cs_vNodes);
1292 if (vNodes.size() >= 2) {
1293 LogPrintf("P2P peers available. Skipped DNS seeding.\n");
1294 return;
1295 }
1296 }
1297
0e4b3175 1298 const vector<CDNSSeedData> &vSeeds = Params().DNSSeeds();
f684aec4
JG
1299 int found = 0;
1300
881a85a2 1301 LogPrintf("Loading addresses from DNS seeds (could take a while)\n");
af899882 1302
0e4b3175 1303 BOOST_FOREACH(const CDNSSeedData &seed, vSeeds) {
af899882 1304 if (HaveNameProxy()) {
0e4b3175 1305 AddOneShot(seed.host);
af899882 1306 } else {
0e4b3175 1307 vector<CNetAddr> vIPs;
af899882 1308 vector<CAddress> vAdd;
0e4b3175 1309 if (LookupHost(seed.host.c_str(), vIPs))
af899882 1310 {
db954a65 1311 BOOST_FOREACH(const CNetAddr& ip, vIPs)
a6a5bb7c 1312 {
af899882 1313 int nOneDay = 24*3600;
0e4b3175 1314 CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()));
af899882 1315 addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
0ba20651
MT
1316 // only add seeds with the right port
1317 if (addr.GetPort() == ASSETCHAINS_P2PPORT)
1318 {
1319 vAdd.push_back(addr);
1320 found++;
1321 }
a6a5bb7c 1322 }
f684aec4 1323 }
0e4b3175 1324 addrman.Add(vAdd, CNetAddr(seed.name, true));
f684aec4
JG
1325 }
1326 }
1327
881a85a2 1328 LogPrintf("%d addresses found from DNS seeds\n", found);
f684aec4 1329}
0a61b0df 1330
1331
5fee401f
PW
1332void DumpAddresses()
1333{
51ed9ec9 1334 int64_t nStart = GetTimeMillis();
928d3a01 1335
5fee401f 1336 CAddrDB adb;
928d3a01
JG
1337 adb.Write(addrman);
1338
f48742c2 1339 LogPrint("net", "Flushed %d addresses to peers.dat %dms\n",
928d3a01 1340 addrman.size(), GetTimeMillis() - nStart);
5fee401f 1341}
0a61b0df 1342
478b01d9
PW
1343void static ProcessOneShot()
1344{
1345 string strDest;
1346 {
1347 LOCK(cs_vOneShots);
1348 if (vOneShots.empty())
1349 return;
1350 strDest = vOneShots.front();
1351 vOneShots.pop_front();
1352 }
1353 CAddress addr;
c59abe25
PW
1354 CSemaphoreGrant grant(*semOutbound, true);
1355 if (grant) {
1356 if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true))
1357 AddOneShot(strDest);
1358 }
478b01d9
PW
1359}
1360
21eb5ada 1361void ThreadOpenConnections()
0a61b0df 1362{
0a61b0df 1363 // Connect to specific addresses
f161a2c2 1364 if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
0a61b0df 1365 {
51ed9ec9 1366 for (int64_t nLoop = 0;; nLoop++)
0a61b0df 1367 {
478b01d9 1368 ProcessOneShot();
db954a65 1369 BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"])
0a61b0df 1370 {
478b01d9 1371 CAddress addr;
c59abe25 1372 OpenNetworkConnection(addr, NULL, strAddr.c_str());
0a61b0df 1373 for (int i = 0; i < 10 && i < nLoop; i++)
1374 {
1b43bf0d 1375 MilliSleep(500);
0a61b0df 1376 }
1377 }
1b43bf0d 1378 MilliSleep(500);
0a61b0df 1379 }
1380 }
1381
0a61b0df 1382 // Initiate network connections
51ed9ec9 1383 int64_t nStart = GetTime();
050d2e95 1384 while (true)
0a61b0df 1385 {
478b01d9
PW
1386 ProcessOneShot();
1387
1b43bf0d 1388 MilliSleep(500);
cc201e01 1389
c59abe25 1390 CSemaphoreGrant grant(*semOutbound);
21eb5ada 1391 boost::this_thread::interruption_point();
0a61b0df 1392
0e4b3175 1393 // Add seed nodes if DNS seeds are all down (an infrastructure attack?).
a671a00f 1394 // if (addrman.size() == 0 && (GetTime() - nStart > 60)) {
1395 if (GetTime() - nStart > 60) {
0e4b3175
MH
1396 static bool done = false;
1397 if (!done) {
a671a00f 1398 //LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n");
1399 LogPrintf("Adding fixed seed nodes.\n");
739d6155 1400 addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1"));
0e4b3175 1401 done = true;
0a61b0df 1402 }
1403 }
1404
0a61b0df 1405 //
1406 // Choose an address to connect to based on most recently seen
1407 //
1408 CAddress addrConnect;
0a61b0df 1409
19521acf 1410 // Only connect out to one peer per network group (/16 for IPv4).
0a61b0df 1411 // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
c59abe25 1412 int nOutbound = 0;
67a42f92 1413 set<vector<unsigned char> > setConnected;
f8dcd5ca
PW
1414 {
1415 LOCK(cs_vNodes);
c59abe25 1416 BOOST_FOREACH(CNode* pnode, vNodes) {
19521acf
GM
1417 if (!pnode->fInbound) {
1418 setConnected.insert(pnode->addr.GetGroup());
c59abe25 1419 nOutbound++;
19521acf 1420 }
c59abe25 1421 }
f8dcd5ca 1422 }
0a61b0df 1423
51ed9ec9 1424 int64_t nANow = GetAdjustedTime();
a4e6ae10 1425
5fee401f 1426 int nTries = 0;
050d2e95 1427 while (true)
0a61b0df 1428 {
1d5b47a9 1429 CAddrInfo addr = addrman.Select();
0a61b0df 1430
5fee401f 1431 // if we selected an invalid address, restart
23aa78c4 1432 if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
5fee401f 1433 break;
0a61b0df 1434
f161a2c2
PW
1435 // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
1436 // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
1437 // already-connected network ranges, ...) before trying new addrman addresses.
5fee401f 1438 nTries++;
f161a2c2
PW
1439 if (nTries > 100)
1440 break;
0a61b0df 1441
457754d2
PW
1442 if (IsLimited(addr))
1443 continue;
1444
5fee401f
PW
1445 // only consider very recently tried nodes after 30 failed attempts
1446 if (nANow - addr.nLastTry < 600 && nTries < 30)
1447 continue;
1448
1449 // do not allow non-default ports, unless after 50 invalid addresses selected already
0e4b3175 1450 if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50)
5fee401f
PW
1451 continue;
1452
1453 addrConnect = addr;
1454 break;
0a61b0df 1455 }
1456
1457 if (addrConnect.IsValid())
c59abe25 1458 OpenNetworkConnection(addrConnect, &grant);
0a61b0df 1459 }
1460}
1461
21eb5ada 1462void ThreadOpenAddedConnections()
b24e6e4d 1463{
74088e86
MC
1464 {
1465 LOCK(cs_vAddedNodes);
1466 vAddedNodes = mapMultiArgs["-addnode"];
1467 }
b24e6e4d 1468
81bbef26 1469 if (HaveNameProxy()) {
21eb5ada 1470 while(true) {
74088e86
MC
1471 list<string> lAddresses(0);
1472 {
1473 LOCK(cs_vAddedNodes);
db954a65 1474 BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
74088e86
MC
1475 lAddresses.push_back(strAddNode);
1476 }
db954a65 1477 BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
9bab521d 1478 CAddress addr;
c59abe25
PW
1479 CSemaphoreGrant grant(*semOutbound);
1480 OpenNetworkConnection(addr, &grant, strAddNode.c_str());
1b43bf0d 1481 MilliSleep(500);
9bab521d 1482 }
1b43bf0d 1483 MilliSleep(120000); // Retry every 2 minutes
9bab521d 1484 }
9bab521d
PW
1485 }
1486
f2bd6c28 1487 for (unsigned int i = 0; true; i++)
b24e6e4d 1488 {
74088e86
MC
1489 list<string> lAddresses(0);
1490 {
1491 LOCK(cs_vAddedNodes);
db954a65 1492 BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
74088e86
MC
1493 lAddresses.push_back(strAddNode);
1494 }
1495
1496 list<vector<CService> > lservAddressesToAdd(0);
db954a65 1497 BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
74088e86 1498 vector<CService> vservNode(0);
0e4b3175 1499 if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
f8dcd5ca 1500 {
74088e86
MC
1501 lservAddressesToAdd.push_back(vservNode);
1502 {
1503 LOCK(cs_setservAddNodeAddresses);
db954a65 1504 BOOST_FOREACH(const CService& serv, vservNode)
74088e86
MC
1505 setservAddNodeAddresses.insert(serv);
1506 }
f8dcd5ca 1507 }
b24e6e4d 1508 }
b24e6e4d 1509 // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
9bab521d 1510 // (keeping in mind that addnode entries can have many IPs if fNameLookup)
f8dcd5ca
PW
1511 {
1512 LOCK(cs_vNodes);
b24e6e4d 1513 BOOST_FOREACH(CNode* pnode, vNodes)
74088e86 1514 for (list<vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
db954a65 1515 BOOST_FOREACH(const CService& addrNode, *(it))
b24e6e4d
MC
1516 if (pnode->addr == addrNode)
1517 {
74088e86 1518 it = lservAddressesToAdd.erase(it);
b24e6e4d
MC
1519 it--;
1520 break;
1521 }
f8dcd5ca 1522 }
74088e86 1523 BOOST_FOREACH(vector<CService>& vserv, lservAddressesToAdd)
b24e6e4d 1524 {
c59abe25 1525 CSemaphoreGrant grant(*semOutbound);
f2bd6c28 1526 OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
1b43bf0d 1527 MilliSleep(500);
b24e6e4d 1528 }
1b43bf0d 1529 MilliSleep(120000); // Retry every 2 minutes
b24e6e4d
MC
1530 }
1531}
1532
814efd6f 1533// if successful, this moves the passed grant to the constructed node
5bd6c31b 1534bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
0a61b0df 1535{
1536 //
1537 // Initiate outbound network connection
1538 //
21eb5ada 1539 boost::this_thread::interruption_point();
5bd6c31b 1540 if (!pszDest) {
39857190
PW
1541 if (IsLocal(addrConnect) ||
1542 FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
f469f79f 1543 FindNode(addrConnect.ToStringIPPort()))
9bab521d 1544 return false;
49b22928 1545 } else if (FindNode(std::string(pszDest)))
0a61b0df 1546 return false;
1547
5bd6c31b 1548 CNode* pnode = ConnectNode(addrConnect, pszDest);
21eb5ada
GA
1549 boost::this_thread::interruption_point();
1550
0a61b0df 1551 if (!pnode)
1552 return false;
c59abe25
PW
1553 if (grantOutbound)
1554 grantOutbound->MoveTo(pnode->grantOutbound);
0a61b0df 1555 pnode->fNetworkNode = true;
478b01d9
PW
1556 if (fOneShot)
1557 pnode->fOneShot = true;
0a61b0df 1558
0a61b0df 1559 return true;
1560}
1561
1562
21eb5ada 1563void ThreadMessageHandler()
0a61b0df 1564{
351593b9 1565 boost::mutex condition_mutex;
1566 boost::unique_lock<boost::mutex> lock(condition_mutex);
49b22928 1567
0a61b0df 1568 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
21eb5ada 1569 while (true)
0a61b0df 1570 {
1571 vector<CNode*> vNodesCopy;
0a61b0df 1572 {
f8dcd5ca 1573 LOCK(cs_vNodes);
0a61b0df 1574 vNodesCopy = vNodes;
6ed71b5e 1575 BOOST_FOREACH(CNode* pnode, vNodesCopy) {
0a61b0df 1576 pnode->AddRef();
6ed71b5e 1577 }
0a61b0df 1578 }
1579
1580 // Poll the connected nodes for messages
1581 CNode* pnodeTrickle = NULL;
1582 if (!vNodesCopy.empty())
1583 pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
fabba0e6 1584
75ef87dd 1585 bool fSleep = true;
fabba0e6 1586
223b6f1b 1587 BOOST_FOREACH(CNode* pnode, vNodesCopy)
0a61b0df 1588 {
967f2459
PW
1589 if (pnode->fDisconnect)
1590 continue;
1591
0a61b0df 1592 // Receive messages
f8dcd5ca 1593 {
607dbfde 1594 TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
f8dcd5ca 1595 if (lockRecv)
75ef87dd 1596 {
501da250 1597 if (!g_signals.ProcessMessages(pnode))
607dbfde 1598 pnode->CloseSocketDisconnect();
fabba0e6 1599
75ef87dd
PS
1600 if (pnode->nSendSize < SendBufferSize())
1601 {
1602 if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg[0].complete()))
1603 {
1604 fSleep = false;
1605 }
1606 }
1607 }
f8dcd5ca 1608 }
21eb5ada 1609 boost::this_thread::interruption_point();
0a61b0df 1610
1611 // Send messages
f8dcd5ca
PW
1612 {
1613 TRY_LOCK(pnode->cs_vSend, lockSend);
501da250 1614 if (lockSend)
fc720207 1615 g_signals.SendMessages(pnode, pnode == pnodeTrickle || pnode->fWhitelisted);
f8dcd5ca 1616 }
21eb5ada 1617 boost::this_thread::interruption_point();
0a61b0df 1618 }
1619
0a61b0df 1620 {
f8dcd5ca 1621 LOCK(cs_vNodes);
223b6f1b 1622 BOOST_FOREACH(CNode* pnode, vNodesCopy)
0a61b0df 1623 pnode->Release();
1624 }
fabba0e6 1625
75ef87dd 1626 if (fSleep)
351593b9 1627 messageHandlerCondition.timed_wait(lock, boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(100));
0a61b0df 1628 }
1629}
1630
1631
dc942e6f 1632bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted)
0a61b0df 1633{
1634 strError = "";
1635 int nOne = 1;
1636
0a61b0df 1637 // Create socket for listening for incoming connections
8f10a288 1638 struct sockaddr_storage sockaddr;
8f10a288
PW
1639 socklen_t len = sizeof(sockaddr);
1640 if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
1641 {
5bd6c31b 1642 strError = strprintf("Error: Bind address family for %s not supported", addrBind.ToString());
7d9d134b 1643 LogPrintf("%s\n", strError);
8f10a288
PW
1644 return false;
1645 }
1646
1647 SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
0a61b0df 1648 if (hListenSocket == INVALID_SOCKET)
1649 {
a60838d0 1650 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()));
7d9d134b 1651 LogPrintf("%s\n", strError);
0a61b0df 1652 return false;
1653 }
0095b9a1
PW
1654 if (!IsSelectableSocket(hListenSocket))
1655 {
1656 strError = "Error: Couldn't create a listenable socket for incoming connections";
1657 LogPrintf("%s\n", strError);
1658 return false;
1659 }
1660
0a61b0df 1661
9cb1ec9c 1662#ifndef _WIN32
ec93a0e2 1663#ifdef SO_NOSIGPIPE
0a61b0df 1664 // Different way of disabling SIGPIPE on BSD
1665 setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
1666#endif
0a61b0df 1667 // Allow binding if the port is still in TIME_WAIT state after
ccc4ad6c 1668 // the program was closed and restarted.
0a61b0df 1669 setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
95a50390
GM
1670 // Disable Nagle's algorithm
1671 setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int));
ccc4ad6c
CF
1672#else
1673 setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int));
95a50390 1674 setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int));
0a61b0df 1675#endif
1676
814efd6f 1677 // Set to non-blocking, incoming connections will also inherit this
eaedb59e
PK
1678 if (!SetSocketNonBlocking(hListenSocket, true)) {
1679 strError = strprintf("BindListenPort: Setting listening socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
7d9d134b 1680 LogPrintf("%s\n", strError);
0a61b0df 1681 return false;
1682 }
1683
8f10a288
PW
1684 // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
1685 // and enable it by default or not. Try to enable it, if possible.
1686 if (addrBind.IsIPv6()) {
1687#ifdef IPV6_V6ONLY
9cb1ec9c 1688#ifdef _WIN32
b3e0aaf3
PK
1689 setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int));
1690#else
8f10a288 1691 setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
23aa78c4 1692#endif
b3e0aaf3 1693#endif
9cb1ec9c 1694#ifdef _WIN32
9e9ca2b6
PK
1695 int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
1696 setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
8f10a288
PW
1697#endif
1698 }
8f10a288
PW
1699
1700 if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
0a61b0df 1701 {
1702 int nErr = WSAGetLastError();
1703 if (nErr == WSAEADDRINUSE)
b30900a5 1704 strError = strprintf(_("Unable to bind to %s on this computer. Zcash is probably already running."), addrBind.ToString());
0a61b0df 1705 else
a60838d0 1706 strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
7d9d134b 1707 LogPrintf("%s\n", strError);
c994d2e7 1708 CloseSocket(hListenSocket);
0a61b0df 1709 return false;
1710 }
7d9d134b 1711 LogPrintf("Bound to %s\n", addrBind.ToString());
0a61b0df 1712
1713 // Listen for incoming connections
1714 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1715 {
a60838d0 1716 strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
7d9d134b 1717 LogPrintf("%s\n", strError);
c994d2e7 1718 CloseSocket(hListenSocket);
0a61b0df 1719 return false;
1720 }
1721
dc942e6f 1722 vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
8f10a288 1723
dc942e6f 1724 if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
8f10a288
PW
1725 AddLocal(addrBind, LOCAL_BIND);
1726
0a61b0df 1727 return true;
1728}
1729
80ecf670 1730void static Discover(boost::thread_group& threadGroup)
0a61b0df 1731{
587f929c 1732 if (!fDiscover)
19b6958c 1733 return;
0a61b0df 1734
9cb1ec9c 1735#ifdef _WIN32
814efd6f 1736 // Get local host IP
cd4d3f19 1737 char pszHostName[256] = "";
0a61b0df 1738 if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1739 {
67a42f92
PW
1740 vector<CNetAddr> vaddr;
1741 if (LookupHost(pszHostName, vaddr))
f8e4d43b 1742 {
67a42f92 1743 BOOST_FOREACH (const CNetAddr &addr, vaddr)
f8e4d43b 1744 {
8fa0494e
PK
1745 if (AddLocal(addr, LOCAL_IF))
1746 LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToString());
f8e4d43b
PK
1747 }
1748 }
0a61b0df 1749 }
1750#else
1751 // Get local host ip
1752 struct ifaddrs* myaddrs;
1753 if (getifaddrs(&myaddrs) == 0)
1754 {
1755 for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1756 {
1757 if (ifa->ifa_addr == NULL) continue;
1758 if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1759 if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1760 if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
0a61b0df 1761 if (ifa->ifa_addr->sa_family == AF_INET)
1762 {
1763 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
39857190 1764 CNetAddr addr(s4->sin_addr);
23aa78c4 1765 if (AddLocal(addr, LOCAL_IF))
8fa0494e 1766 LogPrintf("%s: IPv4 %s: %s\n", __func__, ifa->ifa_name, addr.ToString());
0a61b0df 1767 }
1768 else if (ifa->ifa_addr->sa_family == AF_INET6)
1769 {
1770 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
39857190 1771 CNetAddr addr(s6->sin6_addr);
23aa78c4 1772 if (AddLocal(addr, LOCAL_IF))
8fa0494e 1773 LogPrintf("%s: IPv6 %s: %s\n", __func__, ifa->ifa_name, addr.ToString());
0a61b0df 1774 }
1775 }
1776 freeifaddrs(myaddrs);
1777 }
1778#endif
19b6958c
PW
1779}
1780
9a1dcea2 1781void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
19b6958c 1782{
94064710
WL
1783 uiInterface.InitMessage(_("Loading addresses..."));
1784 // Load addresses for peers.dat
1785 int64_t nStart = GetTimeMillis();
1786 {
1787 CAddrDB adb;
1788 if (!adb.Read(addrman))
1789 LogPrintf("Invalid or missing peers.dat; recreating\n");
1790 }
1791 LogPrintf("Loaded %i addresses from peers.dat %dms\n",
1792 addrman.size(), GetTimeMillis() - nStart);
1793 fAddressesInitialized = true;
1794
c59abe25
PW
1795 if (semOutbound == NULL) {
1796 // initialize semaphore
ba29a559 1797 int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
c59abe25
PW
1798 semOutbound = new CSemaphore(nMaxOutbound);
1799 }
1800
19b6958c
PW
1801 if (pnodeLocalHost == NULL)
1802 pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
1803
80ecf670 1804 Discover(threadGroup);
0a61b0df 1805
1806 //
1807 // Start threads
1808 //
1809
9d952d17 1810 if (!GetBoolArg("-dnsseed", true))
881a85a2 1811 LogPrintf("DNS seeding disabled\n");
2bc6cece 1812 else
53e71135 1813 threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "dnsseed", &ThreadDNSAddressSeed));
2bc6cece 1814
0a61b0df 1815 // Send and receive from sockets, accept connections
b31499ec 1816 threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "net", &ThreadSocketHandler));
0a61b0df 1817
b24e6e4d 1818 // Initiate outbound connections from -addnode
b31499ec 1819 threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "addcon", &ThreadOpenAddedConnections));
b24e6e4d 1820
0a61b0df 1821 // Initiate outbound connections
b31499ec 1822 threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "opencon", &ThreadOpenConnections));
0a61b0df 1823
1824 // Process messages
b31499ec 1825 threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler));
0a61b0df 1826
5fee401f 1827 // Dump network addresses
9a1dcea2 1828 scheduler.scheduleEvery(&DumpAddresses, DUMP_ADDRESSES_INTERVAL);
0a61b0df 1829}
1830
1831bool StopNode()
1832{
881a85a2 1833 LogPrintf("StopNode()\n");
89b5616d
PW
1834 if (semOutbound)
1835 for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
1836 semOutbound->post();
94064710
WL
1837
1838 if (fAddressesInitialized)
1839 {
1840 DumpAddresses();
1841 fAddressesInitialized = false;
1842 }
3427517d 1843
0a61b0df 1844 return true;
1845}
1846
39d2e9e0 1847static class CNetCleanup
0a61b0df 1848{
1849public:
5bd6c31b
PK
1850 CNetCleanup() {}
1851
0a61b0df 1852 ~CNetCleanup()
1853 {
1854 // Close sockets
223b6f1b 1855 BOOST_FOREACH(CNode* pnode, vNodes)
0a61b0df 1856 if (pnode->hSocket != INVALID_SOCKET)
43f510d3 1857 CloseSocket(pnode->hSocket);
dc942e6f
PW
1858 BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
1859 if (hListenSocket.socket != INVALID_SOCKET)
43f510d3
WL
1860 if (!CloseSocket(hListenSocket.socket))
1861 LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
0a61b0df 1862
3427517d
PW
1863 // clean up some globals (to help leak detection)
1864 BOOST_FOREACH(CNode *pnode, vNodes)
1865 delete pnode;
1866 BOOST_FOREACH(CNode *pnode, vNodesDisconnected)
1867 delete pnode;
1868 vNodes.clear();
1869 vNodesDisconnected.clear();
3dc1464f 1870 vhListenSocket.clear();
3427517d
PW
1871 delete semOutbound;
1872 semOutbound = NULL;
1873 delete pnodeLocalHost;
1874 pnodeLocalHost = NULL;
1875
9cb1ec9c 1876#ifdef _WIN32
0a61b0df 1877 // Shutdown Windows Sockets
1878 WSACleanup();
1879#endif
1880 }
1881}
1882instance_of_cnetcleanup;
269d9c64 1883
d38da59b 1884void RelayTransaction(const CTransaction& tx)
269d9c64
MC
1885{
1886 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
1887 ss.reserve(10000);
1888 ss << tx;
d38da59b 1889 RelayTransaction(tx, ss);
269d9c64
MC
1890}
1891
d38da59b 1892void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
269d9c64 1893{
805344dc 1894 CInv inv(MSG_TX, tx.GetHash());
269d9c64
MC
1895 {
1896 LOCK(cs_mapRelay);
1897 // Expire old relay messages
1898 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
1899 {
1900 mapRelay.erase(vRelayExpiration.front().second);
1901 vRelayExpiration.pop_front();
1902 }
1903
1904 // Save original serialized message so newer versions are preserved
1905 mapRelay.insert(std::make_pair(inv, ss));
1906 vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
1907 }
1908 LOCK(cs_vNodes);
1909 BOOST_FOREACH(CNode* pnode, vNodes)
1910 {
4c8fc1a5
MC
1911 if(!pnode->fRelayTxes)
1912 continue;
269d9c64
MC
1913 LOCK(pnode->cs_filter);
1914 if (pnode->pfilter)
1915 {
d38da59b 1916 if (pnode->pfilter->IsRelevantAndUpdate(tx))
269d9c64
MC
1917 pnode->PushInventory(inv);
1918 } else
1919 pnode->PushInventory(inv);
1920 }
1921}
ce14345a 1922
51ed9ec9 1923void CNode::RecordBytesRecv(uint64_t bytes)
ce14345a
SE
1924{
1925 LOCK(cs_totalBytesRecv);
1926 nTotalBytesRecv += bytes;
1927}
1928
51ed9ec9 1929void CNode::RecordBytesSent(uint64_t bytes)
ce14345a
SE
1930{
1931 LOCK(cs_totalBytesSent);
1932 nTotalBytesSent += bytes;
1933}
1934
51ed9ec9 1935uint64_t CNode::GetTotalBytesRecv()
ce14345a
SE
1936{
1937 LOCK(cs_totalBytesRecv);
1938 return nTotalBytesRecv;
1939}
1940
51ed9ec9 1941uint64_t CNode::GetTotalBytesSent()
ce14345a
SE
1942{
1943 LOCK(cs_totalBytesSent);
1944 return nTotalBytesSent;
1945}
9038b18f
GA
1946
1947void CNode::Fuzz(int nChance)
1948{
1949 if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake
1950 if (GetRand(nChance) != 0) return; // Fuzz 1 of every nChance messages
1951
1952 switch (GetRand(3))
1953 {
1954 case 0:
1955 // xor a random byte with a random value:
1956 if (!ssSend.empty()) {
1957 CDataStream::size_type pos = GetRand(ssSend.size());
1958 ssSend[pos] ^= (unsigned char)(GetRand(256));
1959 }
1960 break;
1961 case 1:
1962 // delete a random byte:
1963 if (!ssSend.empty()) {
1964 CDataStream::size_type pos = GetRand(ssSend.size());
1965 ssSend.erase(ssSend.begin()+pos);
1966 }
1967 break;
1968 case 2:
1969 // insert a random byte at a random position
1970 {
1971 CDataStream::size_type pos = GetRand(ssSend.size());
1972 char ch = (char)GetRand(256);
1973 ssSend.insert(ssSend.begin()+pos, ch);
1974 }
1975 break;
1976 }
1977 // Chance of more than one change half the time:
1978 // (more changes exponentially less likely):
1979 Fuzz(2);
1980}
d004d727
WL
1981
1982//
1983// CAddrDB
1984//
1985
1986CAddrDB::CAddrDB()
1987{
1988 pathAddr = GetDataDir() / "peers.dat";
1989}
1990
1991bool CAddrDB::Write(const CAddrMan& addr)
1992{
1993 // Generate random temporary filename
1994 unsigned short randv = 0;
001a53d7 1995 GetRandBytes((unsigned char*)&randv, sizeof(randv));
d004d727
WL
1996 std::string tmpfn = strprintf("peers.dat.%04x", randv);
1997
1998 // serialize addresses, checksum data up to that point, then append csum
1999 CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
2000 ssPeers << FLATDATA(Params().MessageStart());
2001 ssPeers << addr;
2002 uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
2003 ssPeers << hash;
2004
2005 // open temp output file, and associate with CAutoFile
2006 boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
2007 FILE *file = fopen(pathTmp.string().c_str(), "wb");
eee030f6 2008 CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
fef24cab 2009 if (fileout.IsNull())
5262fde0 2010 return error("%s: Failed to open file %s", __func__, pathTmp.string());
d004d727
WL
2011
2012 // Write and commit header, data
2013 try {
2014 fileout << ssPeers;
2015 }
27df4123 2016 catch (const std::exception& e) {
5262fde0 2017 return error("%s: Serialize or I/O error - %s", __func__, e.what());
d004d727 2018 }
a8738238 2019 FileCommit(fileout.Get());
d004d727
WL
2020 fileout.fclose();
2021
2022 // replace existing peers.dat, if any, with new peers.dat.XXXX
2023 if (!RenameOver(pathTmp, pathAddr))
5262fde0 2024 return error("%s: Rename-into-place failed", __func__);
d004d727
WL
2025
2026 return true;
2027}
2028
2029bool CAddrDB::Read(CAddrMan& addr)
2030{
2031 // open input file, and associate with CAutoFile
2032 FILE *file = fopen(pathAddr.string().c_str(), "rb");
eee030f6 2033 CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
fef24cab 2034 if (filein.IsNull())
5262fde0 2035 return error("%s: Failed to open file %s", __func__, pathAddr.string());
d004d727
WL
2036
2037 // use file size to size memory buffer
a486abd4 2038 int fileSize = boost::filesystem::file_size(pathAddr);
d004d727 2039 int dataSize = fileSize - sizeof(uint256);
a486abd4 2040 // Don't try to resize to a negative number if file is small
2fdd4c79
PK
2041 if (dataSize < 0)
2042 dataSize = 0;
d004d727
WL
2043 vector<unsigned char> vchData;
2044 vchData.resize(dataSize);
2045 uint256 hashIn;
2046
2047 // read data and checksum from file
2048 try {
2049 filein.read((char *)&vchData[0], dataSize);
2050 filein >> hashIn;
2051 }
27df4123 2052 catch (const std::exception& e) {
5262fde0 2053 return error("%s: Deserialize or I/O error - %s", __func__, e.what());
d004d727
WL
2054 }
2055 filein.fclose();
2056
2057 CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
2058
2059 // verify stored checksum matches input data
2060 uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
2061 if (hashIn != hashTmp)
5262fde0 2062 return error("%s: Checksum mismatch, data corrupted", __func__);
d004d727
WL
2063
2064 unsigned char pchMsgTmp[4];
2065 try {
2066 // de-serialize file header (network specific magic number) and ..
2067 ssPeers >> FLATDATA(pchMsgTmp);
2068
2069 // ... verify the network matches ours
2070 if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
5262fde0 2071 return error("%s: Invalid network magic number", __func__);
d004d727
WL
2072
2073 // de-serialize address data into one CAddrMan object
2074 ssPeers >> addr;
2075 }
27df4123 2076 catch (const std::exception& e) {
5262fde0 2077 return error("%s: Deserialize or I/O error - %s", __func__, e.what());
d004d727
WL
2078 }
2079
2080 return true;
2081}
651480c8
WL
2082
2083unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
2084unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
2085
db954a65 2086CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
d4d5022c 2087 ssSend(SER_NETWORK, INIT_PROTO_VERSION),
83671efe 2088 addrKnown(5000, 0.001),
d4d5022c 2089 setInventoryKnown(SendBufferSize() / 1000)
651480c8
WL
2090{
2091 nServices = 0;
2092 hSocket = hSocketIn;
2093 nRecvVersion = INIT_PROTO_VERSION;
2094 nLastSend = 0;
2095 nLastRecv = 0;
2096 nSendBytes = 0;
2097 nRecvBytes = 0;
2098 nTimeConnected = GetTime();
26a6bae7 2099 nTimeOffset = 0;
651480c8
WL
2100 addr = addrIn;
2101 addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
2102 nVersion = 0;
2103 strSubVer = "";
2104 fWhitelisted = false;
2105 fOneShot = false;
2106 fClient = false; // set by version message
2107 fInbound = fInboundIn;
2108 fNetworkNode = false;
2109 fSuccessfullyConnected = false;
2110 fDisconnect = false;
2111 nRefCount = 0;
2112 nSendSize = 0;
2113 nSendOffset = 0;
4f152496 2114 hashContinue = uint256();
651480c8 2115 nStartingHeight = -1;
651480c8
WL
2116 fGetAddr = false;
2117 fRelayTxes = false;
a514cb29 2118 fSentAddr = false;
651480c8
WL
2119 pfilter = new CBloomFilter();
2120 nPingNonceSent = 0;
2121 nPingUsecStart = 0;
2122 nPingUsecTime = 0;
2123 fPingQueued = false;
9dcea38a 2124 nMinPingUsecTime = std::numeric_limits<int64_t>::max();
651480c8
WL
2125
2126 {
2127 LOCK(cs_nLastNodeId);
2128 id = nLastNodeId++;
2129 }
2130
2131 if (fLogIPs)
2132 LogPrint("net", "Added connection to %s peer=%d\n", addrName, id);
2133 else
2134 LogPrint("net", "Added connection peer=%d\n", id);
2135
2136 // Be shy and don't send version until we hear
2137 if (hSocket != INVALID_SOCKET && !fInbound)
2138 PushVersion();
2139
2140 GetNodeSignals().InitializeNode(GetId(), this);
2141}
2142
2143CNode::~CNode()
2144{
2145 CloseSocket(hSocket);
2146
2147 if (pfilter)
2148 delete pfilter;
2149
2150 GetNodeSignals().FinalizeNode(GetId());
2151}
2152
2153void CNode::AskFor(const CInv& inv)
2154{
e2190f80 2155 if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ)
d4168c82 2156 return;
e2190f80 2157 // a peer may not have multiple non-responded queue positions for a single inv item
56f165bd 2158 if (!setAskFor.insert(inv.hash).second)
2159 return;
2160
651480c8
WL
2161 // We're using mapAskFor as a priority queue,
2162 // the key is the earliest time the request can be sent
2163 int64_t nRequestTime;
2164 limitedmap<CInv, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv);
2165 if (it != mapAlreadyAskedFor.end())
2166 nRequestTime = it->second;
2167 else
2168 nRequestTime = 0;
2c2cc5da 2169 LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000), id);
651480c8
WL
2170
2171 // Make sure not to reuse time indexes to keep things in the same order
2172 int64_t nNow = GetTimeMicros() - 1000000;
2173 static int64_t nLastTime;
2174 ++nLastTime;
2175 nNow = std::max(nNow, nLastTime);
2176 nLastTime = nNow;
2177
2178 // Each retry is 2 minutes after the last
2179 nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
2180 if (it != mapAlreadyAskedFor.end())
2181 mapAlreadyAskedFor.update(it, nRequestTime);
2182 else
2183 mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime));
2184 mapAskFor.insert(std::make_pair(nRequestTime, inv));
2185}
2186
2187void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend)
2188{
2189 ENTER_CRITICAL_SECTION(cs_vSend);
2190 assert(ssSend.size() == 0);
eec37136 2191 ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0);
28d4cff0 2192 LogPrint("net", "sending: %s ", SanitizeString(pszCommand));
651480c8
WL
2193}
2194
2195void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
2196{
2197 ssSend.clear();
2198
2199 LEAVE_CRITICAL_SECTION(cs_vSend);
2200
2201 LogPrint("net", "(aborted)\n");
2202}
2203
2204void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
2205{
2206 // The -*messagestest options are intentionally not documented in the help message,
2207 // since they are only used during development to debug the networking code and are
2208 // not intended for end-users.
2209 if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0)
2210 {
2211 LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n");
2212 AbortMessage();
2213 return;
2214 }
2215 if (mapArgs.count("-fuzzmessagestest"))
2216 Fuzz(GetArg("-fuzzmessagestest", 10));
2217
2218 if (ssSend.size() == 0)
60457d3c
CF
2219 {
2220 LEAVE_CRITICAL_SECTION(cs_vSend);
651480c8 2221 return;
60457d3c 2222 }
651480c8
WL
2223 // Set the size
2224 unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
dec84cae 2225 WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
651480c8
WL
2226
2227 // Set the checksum
2228 uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
2229 unsigned int nChecksum = 0;
2230 memcpy(&nChecksum, &hash, sizeof(nChecksum));
2231 assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
2232 memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum));
2233
2234 LogPrint("net", "(%d bytes) peer=%d\n", nSize, id);
2235
2236 std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData());
2237 ssSend.GetAndClear(*it);
2238 nSendSize += (*it).size();
2239
2240 // If write queue empty, attempt "optimistic write"
2241 if (it == vSendMsg.begin())
2242 SocketSendData(this);
2243
2244 LEAVE_CRITICAL_SECTION(cs_vSend);
2245}
This page took 0.792261 seconds and 4 git commands to generate.