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