Fixes issue introduced in pull#90.
[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                     BOOST_FOREACH(CService& addrNode, *(it))
1473                         if (pnode->addr == addrNode)
1474                         {
1475                             it = lservAddressesToAdd.erase(it);
1476                             it--;
1477                             break;
1478                         }
1479         }
1480         BOOST_FOREACH(vector<CService>& vserv, lservAddressesToAdd)
1481         {
1482             if (vserv.size() == 0)
1483                 continue;
1484             CSemaphoreGrant grant(*semOutbound);
1485             OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
1486             Sleep(500);
1487             if (fShutdown)
1488                 return;
1489         }
1490         if (fShutdown)
1491             return;
1492         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1493         Sleep(120000); // Retry every 2 minutes
1494         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1495         if (fShutdown)
1496             return;
1497     }
1498 }
1499
1500 // if successful, this moves the passed grant to the constructed node
1501 bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot)
1502 {
1503     //
1504     // Initiate outbound network connection
1505     //
1506     if (fShutdown)
1507         return false;
1508     if (!strDest)
1509         if (IsLocal(addrConnect) ||
1510             FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
1511             FindNode(addrConnect.ToStringIPPort().c_str()))
1512             return false;
1513     if (strDest && FindNode(strDest))
1514         return false;
1515
1516     vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1517     CNode* pnode = ConnectNode(addrConnect, strDest);
1518     vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1519     if (fShutdown)
1520         return false;
1521     if (!pnode)
1522         return false;
1523     if (grantOutbound)
1524         grantOutbound->MoveTo(pnode->grantOutbound);
1525     pnode->fNetworkNode = true;
1526     if (fOneShot)
1527         pnode->fOneShot = true;
1528
1529     return true;
1530 }
1531
1532 // for now, use a very simple selection metric: the node from which we received
1533 // most recently
1534 double static NodeSyncScore(const CNode *pnode) {
1535     return -pnode->nLastRecv;
1536 }
1537
1538 void static StartSync(const vector<CNode*> &vNodes) {
1539     CNode *pnodeNewSync = NULL;
1540     double dBestScore = 0;
1541
1542     // Iterate over all nodes
1543     BOOST_FOREACH(CNode* pnode, vNodes) {
1544         // check preconditions for allowing a sync
1545         if (!pnode->fClient && !pnode->fOneShot &&
1546             !pnode->fDisconnect && pnode->fSuccessfullyConnected &&
1547             (pnode->nStartingHeight > (nBestHeight - 144)) &&
1548             (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
1549             // if ok, compare node's score with the best so far
1550             double dScore = NodeSyncScore(pnode);
1551             if (pnodeNewSync == NULL || dScore > dBestScore) {
1552                 pnodeNewSync = pnode;
1553                 dBestScore = dScore;
1554             }
1555         }
1556     }
1557     // if a new sync candidate was found, start sync!
1558     if (pnodeNewSync) {
1559         pnodeNewSync->fStartSync = true;
1560         pnodeSync = pnodeNewSync;
1561     }
1562 }
1563
1564 void ThreadMessageHandler(void* parg)
1565 {
1566     // Make this thread recognisable as the message handling thread
1567     RenameThread("novacoin-msghand");
1568
1569     try
1570     {
1571         vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1572         ThreadMessageHandler2(parg);
1573         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1574     }
1575     catch (std::exception& e) {
1576         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1577         PrintException(&e, "ThreadMessageHandler()");
1578     } catch (...) {
1579         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1580         PrintException(NULL, "ThreadMessageHandler()");
1581     }
1582     printf("ThreadMessageHandler exited\n");
1583 }
1584
1585 void ThreadMessageHandler2(void* parg)
1586 {
1587     printf("ThreadMessageHandler started\n");
1588     SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1589     while (!fShutdown)
1590     {
1591         bool fHaveSyncNode = false;
1592         vector<CNode*> vNodesCopy;
1593         {
1594             LOCK(cs_vNodes);
1595             vNodesCopy = vNodes;
1596             BOOST_FOREACH(CNode* pnode, vNodesCopy) {
1597                 pnode->AddRef();
1598                 if (pnode == pnodeSync)
1599                     fHaveSyncNode = true;
1600             }
1601         }
1602
1603         if (!fHaveSyncNode)
1604             StartSync(vNodesCopy);
1605
1606         // Poll the connected nodes for messages
1607         CNode* pnodeTrickle = NULL;
1608         if (!vNodesCopy.empty())
1609             pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
1610         BOOST_FOREACH(CNode* pnode, vNodesCopy)
1611         {
1612             // Receive messages
1613             {
1614                 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1615                 if (lockRecv)
1616                     ProcessMessages(pnode);
1617             }
1618             if (fShutdown)
1619                 return;
1620
1621             // Send messages
1622             {
1623                 TRY_LOCK(pnode->cs_vSend, lockSend);
1624                 if (lockSend)
1625                     SendMessages(pnode, pnode == pnodeTrickle);
1626             }
1627             if (fShutdown)
1628                 return;
1629         }
1630
1631         {
1632             LOCK(cs_vNodes);
1633             BOOST_FOREACH(CNode* pnode, vNodesCopy)
1634                 pnode->Release();
1635         }
1636
1637         // Wait and allow messages to bunch up.
1638         // Reduce vnThreadsRunning so StopNode has permission to exit while
1639         // we're sleeping, but we must always check fShutdown after doing this.
1640         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1641         Sleep(100);
1642         if (fRequestShutdown)
1643             StartShutdown();
1644         vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1645         if (fShutdown)
1646             return;
1647     }
1648 }
1649
1650
1651
1652
1653
1654
1655 bool BindListenPort(const CService &addrBind, string& strError)
1656 {
1657     strError = "";
1658     int nOne = 1;
1659
1660 #ifdef WIN32
1661     // Initialize Windows Sockets
1662     WSADATA wsadata;
1663     int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
1664     if (ret != NO_ERROR)
1665     {
1666         strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
1667         printf("%s\n", strError.c_str());
1668         return false;
1669     }
1670 #endif
1671
1672     // Create socket for listening for incoming connections
1673 #ifdef USE_IPV6
1674     struct sockaddr_storage sockaddr;
1675 #else
1676     struct sockaddr sockaddr;
1677 #endif
1678     socklen_t len = sizeof(sockaddr);
1679     if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
1680     {
1681         strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
1682         printf("%s\n", strError.c_str());
1683         return false;
1684     }
1685
1686     SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
1687     if (hListenSocket == INVALID_SOCKET)
1688     {
1689         strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
1690         printf("%s\n", strError.c_str());
1691         return false;
1692     }
1693
1694 #ifdef SO_NOSIGPIPE
1695     // Different way of disabling SIGPIPE on BSD
1696     setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
1697 #endif
1698
1699 #ifndef WIN32
1700     // Allow binding if the port is still in TIME_WAIT state after
1701     // the program was closed and restarted.  Not an issue on windows.
1702     setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
1703 #endif
1704
1705
1706 #ifdef WIN32
1707     // Set to non-blocking, incoming connections will also inherit this
1708     if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
1709 #else
1710     if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
1711 #endif
1712     {
1713         strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
1714         printf("%s\n", strError.c_str());
1715         return false;
1716     }
1717
1718 #ifdef USE_IPV6
1719     // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
1720     // and enable it by default or not. Try to enable it, if possible.
1721     if (addrBind.IsIPv6()) {
1722 #ifdef IPV6_V6ONLY
1723 #ifdef WIN32
1724         setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int));
1725 #else
1726         setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
1727 #endif
1728 #endif
1729 #ifdef WIN32
1730         int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
1731         int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
1732         // this call is allowed to fail
1733         setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
1734 #endif
1735     }
1736 #endif
1737
1738     if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
1739     {
1740         int nErr = WSAGetLastError();
1741         if (nErr == WSAEADDRINUSE)
1742             strError = strprintf(_("Unable to bind to %s on this computer. NovaCoin is probably already running."), addrBind.ToString().c_str());
1743         else
1744             strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr));
1745         printf("%s\n", strError.c_str());
1746         return false;
1747     }
1748     printf("Bound to %s\n", addrBind.ToString().c_str());
1749
1750     // Listen for incoming connections
1751     if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1752     {
1753         strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
1754         printf("%s\n", strError.c_str());
1755         return false;
1756     }
1757
1758     vhListenSocket.push_back(hListenSocket);
1759
1760     if (addrBind.IsRoutable() && fDiscover)
1761         AddLocal(addrBind, LOCAL_BIND);
1762
1763     return true;
1764 }
1765
1766 void static Discover()
1767 {
1768     if (!fDiscover)
1769         return;
1770
1771 #ifdef WIN32
1772     // Get local host IP
1773     char pszHostName[1000] = "";
1774     if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1775     {
1776         vector<CNetAddr> vaddr;
1777         if (LookupHost(pszHostName, vaddr))
1778         {
1779             BOOST_FOREACH (const CNetAddr &addr, vaddr)
1780             {
1781                 AddLocal(addr, LOCAL_IF);
1782             }
1783         }
1784     }
1785 #else
1786     // Get local host ip
1787     struct ifaddrs* myaddrs;
1788     if (getifaddrs(&myaddrs) == 0)
1789     {
1790         for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1791         {
1792             if (ifa->ifa_addr == NULL) continue;
1793             if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1794             if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1795             if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
1796             if (ifa->ifa_addr->sa_family == AF_INET)
1797             {
1798                 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
1799                 CNetAddr addr(s4->sin_addr);
1800                 if (AddLocal(addr, LOCAL_IF))
1801                     printf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1802             }
1803 #ifdef USE_IPV6
1804             else if (ifa->ifa_addr->sa_family == AF_INET6)
1805             {
1806                 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
1807                 CNetAddr addr(s6->sin6_addr);
1808                 if (AddLocal(addr, LOCAL_IF))
1809                     printf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1810             }
1811 #endif
1812         }
1813         freeifaddrs(myaddrs);
1814     }
1815 #endif
1816
1817     // Don't use external IPv4 discovery, when -onlynet="IPv6"
1818     if (!IsLimited(NET_IPV4))
1819         NewThread(ThreadGetMyExternalIP, NULL);
1820 }
1821
1822 void StartNode(void* parg)
1823 {
1824     // Make this thread recognisable as the startup thread
1825     RenameThread("novacoin-start");
1826
1827     if (semOutbound == NULL) {
1828         // initialize semaphore
1829         int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
1830         semOutbound = new CSemaphore(nMaxOutbound);
1831     }
1832
1833     if (pnodeLocalHost == NULL)
1834         pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
1835
1836     Discover();
1837
1838     //
1839     // Start threads
1840     //
1841
1842     if (!GetBoolArg("-dnsseed", true))
1843         printf("DNS seeding disabled\n");
1844     else
1845         if (!NewThread(ThreadDNSAddressSeed, NULL))
1846             printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
1847
1848     // Map ports with UPnP
1849     if (fUseUPnP)
1850         MapPort();
1851
1852     // Get addresses from IRC and advertise ours
1853     if (!NewThread(ThreadIRCSeed, NULL))
1854         printf("Error: NewThread(ThreadIRCSeed) failed\n");
1855
1856     // Send and receive from sockets, accept connections
1857     if (!NewThread(ThreadSocketHandler, NULL))
1858         printf("Error: NewThread(ThreadSocketHandler) failed\n");
1859
1860     // Initiate outbound connections from -addnode
1861     if (!NewThread(ThreadOpenAddedConnections, NULL))
1862         printf("Error: NewThread(ThreadOpenAddedConnections) failed\n");
1863
1864     // Initiate outbound connections
1865     if (!NewThread(ThreadOpenConnections, NULL))
1866         printf("Error: NewThread(ThreadOpenConnections) failed\n");
1867
1868     // Process messages
1869     if (!NewThread(ThreadMessageHandler, NULL))
1870         printf("Error: NewThread(ThreadMessageHandler) failed\n");
1871
1872     // Dump network addresses
1873     if (!NewThread(ThreadDumpAddress, NULL))
1874         printf("Error; NewThread(ThreadDumpAddress) failed\n");
1875
1876     // ppcoin: mint proof-of-stake blocks in the background
1877     if (!NewThread(ThreadStakeMinter, pwalletMain))
1878         printf("Error: NewThread(ThreadStakeMinter) failed\n");
1879 }
1880
1881 bool StopNode()
1882 {
1883     printf("StopNode()\n");
1884     fShutdown = true;
1885     nTransactionsUpdated++;
1886     int64_t nStart = GetTime();
1887     {
1888         LOCK(cs_main);
1889         ThreadScriptCheckQuit();
1890     }
1891     if (semOutbound)
1892         for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
1893             semOutbound->post();
1894     do
1895     {
1896         int nThreadsRunning = 0;
1897         for (int n = 0; n < THREAD_MAX; n++)
1898             nThreadsRunning += vnThreadsRunning[n];
1899         if (nThreadsRunning == 0)
1900             break;
1901         if (GetTime() - nStart > 20)
1902             break;
1903         Sleep(20);
1904     } while(true);
1905     if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
1906     if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
1907     if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
1908     if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n");
1909     if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n");
1910 #ifdef USE_UPNP
1911     if (vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
1912 #endif
1913     if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
1914     if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
1915     if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
1916     if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStakeMinter still running\n");
1917     if (vnThreadsRunning[THREAD_SCRIPTCHECK] > 0) printf("ThreadScriptCheck still running\n");
1918     while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0 || vnThreadsRunning[THREAD_SCRIPTCHECK] > 0)
1919         Sleep(20);
1920     Sleep(50);
1921     DumpAddresses();
1922     return true;
1923 }
1924
1925 class CNetCleanup
1926 {
1927 public:
1928     CNetCleanup()
1929     {
1930     }
1931     ~CNetCleanup()
1932     {
1933         // Close sockets
1934         BOOST_FOREACH(CNode* pnode, vNodes)
1935             if (pnode->hSocket != INVALID_SOCKET)
1936                 closesocket(pnode->hSocket);
1937         BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
1938             if (hListenSocket != INVALID_SOCKET)
1939                 if (closesocket(hListenSocket) == SOCKET_ERROR)
1940                     printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
1941
1942 #ifdef WIN32
1943         // Shutdown Windows Sockets
1944         WSACleanup();
1945 #endif
1946     }
1947 }
1948 instance_of_cnetcleanup;
1949
1950 void RelayTransaction(const CTransaction& tx, const uint256& hash)
1951 {
1952     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
1953     ss.reserve(10000);
1954     ss << tx;
1955     RelayTransaction(tx, hash, ss);
1956 }
1957
1958 void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
1959 {
1960     CInv inv(MSG_TX, hash);
1961     {
1962         LOCK(cs_mapRelay);
1963         // Expire old relay messages
1964         while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
1965         {
1966             mapRelay.erase(vRelayExpiration.front().second);
1967             vRelayExpiration.pop_front();
1968         }
1969
1970         // Save original serialized message so newer versions are preserved
1971         mapRelay.insert(std::make_pair(inv, ss));
1972         vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
1973     }
1974
1975     RelayInventory(inv);
1976 }
1977
1978 void CNode::RecordBytesRecv(uint64_t bytes)
1979 {
1980     LOCK(cs_totalBytesRecv);
1981     nTotalBytesRecv += bytes;
1982 }
1983
1984 void CNode::RecordBytesSent(uint64_t bytes)
1985 {
1986     LOCK(cs_totalBytesSent);
1987     nTotalBytesSent += bytes;
1988 }
1989
1990 uint64_t CNode::GetTotalBytesRecv()
1991 {
1992     LOCK(cs_totalBytesRecv);
1993     return nTotalBytesRecv;
1994 }
1995
1996 uint64_t CNode::GetTotalBytesSent()
1997 {
1998     LOCK(cs_totalBytesSent);
1999     return nTotalBytesSent;
2000 }