fix "List iterator not dereferencable" and
[novacoin.git] / src / net.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "irc.h"
7 #include "db.h"
8 #include "net.h"
9 #include "init.h"
10 #include "strlcpy.h"
11 #include "addrman.h"
12 #include "ui_interface.h"
13
14 #ifdef WIN32
15 #include <string.h>
16 #endif
17
18 #ifdef USE_UPNP
19 #include <miniupnpc/miniwget.h>
20 #include <miniupnpc/miniupnpc.h>
21 #include <miniupnpc/upnpcommands.h>
22 #include <miniupnpc/upnperrors.h>
23 #endif
24
25 using namespace std;
26 using namespace boost;
27
28 static const int MAX_OUTBOUND_CONNECTIONS = 16;
29
30 void ThreadMessageHandler2(void* parg);
31 void ThreadSocketHandler2(void* parg);
32 void ThreadOpenConnections2(void* parg);
33 void ThreadOpenAddedConnections2(void* parg);
34 #ifdef USE_UPNP
35 void ThreadMapPort2(void* parg);
36 #endif
37 void ThreadDNSAddressSeed2(void* parg);
38
39 struct LocalServiceInfo {
40     int nScore;
41     int nPort;
42 };
43
44 //
45 // Global state variables
46 //
47 bool fClient = false;
48 bool fDiscover = true;
49 bool fUseUPnP = false;
50 uint64_t nLocalServices = (fClient ? 0 : NODE_NETWORK);
51 static CCriticalSection cs_mapLocalHost;
52 static map<CNetAddr, LocalServiceInfo> mapLocalHost;
53 static bool vfReachable[NET_MAX] = {};
54 static bool vfLimited[NET_MAX] = {};
55 static CNode* pnodeLocalHost = NULL;
56 static CNode* pnodeSync = NULL;
57 CAddress addrSeenByPeer(CService("0.0.0.0", 0), nLocalServices);
58 uint64_t nLocalHostNonce = 0;
59 boost::array<int, THREAD_MAX> vnThreadsRunning;
60 static std::vector<SOCKET> vhListenSocket;
61 CAddrMan addrman;
62
63 vector<CNode*> vNodes;
64 CCriticalSection cs_vNodes;
65 map<CInv, CDataStream> mapRelay;
66 deque<pair<int64_t, CInv> > vRelayExpiration;
67 CCriticalSection cs_mapRelay;
68 map<CInv, int64_t> mapAlreadyAskedFor;
69
70 static deque<string> vOneShots;
71 CCriticalSection cs_vOneShots;
72
73 set<CNetAddr> setservAddNodeAddresses;
74 CCriticalSection cs_setservAddNodeAddresses;
75
76 vector<std::string> vAddedNodes;
77 CCriticalSection cs_vAddedNodes;
78
79 static CSemaphore *semOutbound = NULL;
80
81 void AddOneShot(string strDest)
82 {
83     LOCK(cs_vOneShots);
84     vOneShots.push_back(strDest);
85 }
86
87 unsigned short GetListenPort()
88 {
89     return (unsigned short)(GetArg("-port", GetDefaultPort()));
90 }
91
92 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
93 {
94     // Filter out duplicate requests
95     if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
96         return;
97     pindexLastGetBlocksBegin = pindexBegin;
98     hashLastGetBlocksEnd = hashEnd;
99
100     PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
101 }
102
103 // find 'best' local address for a particular peer
104 bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
105 {
106     if (fNoListen)
107         return false;
108
109     int nBestScore = -1;
110     int nBestReachability = -1;
111     {
112         LOCK(cs_mapLocalHost);
113         for (map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
114         {
115             int nScore = (*it).second.nScore;
116             int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
117             if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
118             {
119                 addr = CService((*it).first, (*it).second.nPort);
120                 nBestReachability = nReachability;
121                 nBestScore = nScore;
122             }
123         }
124     }
125     return nBestScore >= 0;
126 }
127
128 // get best local address for a particular peer as a CAddress
129 CAddress GetLocalAddress(const CNetAddr *paddrPeer)
130 {
131     CAddress ret(CService("0.0.0.0",0),0);
132     CService addr;
133     if (GetLocal(addr, paddrPeer))
134     {
135         ret = CAddress(addr);
136         ret.nServices = nLocalServices;
137         ret.nTime = GetAdjustedTime();
138     }
139     return ret;
140 }
141
142 bool RecvLine(SOCKET hSocket, string& strLine)
143 {
144     strLine = "";
145     while (true)
146     {
147         char c;
148         int nBytes = recv(hSocket, &c, 1, 0);
149         if (nBytes > 0)
150         {
151             if (c == '\n')
152                 continue;
153             if (c == '\r')
154                 return true;
155             strLine += c;
156             if (strLine.size() >= 9000)
157                 return true;
158         }
159         else if (nBytes <= 0)
160         {
161             if (fShutdown)
162                 return false;
163             if (nBytes < 0)
164             {
165                 int nErr = WSAGetLastError();
166                 if (nErr == WSAEMSGSIZE)
167                     continue;
168                 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
169                 {
170                     Sleep(10);
171                     continue;
172                 }
173             }
174             if (!strLine.empty())
175                 return true;
176             if (nBytes == 0)
177             {
178                 // socket closed
179                 printf("socket closed\n");
180                 return false;
181             }
182             else
183             {
184                 // socket error
185                 int nErr = WSAGetLastError();
186                 printf("recv failed: %d\n", nErr);
187                 return false;
188             }
189         }
190     }
191 }
192
193 // used when scores of local addresses may have changed
194 // pushes better local address to peers
195 void static AdvertizeLocal()
196 {
197     LOCK(cs_vNodes);
198     BOOST_FOREACH(CNode* pnode, vNodes)
199     {
200         if (pnode->fSuccessfullyConnected)
201         {
202             CAddress addrLocal = GetLocalAddress(&pnode->addr);
203             if (addrLocal.IsRoutable() && (CService)addrLocal != (CService)pnode->addrLocal)
204             {
205                 pnode->PushAddress(addrLocal);
206                 pnode->addrLocal = addrLocal;
207             }
208         }
209     }
210 }
211
212 void SetReachable(enum Network net, bool fFlag)
213 {
214     LOCK(cs_mapLocalHost);
215     vfReachable[net] = fFlag;
216     if (net == NET_IPV6 && fFlag)
217         vfReachable[NET_IPV4] = true;
218 }
219
220 // learn a new local address
221 bool AddLocal(const CService& addr, int nScore)
222 {
223     if (!addr.IsRoutable())
224         return false;
225
226     if (!fDiscover && nScore < LOCAL_MANUAL)
227         return false;
228
229     if (IsLimited(addr))
230         return false;
231
232     printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore);
233
234     {
235         LOCK(cs_mapLocalHost);
236         bool fAlready = mapLocalHost.count(addr) > 0;
237         LocalServiceInfo &info = mapLocalHost[addr];
238         if (!fAlready || nScore >= info.nScore) {
239             info.nScore = nScore + (fAlready ? 1 : 0);
240             info.nPort = addr.GetPort();
241         }
242         SetReachable(addr.GetNetwork());
243     }
244
245     AdvertizeLocal();
246
247     return true;
248 }
249
250 bool AddLocal(const CNetAddr &addr, int nScore)
251 {
252     return AddLocal(CService(addr, GetListenPort()), nScore);
253 }
254
255 /** Make a particular network entirely off-limits (no automatic connects to it) */
256 void SetLimited(enum Network net, bool fLimited)
257 {
258     if (net == NET_UNROUTABLE)
259         return;
260     LOCK(cs_mapLocalHost);
261     vfLimited[net] = fLimited;
262 }
263
264 bool IsLimited(enum Network net)
265 {
266     LOCK(cs_mapLocalHost);
267     return vfLimited[net];
268 }
269
270 bool IsLimited(const CNetAddr &addr)
271 {
272     return IsLimited(addr.GetNetwork());
273 }
274
275 /** vote for a local address */
276 bool SeenLocal(const CService& addr)
277 {
278     {
279         LOCK(cs_mapLocalHost);
280         if (mapLocalHost.count(addr) == 0)
281             return false;
282         mapLocalHost[addr].nScore++;
283     }
284
285     AdvertizeLocal();
286
287     return true;
288 }
289
290 /** check whether a given address is potentially local */
291 bool IsLocal(const CService& addr)
292 {
293     LOCK(cs_mapLocalHost);
294     return mapLocalHost.count(addr) > 0;
295 }
296
297 /** check whether a given address is in a network we can probably connect to */
298 bool IsReachable(const CNetAddr& addr)
299 {
300     LOCK(cs_mapLocalHost);
301     enum Network net = addr.GetNetwork();
302     return vfReachable[net] && !vfLimited[net];
303 }
304
305 extern int GetExternalIPbySTUN(uint64_t rnd, struct sockaddr_in *mapped, const char **srv);
306
307 // We now get our external IP from the IRC server first and only use this as a backup
308 bool GetMyExternalIP(CNetAddr& ipRet)
309 {
310     struct sockaddr_in mapped;
311     uint64_t rnd = GetRand(~0LL);
312     const char *srv;
313     int rc = GetExternalIPbySTUN(rnd, &mapped, &srv);
314     if(rc >= 0) {
315         ipRet = CNetAddr(mapped.sin_addr);
316         printf("GetExternalIPbySTUN(%" PRIu64 ") returned %s in attempt %d; Server=%s\n", rnd, ipRet.ToStringIP().c_str(), rc, srv);
317         return true;
318     }
319     return false;
320 }
321
322 void ThreadGetMyExternalIP(void* parg)
323 {
324     // Make this thread recognisable as the external IP detection thread
325     RenameThread("novacoin-ext-ip");
326
327     CNetAddr addrLocalHost;
328     if (GetMyExternalIP(addrLocalHost))
329     {
330         printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
331         AddLocal(addrLocalHost, LOCAL_HTTP);
332     }
333 }
334
335
336
337
338
339 void AddressCurrentlyConnected(const CService& addr)
340 {
341     addrman.Connected(addr);
342 }
343
344
345
346
347 uint64_t CNode::nTotalBytesRecv = 0;
348 uint64_t CNode::nTotalBytesSent = 0;
349 CCriticalSection CNode::cs_totalBytesRecv;
350 CCriticalSection CNode::cs_totalBytesSent;
351
352 CNode* FindNode(const CNetAddr& ip)
353 {
354     LOCK(cs_vNodes);
355     BOOST_FOREACH(CNode* pnode, vNodes)
356         if ((CNetAddr)pnode->addr == ip)
357             return (pnode);
358     return NULL;
359 }
360
361 CNode* FindNode(std::string addrName)
362 {
363     LOCK(cs_vNodes);
364     BOOST_FOREACH(CNode* pnode, vNodes)
365         if (pnode->addrName == addrName)
366             return (pnode);
367     return NULL;
368 }
369
370 CNode* FindNode(const CService& addr)
371 {
372     LOCK(cs_vNodes);
373     BOOST_FOREACH(CNode* pnode, vNodes)
374         if ((CService)pnode->addr == addr)
375             return (pnode);
376     return NULL;
377 }
378
379 CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64_t nTimeout)
380 {
381     if (pszDest == NULL) {
382         if (IsLocal(addrConnect))
383             return NULL;
384
385         // Look for an existing connection
386         CNode* pnode = FindNode((CService)addrConnect);
387         if (pnode)
388         {
389             if (nTimeout != 0)
390                 pnode->AddRef(nTimeout);
391             else
392                 pnode->AddRef();
393             return pnode;
394         }
395     }
396
397
398     /// debug print
399     printf("trying connection %s lastseen=%.1fhrs\n",
400         pszDest ? pszDest : addrConnect.ToString().c_str(),
401         pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
402
403     // Connect
404     SOCKET hSocket;
405     if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, GetDefaultPort()) : ConnectSocket(addrConnect, hSocket))
406     {
407         addrman.Attempt(addrConnect);
408
409         /// debug print
410         printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str());
411
412         // Set to non-blocking
413 #ifdef WIN32
414         u_long nOne = 1;
415         if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
416             printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
417 #else
418         if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
419             printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
420 #endif
421
422         // Add node
423         CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
424         if (nTimeout != 0)
425             pnode->AddRef(nTimeout);
426         else
427             pnode->AddRef();
428
429         {
430             LOCK(cs_vNodes);
431             vNodes.push_back(pnode);
432         }
433
434         pnode->nTimeConnected = GetTime();
435         return pnode;
436     }
437     else
438     {
439         return NULL;
440     }
441 }
442
443 void CNode::CloseSocketDisconnect()
444 {
445     fDisconnect = true;
446     if (hSocket != INVALID_SOCKET)
447     {
448         printf("disconnecting node %s\n", addrName.c_str());
449         closesocket(hSocket);
450         hSocket = INVALID_SOCKET;
451         vRecv.clear();
452     }
453
454     // in case this fails, we'll empty the recv buffer when the CNode is deleted
455     TRY_LOCK(cs_vRecv, lockRecv);
456     if (lockRecv)
457         vRecv.clear();
458
459     // if this was the sync node, we'll need a new one
460     if (this == pnodeSync)
461         pnodeSync = NULL;
462 }
463
464 void CNode::Cleanup()
465 {
466 }
467
468
469 void CNode::PushVersion()
470 {
471     /// when NTP implemented, change to just nTime = GetAdjustedTime()
472     int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
473     CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
474     CAddress addrMe = GetLocalAddress(&addr);
475     RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
476     printf("send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString().c_str(), addrYou.ToString().c_str(), addr.ToString().c_str());
477     PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
478                 nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
479 }
480
481
482
483
484
485 std::map<CNetAddr, int64_t> CNode::setBanned;
486 CCriticalSection CNode::cs_setBanned;
487
488 void CNode::ClearBanned()
489 {
490     setBanned.clear();
491 }
492
493 bool CNode::IsBanned(CNetAddr ip)
494 {
495     bool fResult = false;
496     {
497         LOCK(cs_setBanned);
498         std::map<CNetAddr, int64_t>::iterator i = setBanned.find(ip);
499         if (i != setBanned.end())
500         {
501             int64_t t = (*i).second;
502             if (GetTime() < t)
503                 fResult = true;
504         }
505     }
506     return fResult;
507 }
508
509 bool CNode::Misbehaving(int howmuch)
510 {
511     if (addr.IsLocal())
512     {
513         printf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch);
514         return false;
515     }
516
517     nMisbehavior += howmuch;
518     if (nMisbehavior >= GetArg("-banscore", 100))
519     {
520         int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24);  // Default 24-hour ban
521         printf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
522         {
523             LOCK(cs_setBanned);
524             if (setBanned[addr] < banTime)
525                 setBanned[addr] = banTime;
526         }
527         CloseSocketDisconnect();
528         return true;
529     } else
530         printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
531     return false;
532 }
533
534 #undef X
535 #define X(name) stats.name = name
536 void CNode::copyStats(CNodeStats &stats)
537 {
538     X(nServices);
539     X(nLastSend);
540     X(nLastRecv);
541     X(nTimeConnected);
542     X(addrName);
543     X(nVersion);
544     X(strSubVer);
545     X(fInbound);
546     X(nReleaseTime);
547     X(nStartingHeight);
548     X(nMisbehavior);
549     X(nSendBytes);
550     X(nRecvBytes);
551     stats.fSyncNode = (this == pnodeSync);
552 }
553 #undef X
554
555
556
557
558
559
560
561
562
563
564 void ThreadSocketHandler(void* parg)
565 {
566     // Make this thread recognisable as the networking thread
567     RenameThread("novacoin-net");
568
569     try
570     {
571         vnThreadsRunning[THREAD_SOCKETHANDLER]++;
572         ThreadSocketHandler2(parg);
573         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
574     }
575     catch (std::exception& e) {
576         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
577         PrintException(&e, "ThreadSocketHandler()");
578     } catch (...) {
579         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
580         throw; // support pthread_cancel()
581     }
582     printf("ThreadSocketHandler exited\n");
583 }
584
585 void ThreadSocketHandler2(void* parg)
586 {
587     printf("ThreadSocketHandler started\n");
588     list<CNode*> vNodesDisconnected;
589     unsigned int nPrevNodeCount = 0;
590
591     while (true)
592     {
593         //
594         // Disconnect nodes
595         //
596         {
597             LOCK(cs_vNodes);
598             // Disconnect unused nodes
599             vector<CNode*> vNodesCopy = vNodes;
600             BOOST_FOREACH(CNode* pnode, vNodesCopy)
601             {
602                 if (pnode->fDisconnect ||
603                     (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
604                 {
605                     // remove from vNodes
606                     vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
607
608                     // release outbound grant (if any)
609                     pnode->grantOutbound.Release();
610
611                     // close socket and cleanup
612                     pnode->CloseSocketDisconnect();
613                     pnode->Cleanup();
614
615                     // hold in disconnected pool until all refs are released
616                     pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
617                     if (pnode->fNetworkNode || pnode->fInbound)
618                         pnode->Release();
619                     vNodesDisconnected.push_back(pnode);
620                 }
621             }
622
623             // Delete disconnected nodes
624             list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
625             BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
626             {
627                 // wait until threads are done using it
628                 if (pnode->GetRefCount() <= 0)
629                 {
630                     bool fDelete = false;
631                     {
632                         TRY_LOCK(pnode->cs_vSend, lockSend);
633                         if (lockSend)
634                         {
635                             TRY_LOCK(pnode->cs_vRecv, lockRecv);
636                             if (lockRecv)
637                             {
638                                 TRY_LOCK(pnode->cs_mapRequests, lockReq);
639                                 if (lockReq)
640                                 {
641                                     TRY_LOCK(pnode->cs_inventory, lockInv);
642                                     if (lockInv)
643                                         fDelete = true;
644                                 }
645                             }
646                         }
647                     }
648                     if (fDelete)
649                     {
650                         vNodesDisconnected.remove(pnode);
651                         delete pnode;
652                     }
653                 }
654             }
655         }
656         if (vNodes.size() != nPrevNodeCount)
657         {
658             nPrevNodeCount = vNodes.size();
659             uiInterface.NotifyNumConnectionsChanged(vNodes.size());
660         }
661
662
663         //
664         // Find which sockets have data to receive
665         //
666         struct timeval timeout;
667         timeout.tv_sec  = 0;
668         timeout.tv_usec = 50000; // frequency to poll pnode->vSend
669
670         fd_set fdsetRecv;
671         fd_set fdsetSend;
672         fd_set fdsetError;
673         FD_ZERO(&fdsetRecv);
674         FD_ZERO(&fdsetSend);
675         FD_ZERO(&fdsetError);
676         SOCKET hSocketMax = 0;
677         bool have_fds = false;
678
679         BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
680             FD_SET(hListenSocket, &fdsetRecv);
681             hSocketMax = max(hSocketMax, hListenSocket);
682             have_fds = true;
683         }
684         {
685             LOCK(cs_vNodes);
686             BOOST_FOREACH(CNode* pnode, vNodes)
687             {
688                 if (pnode->hSocket == INVALID_SOCKET)
689                     continue;
690                 FD_SET(pnode->hSocket, &fdsetRecv);
691                 FD_SET(pnode->hSocket, &fdsetError);
692                 hSocketMax = max(hSocketMax, pnode->hSocket);
693                 have_fds = true;
694                 {
695                     TRY_LOCK(pnode->cs_vSend, lockSend);
696                     if (lockSend && !pnode->vSend.empty())
697                         FD_SET(pnode->hSocket, &fdsetSend);
698                 }
699             }
700         }
701
702         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
703         int nSelect = select(have_fds ? hSocketMax + 1 : 0,
704                              &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
705         vnThreadsRunning[THREAD_SOCKETHANDLER]++;
706         if (fShutdown)
707             return;
708         if (nSelect == SOCKET_ERROR)
709         {
710             if (have_fds)
711             {
712                 int nErr = WSAGetLastError();
713                 printf("socket select error %d\n", nErr);
714                 for (unsigned int i = 0; i <= hSocketMax; i++)
715                     FD_SET(i, &fdsetRecv);
716             }
717             FD_ZERO(&fdsetSend);
718             FD_ZERO(&fdsetError);
719             Sleep(timeout.tv_usec/1000);
720         }
721
722
723         //
724         // Accept new connections
725         //
726         BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
727         if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
728         {
729 #ifdef USE_IPV6
730             struct sockaddr_storage sockaddr;
731 #else
732             struct sockaddr sockaddr;
733 #endif
734             socklen_t len = sizeof(sockaddr);
735             SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
736             CAddress addr;
737             int nInbound = 0;
738
739             if (hSocket != INVALID_SOCKET)
740                 if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
741                     printf("Warning: Unknown socket family\n");
742
743             {
744                 LOCK(cs_vNodes);
745                 BOOST_FOREACH(CNode* pnode, vNodes)
746                     if (pnode->fInbound)
747                         nInbound++;
748             }
749
750             if (hSocket == INVALID_SOCKET)
751             {
752                 int nErr = WSAGetLastError();
753                 if (nErr != WSAEWOULDBLOCK)
754                     printf("socket error accept failed: %d\n", nErr);
755             }
756             else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
757             {
758                 {
759                     LOCK(cs_setservAddNodeAddresses);
760                     if (!setservAddNodeAddresses.count(addr))
761                         closesocket(hSocket);
762                 }
763             }
764             else if (CNode::IsBanned(addr))
765             {
766                 printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
767                 closesocket(hSocket);
768             }
769             else
770             {
771                 printf("accepted connection %s\n", addr.ToString().c_str());
772                 CNode* pnode = new CNode(hSocket, addr, "", true);
773                 pnode->AddRef();
774                 {
775                     LOCK(cs_vNodes);
776                     vNodes.push_back(pnode);
777                 }
778             }
779         }
780
781
782         //
783         // Service each socket
784         //
785         vector<CNode*> vNodesCopy;
786         {
787             LOCK(cs_vNodes);
788             vNodesCopy = vNodes;
789             BOOST_FOREACH(CNode* pnode, vNodesCopy)
790                 pnode->AddRef();
791         }
792         BOOST_FOREACH(CNode* pnode, vNodesCopy)
793         {
794             if (fShutdown)
795                 return;
796
797             //
798             // Receive
799             //
800             if (pnode->hSocket == INVALID_SOCKET)
801                 continue;
802             if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
803             {
804                 TRY_LOCK(pnode->cs_vRecv, lockRecv);
805                 if (lockRecv)
806                 {
807                     CDataStream& vRecv = pnode->vRecv;
808                     uint64_t nPos = vRecv.size();
809
810                     if (nPos > ReceiveBufferSize()) {
811                         if (!pnode->fDisconnect)
812                             printf("socket recv flood control disconnect (%" PRIszu " bytes)\n", vRecv.size());
813                         pnode->CloseSocketDisconnect();
814                     }
815                     else {
816                         // typical socket buffer is 8K-64K
817                         char pchBuf[0x10000];
818                         int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
819                         if (nBytes > 0)
820                         {
821                             vRecv.resize(nPos + nBytes);
822                             memcpy(&vRecv[nPos], pchBuf, nBytes);
823                             pnode->nLastRecv = GetTime();
824                             pnode->nRecvBytes += nBytes;
825                             pnode->RecordBytesRecv(nBytes);
826                         }
827                         else if (nBytes == 0)
828                         {
829                             // socket closed gracefully
830                             if (!pnode->fDisconnect)
831                                 printf("socket closed\n");
832                             pnode->CloseSocketDisconnect();
833                         }
834                         else if (nBytes < 0)
835                         {
836                             // error
837                             int nErr = WSAGetLastError();
838                             if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
839                             {
840                                 if (!pnode->fDisconnect)
841                                     printf("socket recv error %d\n", nErr);
842                                 pnode->CloseSocketDisconnect();
843                             }
844                         }
845                     }
846                 }
847             }
848
849             //
850             // Send
851             //
852             if (pnode->hSocket == INVALID_SOCKET)
853                 continue;
854             if (FD_ISSET(pnode->hSocket, &fdsetSend))
855             {
856                 TRY_LOCK(pnode->cs_vSend, lockSend);
857                 if (lockSend)
858                 {
859                     CDataStream& vSend = pnode->vSend;
860                     if (!vSend.empty())
861                     {
862                         int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
863                         if (nBytes > 0)
864                         {
865                             vSend.erase(vSend.begin(), vSend.begin() + nBytes);
866                             pnode->nLastSend = GetTime();
867                             pnode->nSendBytes += nBytes;
868                             pnode->RecordBytesSent(nBytes);
869                         }
870                         else if (nBytes < 0)
871                         {
872                             // error
873                             int nErr = WSAGetLastError();
874                             if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
875                             {
876                                 printf("socket send error %d\n", nErr);
877                                 pnode->CloseSocketDisconnect();
878                             }
879                         }
880                     }
881                 }
882             }
883
884             //
885             // Inactivity checking
886             //
887             if (pnode->vSend.empty())
888                 pnode->nLastSendEmpty = GetTime();
889             if (GetTime() - pnode->nTimeConnected > 60)
890             {
891                 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
892                 {
893                     printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
894                     pnode->fDisconnect = true;
895                 }
896                 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
897                 {
898                     printf("socket not sending\n");
899                     pnode->fDisconnect = true;
900                 }
901                 else if (GetTime() - pnode->nLastRecv > 90*60)
902                 {
903                     printf("socket inactivity timeout\n");
904                     pnode->fDisconnect = true;
905                 }
906             }
907         }
908         {
909             LOCK(cs_vNodes);
910             BOOST_FOREACH(CNode* pnode, vNodesCopy)
911                 pnode->Release();
912         }
913
914         Sleep(10);
915     }
916 }
917
918
919
920
921
922
923
924
925
926 #ifdef USE_UPNP
927 void ThreadMapPort(void* parg)
928 {
929     // Make this thread recognisable as the UPnP thread
930     RenameThread("novacoin-UPnP");
931
932     try
933     {
934         vnThreadsRunning[THREAD_UPNP]++;
935         ThreadMapPort2(parg);
936         vnThreadsRunning[THREAD_UPNP]--;
937     }
938     catch (std::exception& e) {
939         vnThreadsRunning[THREAD_UPNP]--;
940         PrintException(&e, "ThreadMapPort()");
941     } catch (...) {
942         vnThreadsRunning[THREAD_UPNP]--;
943         PrintException(NULL, "ThreadMapPort()");
944     }
945     printf("ThreadMapPort exited\n");
946 }
947
948 void ThreadMapPort2(void* parg)
949 {
950     printf("ThreadMapPort started\n");
951
952     std::string port = strprintf("%u", GetListenPort());
953     const char * multicastif = 0;
954     const char * minissdpdpath = 0;
955     struct UPNPDev * devlist = 0;
956     char lanaddr[64];
957
958 #ifndef UPNPDISCOVER_SUCCESS
959     /* miniupnpc 1.5 */
960     devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
961 #else
962     /* miniupnpc 1.6 */
963     int error = 0;
964     devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
965 #endif
966
967     struct UPNPUrls urls;
968     struct IGDdatas data;
969     int r;
970
971     r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
972     if (r == 1)
973     {
974         if (fDiscover) {
975             char externalIPAddress[40];
976             r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
977             if(r != UPNPCOMMAND_SUCCESS)
978                 printf("UPnP: GetExternalIPAddress() returned %d\n", r);
979             else
980             {
981                 if(externalIPAddress[0])
982                 {
983                     printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
984                     AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP);
985                 }
986                 else
987                     printf("UPnP: GetExternalIPAddress failed.\n");
988             }
989         }
990
991         string strDesc = "NovaCoin " + FormatFullVersion();
992 #ifndef UPNPDISCOVER_SUCCESS
993         /* miniupnpc 1.5 */
994         r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
995                             port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0);
996 #else
997         /* miniupnpc 1.6 */
998         r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
999                             port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
1000 #endif
1001
1002         if(r!=UPNPCOMMAND_SUCCESS)
1003             printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
1004                 port.c_str(), port.c_str(), lanaddr, r, strupnperror(r));
1005         else
1006             printf("UPnP Port Mapping successful.\n");
1007         int i = 1;
1008         while (true)
1009         {
1010             if (fShutdown || !fUseUPnP)
1011             {
1012                 r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
1013                 printf("UPNP_DeletePortMapping() returned : %d\n", r);
1014                 freeUPNPDevlist(devlist); devlist = 0;
1015                 FreeUPNPUrls(&urls);
1016                 return;
1017             }
1018             if (i % 600 == 0) // Refresh every 20 minutes
1019             {
1020 #ifndef UPNPDISCOVER_SUCCESS
1021                 /* miniupnpc 1.5 */
1022                 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
1023                                     port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0);
1024 #else
1025                 /* miniupnpc 1.6 */
1026                 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
1027                                     port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
1028 #endif
1029
1030                 if(r!=UPNPCOMMAND_SUCCESS)
1031                     printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
1032                         port.c_str(), port.c_str(), lanaddr, r, strupnperror(r));
1033                 else
1034                     printf("UPnP Port Mapping successful.\n");;
1035             }
1036             Sleep(2000);
1037             i++;
1038         }
1039     } else {
1040         printf("No valid UPnP IGDs found\n");
1041         freeUPNPDevlist(devlist); devlist = 0;
1042         if (r != 0)
1043             FreeUPNPUrls(&urls);
1044         while (true)
1045         {
1046             if (fShutdown || !fUseUPnP)
1047                 return;
1048             Sleep(2000);
1049         }
1050     }
1051 }
1052
1053 void MapPort()
1054 {
1055     if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1)
1056     {
1057         if (!NewThread(ThreadMapPort, NULL))
1058             printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
1059     }
1060 }
1061 #else
1062 void MapPort()
1063 {
1064     // Intentionally left blank.
1065 }
1066 #endif
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 // DNS seeds
1077 // Each pair gives a source name and a seed name.
1078 // The first name is used as information source for addrman.
1079 // The second name should resolve to a list of seed addresses.
1080 static const char *strDNSSeed[][2] = {
1081     {"novacoin.karelia.pro", "dnsseed.novacoin.karelia.pro"},
1082     {"novacoin.su", "dnsseed.novacoin.su"},
1083     {"novacoin.ru", "dnsseed.novacoin.ru"},
1084     {"novacoin.ru", "testseed.novacoin.ru"},
1085     {"novaco.in", "dnsseed.novaco.in"},
1086 };
1087
1088 void ThreadDNSAddressSeed(void* parg)
1089 {
1090     // Make this thread recognisable as the DNS seeding thread
1091     RenameThread("novacoin-dnsseed");
1092
1093     try
1094     {
1095         vnThreadsRunning[THREAD_DNSSEED]++;
1096         ThreadDNSAddressSeed2(parg);
1097         vnThreadsRunning[THREAD_DNSSEED]--;
1098     }
1099     catch (std::exception& e) {
1100         vnThreadsRunning[THREAD_DNSSEED]--;
1101         PrintException(&e, "ThreadDNSAddressSeed()");
1102     } catch (...) {
1103         vnThreadsRunning[THREAD_DNSSEED]--;
1104         throw; // support pthread_cancel()
1105     }
1106     printf("ThreadDNSAddressSeed exited\n");
1107 }
1108
1109 void ThreadDNSAddressSeed2(void* parg)
1110 {
1111     printf("ThreadDNSAddressSeed started\n");
1112     int found = 0;
1113
1114     if (!fTestNet)
1115     {
1116         printf("Loading addresses from DNS seeds (could take a while)\n");
1117
1118         for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
1119             if (HaveNameProxy()) {
1120                 AddOneShot(strDNSSeed[seed_idx][1]);
1121             } else {
1122                 vector<CNetAddr> vaddr;
1123                 vector<CAddress> vAdd;
1124                 if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
1125                 {
1126                     BOOST_FOREACH(CNetAddr& ip, vaddr)
1127                     {
1128                         int nOneDay = 24*3600;
1129                         CAddress addr = CAddress(CService(ip, GetDefaultPort()));
1130                         addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
1131                         vAdd.push_back(addr);
1132                         found++;
1133                     }
1134                 }
1135                 addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
1136             }
1137         }
1138     }
1139
1140     printf("%d addresses found from DNS seeds\n", found);
1141 }
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154 uint32_t pnSeed[] =
1155 {
1156     0x5360a653, 0x6c47bb25, 0x52568c5f, 0xc6f5c851, 0x6f17f3a2, 0x1d52a9d5, 0x2c1544c1, 0xb8748368,
1157     0x055d6ac1, 0x2490bb25, 0x614488d5, 0xa463f8a2, 0xc54c1256, 0xf72d9252, 0x548432c6, 0xade08368,
1158     0x02bf8f55, 0x79f81c48, 0xeb44a26d, 0x802c0856, 0xe3a8d772, 0xc661c852, 0xde30d4b0, 0x1044d079,
1159     0xa1e1485d, 0x269d5e02, 0x65ec8b5b, 0x4b78a605, 0xac9a1f5f, 0x307c7db0, 0xb75d4880, 0x31aaef53,
1160     0xe9433eb0, 0x8ce0861f, 0x1874695f, 0x6baef986, 0x06cfbf2e, 0x6c2e0082, 0x15e024b0, 0x0d0986bc,
1161     0xe7002d48, 0x064b2d05, 0xba568c5f, 0x3c93fa18, 0xfae6234d, 0xb06f5d02, 0x34e25d02, 0x559425b0,
1162     0x308eae6e, 0x48e15d02, 0x87fee36d, 0x647f5e02, 0xcbfe61bc, 0x3bf377d4, 0x1543075b, 0x3ee84980,
1163     0xde26482e, 0x66a65e02, 0x60cf0fb0, 0xf74c8e4f, 0x88d39a5e, 0x1c385e02, 0x62c4f460, 0x5b26df48,
1164     0x5249515d, 0x2b353f7d, 0xb6e34980, 0x5e7cd23e, 0x5ecc5e02, 0x9349515d, 0x31abbf2e, 0xa8675cb6,
1165     0xa8ce4762, 0x09e5d4b0, 0x6db26805, 0xb4f45d02, 0xfe07e555, 0xb6ab40bc, 0x8be25d02, 0x92bd345f,
1166     0x7122306c, 0x9254c248, 0x8dcc5e02, 0x0d1d5d02, 0x35a2805f, 0x404ef986, 0x5dab696d, 0xf153ad2e,
1167     0xc5c7a988, 0xfafd6d4a, 0xf172a7be, 0x09627bd9, 0x747d695f, 0xaa4a5d02, 0x4d226805, 0x6bb40ab9,
1168     0x67d61352,
1169 };
1170
1171 void DumpAddresses()
1172 {
1173     int64_t nStart = GetTimeMillis();
1174
1175     CAddrDB adb;
1176     adb.Write(addrman);
1177
1178     printf("Flushed %d addresses to peers.dat  %" PRId64 "ms\n",
1179            addrman.size(), GetTimeMillis() - nStart);
1180 }
1181
1182 void ThreadDumpAddress2(void* parg)
1183 {
1184     vnThreadsRunning[THREAD_DUMPADDRESS]++;
1185     while (!fShutdown)
1186     {
1187         DumpAddresses();
1188         vnThreadsRunning[THREAD_DUMPADDRESS]--;
1189         Sleep(600000);
1190         vnThreadsRunning[THREAD_DUMPADDRESS]++;
1191     }
1192     vnThreadsRunning[THREAD_DUMPADDRESS]--;
1193 }
1194
1195 void ThreadDumpAddress(void* parg)
1196 {
1197     // Make this thread recognisable as the address dumping thread
1198     RenameThread("novacoin-adrdump");
1199
1200     try
1201     {
1202         ThreadDumpAddress2(parg);
1203     }
1204     catch (std::exception& e) {
1205         PrintException(&e, "ThreadDumpAddress()");
1206     }
1207     printf("ThreadDumpAddress exited\n");
1208 }
1209
1210 void ThreadOpenConnections(void* parg)
1211 {
1212     // Make this thread recognisable as the connection opening thread
1213     RenameThread("novacoin-opencon");
1214
1215     try
1216     {
1217         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1218         ThreadOpenConnections2(parg);
1219         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1220     }
1221     catch (std::exception& e) {
1222         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1223         PrintException(&e, "ThreadOpenConnections()");
1224     } catch (...) {
1225         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1226         PrintException(NULL, "ThreadOpenConnections()");
1227     }
1228     printf("ThreadOpenConnections exited\n");
1229 }
1230
1231 void static ProcessOneShot()
1232 {
1233     string strDest;
1234     {
1235         LOCK(cs_vOneShots);
1236         if (vOneShots.empty())
1237             return;
1238         strDest = vOneShots.front();
1239         vOneShots.pop_front();
1240     }
1241     CAddress addr;
1242     CSemaphoreGrant grant(*semOutbound, true);
1243     if (grant) {
1244         if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true))
1245             AddOneShot(strDest);
1246     }
1247 }
1248
1249 // ppcoin: stake minter thread
1250 void static ThreadStakeMinter(void* parg)
1251 {
1252     printf("ThreadStakeMinter started\n");
1253     CWallet* pwallet = (CWallet*)parg;
1254     try
1255     {
1256         vnThreadsRunning[THREAD_MINTER]++;
1257         StakeMiner(pwallet);
1258         vnThreadsRunning[THREAD_MINTER]--;
1259     }
1260     catch (std::exception& e) {
1261         vnThreadsRunning[THREAD_MINTER]--;
1262         PrintException(&e, "ThreadStakeMinter()");
1263     } catch (...) {
1264         vnThreadsRunning[THREAD_MINTER]--;
1265         PrintException(NULL, "ThreadStakeMinter()");
1266     }
1267     printf("ThreadStakeMinter exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINTER]);
1268 }
1269
1270 void ThreadOpenConnections2(void* parg)
1271 {
1272     printf("ThreadOpenConnections started\n");
1273
1274     // Connect to specific addresses
1275     if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
1276     {
1277         for (int64_t nLoop = 0;; nLoop++)
1278         {
1279             ProcessOneShot();
1280             BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
1281             {
1282                 CAddress addr;
1283                 OpenNetworkConnection(addr, NULL, strAddr.c_str());
1284                 for (int i = 0; i < 10 && i < nLoop; i++)
1285                 {
1286                     Sleep(500);
1287                     if (fShutdown)
1288                         return;
1289                 }
1290             }
1291             Sleep(500);
1292         }
1293     }
1294
1295     // Initiate network connections
1296     int64_t nStart = GetTime();
1297     while (true)
1298     {
1299         ProcessOneShot();
1300
1301         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1302         Sleep(500);
1303         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1304         if (fShutdown)
1305             return;
1306
1307
1308         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1309         CSemaphoreGrant grant(*semOutbound);
1310         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1311         if (fShutdown)
1312             return;
1313
1314         // Add seed nodes if IRC isn't working
1315         if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
1316         {
1317             std::vector<CAddress> vAdd;
1318             for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
1319             {
1320                 // It'll only connect to one or two seed nodes because once it connects,
1321                 // it'll get a pile of addresses with newer timestamps.
1322                 // Seed nodes are given a random 'last seen time' of between one and two
1323                 // weeks ago.
1324                 const int64_t nOneWeek = 7*24*60*60;
1325                 struct in_addr ip;
1326                 memcpy(&ip, &pnSeed[i], sizeof(ip));
1327                 CAddress addr(CService(ip, GetDefaultPort()));
1328                 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1329                 vAdd.push_back(addr);
1330             }
1331             addrman.Add(vAdd, CNetAddr("127.0.0.1"));
1332         }
1333
1334         //
1335         // Choose an address to connect to based on most recently seen
1336         //
1337         CAddress addrConnect;
1338
1339         // Only connect out to one peer per network group (/16 for IPv4).
1340         // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
1341         int nOutbound = 0;
1342         set<vector<unsigned char> > setConnected;
1343         {
1344             LOCK(cs_vNodes);
1345             BOOST_FOREACH(CNode* pnode, vNodes) {
1346                 if (!pnode->fInbound) {
1347                     setConnected.insert(pnode->addr.GetGroup());
1348                     nOutbound++;
1349                 }
1350             }
1351         }
1352
1353         int64_t nANow = GetAdjustedTime();
1354
1355         int nTries = 0;
1356         while (true)
1357         {
1358             // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
1359             CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
1360
1361             // if we selected an invalid address, restart
1362             if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
1363                 break;
1364
1365             // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
1366             // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
1367             // already-connected network ranges, ...) before trying new addrman addresses.
1368             nTries++;
1369             if (nTries > 100)
1370                 break;
1371
1372             if (IsLimited(addr))
1373                 continue;
1374
1375             // only consider very recently tried nodes after 30 failed attempts
1376             if (nANow - addr.nLastTry < 600 && nTries < 30)
1377                 continue;
1378
1379             // do not allow non-default ports, unless after 50 invalid addresses selected already
1380             if (addr.GetPort() != GetDefaultPort() && nTries < 50)
1381                 continue;
1382
1383             addrConnect = addr;
1384             break;
1385         }
1386
1387         if (addrConnect.IsValid())
1388             OpenNetworkConnection(addrConnect, &grant);
1389     }
1390 }
1391
1392 void ThreadOpenAddedConnections(void* parg)
1393 {
1394     // Make this thread recognisable as the connection opening thread
1395     RenameThread("novacoin-opencon");
1396
1397     try
1398     {
1399         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1400         ThreadOpenAddedConnections2(parg);
1401         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1402     }
1403     catch (std::exception& e) {
1404         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1405         PrintException(&e, "ThreadOpenAddedConnections()");
1406     } catch (...) {
1407         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1408         PrintException(NULL, "ThreadOpenAddedConnections()");
1409     }
1410     printf("ThreadOpenAddedConnections exited\n");
1411 }
1412
1413 void ThreadOpenAddedConnections2(void* parg)
1414 {
1415     printf("ThreadOpenAddedConnections started\n");
1416
1417     {
1418         LOCK(cs_vAddedNodes);
1419         vAddedNodes = mapMultiArgs["-addnode"];
1420     }
1421
1422     if (HaveNameProxy()) {
1423         while(!fShutdown) {
1424             list<string> lAddresses(0);
1425             {
1426                 LOCK(cs_vAddedNodes);
1427                 BOOST_FOREACH(string& strAddNode, vAddedNodes)
1428                     lAddresses.push_back(strAddNode);
1429             }
1430             BOOST_FOREACH(string& strAddNode, lAddresses) {
1431                 CAddress addr;
1432                 CSemaphoreGrant grant(*semOutbound);
1433                 OpenNetworkConnection(addr, &grant, strAddNode.c_str());
1434                 Sleep(500);
1435             }
1436             vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1437             Sleep(120000); // Retry every 2 minutes
1438             vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1439         }
1440         return;
1441     }
1442
1443     for (uint32_t i = 0; true; i++)
1444     {
1445         list<string> lAddresses(0);
1446         {
1447             LOCK(cs_vAddedNodes);
1448             BOOST_FOREACH(string& strAddNode, vAddedNodes)
1449                 lAddresses.push_back(strAddNode);
1450         }
1451
1452         list<vector<CService> > lservAddressesToAdd(0);
1453         BOOST_FOREACH(string& strAddNode, lAddresses)
1454         {
1455             vector<CService> vservNode(0);
1456             if (Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
1457             {
1458                 lservAddressesToAdd.push_back(vservNode);
1459                 {
1460                     LOCK(cs_setservAddNodeAddresses);
1461                     BOOST_FOREACH(CService& serv, vservNode)
1462                         setservAddNodeAddresses.insert(serv);
1463                 }
1464             }
1465         }
1466         // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
1467         // (keeping in mind that addnode entries can have many IPs if fNameLookup)
1468         {
1469             LOCK(cs_vNodes);
1470             BOOST_FOREACH(CNode* pnode, vNodes)
1471                 for (list<vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
1472                  {
1473                     BOOST_FOREACH(CService& addrNode, *(it))
1474                         if (pnode->addr == addrNode)
1475                         {
1476                             it = lservAddressesToAdd.erase(it);
1477                             if(it != lservAddressesToAdd.begin())
1478                                 it--;
1479                             break;
1480                         }
1481                     if (it == lservAddressesToAdd.end())
1482                         break;
1483                 }
1484         }
1485         BOOST_FOREACH(vector<CService>& vserv, lservAddressesToAdd)
1486         {
1487             if (vserv.size() == 0)
1488                 continue;
1489             CSemaphoreGrant grant(*semOutbound);
1490             OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
1491             Sleep(500);
1492             if (fShutdown)
1493                 return;
1494         }
1495         if (fShutdown)
1496             return;
1497         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1498         Sleep(120000); // Retry every 2 minutes
1499         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1500         if (fShutdown)
1501             return;
1502     }
1503 }
1504
1505 // if successful, this moves the passed grant to the constructed node
1506 bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot)
1507 {
1508     //
1509     // Initiate outbound network connection
1510     //
1511     if (fShutdown)
1512         return false;
1513     if (!strDest)
1514         if (IsLocal(addrConnect) ||
1515             FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
1516             FindNode(addrConnect.ToStringIPPort().c_str()))
1517             return false;
1518     if (strDest && FindNode(strDest))
1519         return false;
1520
1521     vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1522     CNode* pnode = ConnectNode(addrConnect, strDest);
1523     vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1524     if (fShutdown)
1525         return false;
1526     if (!pnode)
1527         return false;
1528     if (grantOutbound)
1529         grantOutbound->MoveTo(pnode->grantOutbound);
1530     pnode->fNetworkNode = true;
1531     if (fOneShot)
1532         pnode->fOneShot = true;
1533
1534     return true;
1535 }
1536
1537 // for now, use a very simple selection metric: the node from which we received
1538 // most recently
1539 double static NodeSyncScore(const CNode *pnode) {
1540     return -pnode->nLastRecv;
1541 }
1542
1543 void static StartSync(const vector<CNode*> &vNodes) {
1544     CNode *pnodeNewSync = NULL;
1545     double dBestScore = 0;
1546
1547     // Iterate over all nodes
1548     BOOST_FOREACH(CNode* pnode, vNodes) {
1549         // check preconditions for allowing a sync
1550         if (!pnode->fClient && !pnode->fOneShot &&
1551             !pnode->fDisconnect && pnode->fSuccessfullyConnected &&
1552             (pnode->nStartingHeight > (nBestHeight - 144)) &&
1553             (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
1554             // if ok, compare node's score with the best so far
1555             double dScore = NodeSyncScore(pnode);
1556             if (pnodeNewSync == NULL || dScore > dBestScore) {
1557                 pnodeNewSync = pnode;
1558                 dBestScore = dScore;
1559             }
1560         }
1561     }
1562     // if a new sync candidate was found, start sync!
1563     if (pnodeNewSync) {
1564         pnodeNewSync->fStartSync = true;
1565         pnodeSync = pnodeNewSync;
1566     }
1567 }
1568
1569 void ThreadMessageHandler(void* parg)
1570 {
1571     // Make this thread recognisable as the message handling thread
1572     RenameThread("novacoin-msghand");
1573
1574     try
1575     {
1576         vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1577         ThreadMessageHandler2(parg);
1578         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1579     }
1580     catch (std::exception& e) {
1581         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1582         PrintException(&e, "ThreadMessageHandler()");
1583     } catch (...) {
1584         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1585         PrintException(NULL, "ThreadMessageHandler()");
1586     }
1587     printf("ThreadMessageHandler exited\n");
1588 }
1589
1590 void ThreadMessageHandler2(void* parg)
1591 {
1592     printf("ThreadMessageHandler started\n");
1593     SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1594     while (!fShutdown)
1595     {
1596         bool fHaveSyncNode = false;
1597         vector<CNode*> vNodesCopy;
1598         {
1599             LOCK(cs_vNodes);
1600             vNodesCopy = vNodes;
1601             BOOST_FOREACH(CNode* pnode, vNodesCopy) {
1602                 pnode->AddRef();
1603                 if (pnode == pnodeSync)
1604                     fHaveSyncNode = true;
1605             }
1606         }
1607
1608         if (!fHaveSyncNode)
1609             StartSync(vNodesCopy);
1610
1611         // Poll the connected nodes for messages
1612         CNode* pnodeTrickle = NULL;
1613         if (!vNodesCopy.empty())
1614             pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
1615         BOOST_FOREACH(CNode* pnode, vNodesCopy)
1616         {
1617             // Receive messages
1618             {
1619                 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1620                 if (lockRecv)
1621                     ProcessMessages(pnode);
1622             }
1623             if (fShutdown)
1624                 return;
1625
1626             // Send messages
1627             {
1628                 TRY_LOCK(pnode->cs_vSend, lockSend);
1629                 if (lockSend)
1630                     SendMessages(pnode, pnode == pnodeTrickle);
1631             }
1632             if (fShutdown)
1633                 return;
1634         }
1635
1636         {
1637             LOCK(cs_vNodes);
1638             BOOST_FOREACH(CNode* pnode, vNodesCopy)
1639                 pnode->Release();
1640         }
1641
1642         // Wait and allow messages to bunch up.
1643         // Reduce vnThreadsRunning so StopNode has permission to exit while
1644         // we're sleeping, but we must always check fShutdown after doing this.
1645         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1646         Sleep(100);
1647         if (fRequestShutdown)
1648             StartShutdown();
1649         vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1650         if (fShutdown)
1651             return;
1652     }
1653 }
1654
1655
1656
1657
1658
1659
1660 bool BindListenPort(const CService &addrBind, string& strError)
1661 {
1662     strError = "";
1663     int nOne = 1;
1664
1665 #ifdef WIN32
1666     // Initialize Windows Sockets
1667     WSADATA wsadata;
1668     int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
1669     if (ret != NO_ERROR)
1670     {
1671         strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
1672         printf("%s\n", strError.c_str());
1673         return false;
1674     }
1675 #endif
1676
1677     // Create socket for listening for incoming connections
1678 #ifdef USE_IPV6
1679     struct sockaddr_storage sockaddr;
1680 #else
1681     struct sockaddr sockaddr;
1682 #endif
1683     socklen_t len = sizeof(sockaddr);
1684     if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
1685     {
1686         strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
1687         printf("%s\n", strError.c_str());
1688         return false;
1689     }
1690
1691     SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
1692     if (hListenSocket == INVALID_SOCKET)
1693     {
1694         strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
1695         printf("%s\n", strError.c_str());
1696         return false;
1697     }
1698
1699 #ifdef SO_NOSIGPIPE
1700     // Different way of disabling SIGPIPE on BSD
1701     setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
1702 #endif
1703
1704 #ifndef WIN32
1705     // Allow binding if the port is still in TIME_WAIT state after
1706     // the program was closed and restarted.  Not an issue on windows.
1707     setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
1708 #endif
1709
1710
1711 #ifdef WIN32
1712     // Set to non-blocking, incoming connections will also inherit this
1713     if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
1714 #else
1715     if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
1716 #endif
1717     {
1718         strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
1719         printf("%s\n", strError.c_str());
1720         return false;
1721     }
1722
1723 #ifdef USE_IPV6
1724     // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
1725     // and enable it by default or not. Try to enable it, if possible.
1726     if (addrBind.IsIPv6()) {
1727 #ifdef IPV6_V6ONLY
1728 #ifdef WIN32
1729         setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int));
1730 #else
1731         setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
1732 #endif
1733 #endif
1734 #ifdef WIN32
1735         int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
1736         int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
1737         // this call is allowed to fail
1738         setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
1739 #endif
1740     }
1741 #endif
1742
1743     if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
1744     {
1745         int nErr = WSAGetLastError();
1746         if (nErr == WSAEADDRINUSE)
1747             strError = strprintf(_("Unable to bind to %s on this computer. NovaCoin is probably already running."), addrBind.ToString().c_str());
1748         else
1749             strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr));
1750         printf("%s\n", strError.c_str());
1751         return false;
1752     }
1753     printf("Bound to %s\n", addrBind.ToString().c_str());
1754
1755     // Listen for incoming connections
1756     if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1757     {
1758         strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
1759         printf("%s\n", strError.c_str());
1760         return false;
1761     }
1762
1763     vhListenSocket.push_back(hListenSocket);
1764
1765     if (addrBind.IsRoutable() && fDiscover)
1766         AddLocal(addrBind, LOCAL_BIND);
1767
1768     return true;
1769 }
1770
1771 void static Discover()
1772 {
1773     if (!fDiscover)
1774         return;
1775
1776 #ifdef WIN32
1777     // Get local host IP
1778     char pszHostName[1000] = "";
1779     if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1780     {
1781         vector<CNetAddr> vaddr;
1782         if (LookupHost(pszHostName, vaddr))
1783         {
1784             BOOST_FOREACH (const CNetAddr &addr, vaddr)
1785             {
1786                 AddLocal(addr, LOCAL_IF);
1787             }
1788         }
1789     }
1790 #else
1791     // Get local host ip
1792     struct ifaddrs* myaddrs;
1793     if (getifaddrs(&myaddrs) == 0)
1794     {
1795         for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1796         {
1797             if (ifa->ifa_addr == NULL) continue;
1798             if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1799             if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1800             if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
1801             if (ifa->ifa_addr->sa_family == AF_INET)
1802             {
1803                 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
1804                 CNetAddr addr(s4->sin_addr);
1805                 if (AddLocal(addr, LOCAL_IF))
1806                     printf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1807             }
1808 #ifdef USE_IPV6
1809             else if (ifa->ifa_addr->sa_family == AF_INET6)
1810             {
1811                 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
1812                 CNetAddr addr(s6->sin6_addr);
1813                 if (AddLocal(addr, LOCAL_IF))
1814                     printf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1815             }
1816 #endif
1817         }
1818         freeifaddrs(myaddrs);
1819     }
1820 #endif
1821
1822     // Don't use external IPv4 discovery, when -onlynet="IPv6"
1823     if (!IsLimited(NET_IPV4))
1824         NewThread(ThreadGetMyExternalIP, NULL);
1825 }
1826
1827 void StartNode(void* parg)
1828 {
1829     // Make this thread recognisable as the startup thread
1830     RenameThread("novacoin-start");
1831
1832     if (semOutbound == NULL) {
1833         // initialize semaphore
1834         int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
1835         semOutbound = new CSemaphore(nMaxOutbound);
1836     }
1837
1838     if (pnodeLocalHost == NULL)
1839         pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
1840
1841     Discover();
1842
1843     //
1844     // Start threads
1845     //
1846
1847     if (!GetBoolArg("-dnsseed", true))
1848         printf("DNS seeding disabled\n");
1849     else
1850         if (!NewThread(ThreadDNSAddressSeed, NULL))
1851             printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
1852
1853     // Map ports with UPnP
1854     if (fUseUPnP)
1855         MapPort();
1856
1857     // Get addresses from IRC and advertise ours
1858     if (!NewThread(ThreadIRCSeed, NULL))
1859         printf("Error: NewThread(ThreadIRCSeed) failed\n");
1860
1861     // Send and receive from sockets, accept connections
1862     if (!NewThread(ThreadSocketHandler, NULL))
1863         printf("Error: NewThread(ThreadSocketHandler) failed\n");
1864
1865     // Initiate outbound connections from -addnode
1866     if (!NewThread(ThreadOpenAddedConnections, NULL))
1867         printf("Error: NewThread(ThreadOpenAddedConnections) failed\n");
1868
1869     // Initiate outbound connections
1870     if (!NewThread(ThreadOpenConnections, NULL))
1871         printf("Error: NewThread(ThreadOpenConnections) failed\n");
1872
1873     // Process messages
1874     if (!NewThread(ThreadMessageHandler, NULL))
1875         printf("Error: NewThread(ThreadMessageHandler) failed\n");
1876
1877     // Dump network addresses
1878     if (!NewThread(ThreadDumpAddress, NULL))
1879         printf("Error; NewThread(ThreadDumpAddress) failed\n");
1880
1881     // ppcoin: mint proof-of-stake blocks in the background
1882     if (!NewThread(ThreadStakeMinter, pwalletMain))
1883         printf("Error: NewThread(ThreadStakeMinter) failed\n");
1884 }
1885
1886 bool StopNode()
1887 {
1888     printf("StopNode()\n");
1889     fShutdown = true;
1890     nTransactionsUpdated++;
1891     int64_t nStart = GetTime();
1892     {
1893         LOCK(cs_main);
1894         ThreadScriptCheckQuit();
1895     }
1896     if (semOutbound)
1897         for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
1898             semOutbound->post();
1899     do
1900     {
1901         int nThreadsRunning = 0;
1902         for (int n = 0; n < THREAD_MAX; n++)
1903             nThreadsRunning += vnThreadsRunning[n];
1904         if (nThreadsRunning == 0)
1905             break;
1906         if (GetTime() - nStart > 20)
1907             break;
1908         Sleep(20);
1909     } while(true);
1910     if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
1911     if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
1912     if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
1913     if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n");
1914     if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n");
1915 #ifdef USE_UPNP
1916     if (vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
1917 #endif
1918     if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
1919     if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
1920     if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
1921     if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStakeMinter still running\n");
1922     if (vnThreadsRunning[THREAD_SCRIPTCHECK] > 0) printf("ThreadScriptCheck still running\n");
1923     while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0 || vnThreadsRunning[THREAD_SCRIPTCHECK] > 0)
1924         Sleep(20);
1925     Sleep(50);
1926     DumpAddresses();
1927     return true;
1928 }
1929
1930 class CNetCleanup
1931 {
1932 public:
1933     CNetCleanup()
1934     {
1935     }
1936     ~CNetCleanup()
1937     {
1938         // Close sockets
1939         BOOST_FOREACH(CNode* pnode, vNodes)
1940             if (pnode->hSocket != INVALID_SOCKET)
1941                 closesocket(pnode->hSocket);
1942         BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
1943             if (hListenSocket != INVALID_SOCKET)
1944                 if (closesocket(hListenSocket) == SOCKET_ERROR)
1945                     printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
1946
1947 #ifdef WIN32
1948         // Shutdown Windows Sockets
1949         WSACleanup();
1950 #endif
1951     }
1952 }
1953 instance_of_cnetcleanup;
1954
1955 void RelayTransaction(const CTransaction& tx, const uint256& hash)
1956 {
1957     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
1958     ss.reserve(10000);
1959     ss << tx;
1960     RelayTransaction(tx, hash, ss);
1961 }
1962
1963 void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
1964 {
1965     CInv inv(MSG_TX, hash);
1966     {
1967         LOCK(cs_mapRelay);
1968         // Expire old relay messages
1969         while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
1970         {
1971             mapRelay.erase(vRelayExpiration.front().second);
1972             vRelayExpiration.pop_front();
1973         }
1974
1975         // Save original serialized message so newer versions are preserved
1976         mapRelay.insert(std::make_pair(inv, ss));
1977         vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
1978     }
1979
1980     RelayInventory(inv);
1981 }
1982
1983 void CNode::RecordBytesRecv(uint64_t bytes)
1984 {
1985     LOCK(cs_totalBytesRecv);
1986     nTotalBytesRecv += bytes;
1987 }
1988
1989 void CNode::RecordBytesSent(uint64_t bytes)
1990 {
1991     LOCK(cs_totalBytesSent);
1992     nTotalBytesSent += bytes;
1993 }
1994
1995 uint64_t CNode::GetTotalBytesRecv()
1996 {
1997     LOCK(cs_totalBytesRecv);
1998     return nTotalBytesRecv;
1999 }
2000
2001 uint64_t CNode::GetTotalBytesSent()
2002 {
2003     LOCK(cs_totalBytesSent);
2004     return nTotalBytesSent;
2005 }