fix pnseed
[novacoin.git] / src / net.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2012 The PPCoin developers
4 // Copyright (c) 2012-2013 The NovaCoin developers
5 // Distributed under the MIT/X11 software license, see the accompanying
6 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
7
8 #include "irc.h"
9 #include "db.h"
10 #include "net.h"
11 #include "init.h"
12 #include "strlcpy.h"
13 #include "addrman.h"
14 #include "ui_interface.h"
15
16 #ifdef WIN32
17 #include <string.h>
18 #endif
19
20 #ifdef USE_UPNP
21 #include <miniupnpc/miniwget.h>
22 #include <miniupnpc/miniupnpc.h>
23 #include <miniupnpc/upnpcommands.h>
24 #include <miniupnpc/upnperrors.h>
25 #endif
26
27 using namespace std;
28 using namespace boost;
29
30 static const int MAX_OUTBOUND_CONNECTIONS = 8;
31
32 void ThreadMessageHandler2(void* parg);
33 void ThreadSocketHandler2(void* parg);
34 void ThreadOpenConnections2(void* parg);
35 void ThreadOpenAddedConnections2(void* parg);
36 #ifdef USE_UPNP
37 void ThreadMapPort2(void* parg);
38 #endif
39 void ThreadDNSAddressSeed2(void* parg);
40 bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant = true);
41
42
43
44 //
45 // Global state variables
46 //
47 bool fClient = false;
48 bool fAllowDNS = false;
49 static bool fUseUPnP = false;
50 uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
51 CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices);
52 CAddress addrSeenByPeer(CService("0.0.0.0", 0), nLocalServices);
53 static CNode* pnodeLocalHost = NULL;
54 uint64 nLocalHostNonce = 0;
55 array<int, THREAD_MAX> vnThreadsRunning;
56 static SOCKET hListenSocket = INVALID_SOCKET;
57 CAddrMan addrman;
58
59 vector<CNode*> vNodes;
60 CCriticalSection cs_vNodes;
61 map<CInv, CDataStream> mapRelay;
62 deque<pair<int64, CInv> > vRelayExpiration;
63 CCriticalSection cs_mapRelay;
64 map<CInv, int64> mapAlreadyAskedFor;
65
66
67 set<CNetAddr> setservAddNodeAddresses;
68 CCriticalSection cs_setservAddNodeAddresses;
69
70 static CSemaphore *semOutbound = NULL;
71
72 unsigned short GetListenPort()
73 {
74     return (unsigned short)(GetArg("-port", GetDefaultPort()));
75 }
76
77 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
78 {
79     // Filter out duplicate requests
80     if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
81         return;
82     pindexLastGetBlocksBegin = pindexBegin;
83     hashLastGetBlocksEnd = hashEnd;
84
85     PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
86 }
87
88
89
90 bool RecvLine(SOCKET hSocket, string& strLine)
91 {
92     strLine = "";
93     loop
94     {
95         char c;
96         int nBytes = recv(hSocket, &c, 1, 0);
97         if (nBytes > 0)
98         {
99             if (c == '\n')
100                 continue;
101             if (c == '\r')
102                 return true;
103             strLine += c;
104             if (strLine.size() >= 9000)
105                 return true;
106         }
107         else if (nBytes <= 0)
108         {
109             if (fShutdown)
110                 return false;
111             if (nBytes < 0)
112             {
113                 int nErr = WSAGetLastError();
114                 if (nErr == WSAEMSGSIZE)
115                     continue;
116                 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
117                 {
118                     Sleep(10);
119                     continue;
120                 }
121             }
122             if (!strLine.empty())
123                 return true;
124             if (nBytes == 0)
125             {
126                 // socket closed
127                 printf("socket closed\n");
128                 return false;
129             }
130             else
131             {
132                 // socket error
133                 int nErr = WSAGetLastError();
134                 printf("recv failed: %d\n", nErr);
135                 return false;
136             }
137         }
138     }
139 }
140
141
142
143 bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
144 {
145     SOCKET hSocket;
146     if (!ConnectSocket(addrConnect, hSocket))
147         return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());
148
149     send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);
150
151     string strLine;
152     while (RecvLine(hSocket, strLine))
153     {
154         if (strLine.empty()) // HTTP response is separated from headers by blank line
155         {
156             loop
157             {
158                 if (!RecvLine(hSocket, strLine))
159                 {
160                     closesocket(hSocket);
161                     return false;
162                 }
163                 if (pszKeyword == NULL)
164                     break;
165                 if (strLine.find(pszKeyword) != string::npos)
166                 {
167                     strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
168                     break;
169                 }
170             }
171             closesocket(hSocket);
172             if (strLine.find("<") != string::npos)
173                 strLine = strLine.substr(0, strLine.find("<"));
174             strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
175             while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
176                 strLine.resize(strLine.size()-1);
177             CService addr(strLine,0,true);
178             printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
179             if (!addr.IsValid() || !addr.IsRoutable())
180                 return false;
181             ipRet.SetIP(addr);
182             return true;
183         }
184     }
185     closesocket(hSocket);
186     return error("GetMyExternalIP() : connection closed");
187 }
188
189 // We now get our external IP from the IRC server first and only use this as a backup
190 bool GetMyExternalIP(CNetAddr& ipRet)
191 {
192     CService addrConnect;
193     const char* pszGet;
194     const char* pszKeyword;
195
196     if (fNoListen||fUseProxy)
197         return false;
198
199     for (int nLookup = 0; nLookup <= 1; nLookup++)
200     for (int nHost = 1; nHost <= 2; nHost++)
201     {
202         // We should be phasing out our use of sites like these.  If we need
203         // replacements, we should ask for volunteers to put this simple
204         // php file on their webserver that prints the client IP:
205         //  <?php echo $_SERVER["REMOTE_ADDR"]; ?>
206         if (nHost == 1)
207         {
208             addrConnect = CService("91.198.22.70",80); // checkip.dyndns.org
209
210             if (nLookup == 1)
211             {
212                 CService addrIP("checkip.dyndns.org", 80, true);
213                 if (addrIP.IsValid())
214                     addrConnect = addrIP;
215             }
216
217             pszGet = "GET / HTTP/1.1\r\n"
218                      "Host: checkip.dyndns.org\r\n"
219                      "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
220                      "Connection: close\r\n"
221                      "\r\n";
222
223             pszKeyword = "Address:";
224         }
225         else if (nHost == 2)
226         {
227             addrConnect = CService("74.208.43.192", 80); // www.showmyip.com
228
229             if (nLookup == 1)
230             {
231                 CService addrIP("www.showmyip.com", 80, true);
232                 if (addrIP.IsValid())
233                     addrConnect = addrIP;
234             }
235
236             pszGet = "GET /simple/ HTTP/1.1\r\n"
237                      "Host: www.showmyip.com\r\n"
238                      "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
239                      "Connection: close\r\n"
240                      "\r\n";
241
242             pszKeyword = NULL; // Returns just IP address
243         }
244
245         if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
246             return true;
247     }
248
249     return false;
250 }
251
252 void ThreadGetMyExternalIP(void* parg)
253 {
254     // Wait for IRC to get it first
255     if (GetBoolArg("-irc", true))
256     {
257         for (int i = 0; i < 2 * 60; i++)
258         {
259             Sleep(1000);
260             if (fGotExternalIP || fShutdown)
261                 return;
262         }
263     }
264
265     // Fallback in case IRC fails to get it
266     if (GetMyExternalIP(addrLocalHost))
267     {
268         printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
269         if (addrLocalHost.IsRoutable())
270         {
271             // If we already connected to a few before we had our IP, go back and addr them.
272             // setAddrKnown automatically filters any duplicate sends.
273             CAddress addr(addrLocalHost);
274             addr.nTime = GetAdjustedTime();
275             {
276                 LOCK(cs_vNodes);
277                 BOOST_FOREACH(CNode* pnode, vNodes)
278                     pnode->PushAddress(addr);
279             }
280         }
281     }
282 }
283
284
285
286
287
288 void AddressCurrentlyConnected(const CService& addr)
289 {
290     addrman.Connected(addr);
291 }
292
293
294
295
296
297
298
299 CNode* FindNode(const CNetAddr& ip)
300 {
301     {
302         LOCK(cs_vNodes);
303         BOOST_FOREACH(CNode* pnode, vNodes)
304             if ((CNetAddr)pnode->addr == ip)
305                 return (pnode);
306     }
307     return NULL;
308 }
309
310 CNode* FindNode(const CService& addr)
311 {
312     {
313         LOCK(cs_vNodes);
314         BOOST_FOREACH(CNode* pnode, vNodes)
315             if ((CService)pnode->addr == addr)
316                 return (pnode);
317     }
318     return NULL;
319 }
320
321 CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
322 {
323     if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost)
324         return NULL;
325
326     // Look for an existing connection
327     CNode* pnode = FindNode((CService)addrConnect);
328     if (pnode)
329     {
330         if (nTimeout != 0)
331             pnode->AddRef(nTimeout);
332         else
333             pnode->AddRef();
334         return pnode;
335     }
336
337     /// debug print
338     printf("trying connection %s lastseen=%.1fhrs\n",
339         addrConnect.ToString().c_str(),
340         (double)(addrConnect.nTime - GetAdjustedTime())/3600.0);
341
342     addrman.Attempt(addrConnect);
343
344     // Connect
345     SOCKET hSocket;
346     if (ConnectSocket(addrConnect, hSocket))
347     {
348         /// debug print
349         printf("connected %s\n", addrConnect.ToString().c_str());
350
351         // Set to nonblocking
352 #ifdef WIN32
353         u_long nOne = 1;
354         if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
355             printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
356 #else
357         if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
358             printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno);
359 #endif
360
361         // Add node
362         CNode* pnode = new CNode(hSocket, addrConnect, false);
363         if (nTimeout != 0)
364             pnode->AddRef(nTimeout);
365         else
366             pnode->AddRef();
367         {
368             LOCK(cs_vNodes);
369             vNodes.push_back(pnode);
370         }
371
372         pnode->nTimeConnected = GetTime();
373         return pnode;
374     }
375     else
376     {
377         return NULL;
378     }
379 }
380
381 void CNode::CloseSocketDisconnect()
382 {
383     fDisconnect = true;
384     if (hSocket != INVALID_SOCKET)
385     {
386         if (fDebug)
387             printf("%s ", DateTimeStrFormat(GetTime()).c_str());
388         printf("disconnecting node %s\n", addr.ToString().c_str());
389         closesocket(hSocket);
390         hSocket = INVALID_SOCKET;
391         vRecv.clear();
392     }
393 }
394
395 void CNode::Cleanup()
396 {
397 }
398
399
400 void CNode::PushVersion()
401 {
402     /// when NTP implemented, change to just nTime = GetAdjustedTime()
403     int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
404     CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr);
405     CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress(CService("0.0.0.0",0)) : addrLocalHost);
406     RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
407     PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
408                 nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
409 }
410
411
412
413
414
415 std::map<CNetAddr, int64> CNode::setBanned;
416 CCriticalSection CNode::cs_setBanned;
417
418 void CNode::ClearBanned()
419 {
420     setBanned.clear();
421 }
422
423 bool CNode::IsBanned(CNetAddr ip)
424 {
425     bool fResult = false;
426     {
427         LOCK(cs_setBanned);
428         std::map<CNetAddr, int64>::iterator i = setBanned.find(ip);
429         if (i != setBanned.end())
430         {
431             int64 t = (*i).second;
432             if (GetTime() < t)
433                 fResult = true;
434         }
435     }
436     return fResult;
437 }
438
439 bool CNode::Misbehaving(int howmuch)
440 {
441     if (addr.IsLocal())
442     {
443         printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
444         return false;
445     }
446
447     nMisbehavior += howmuch;
448     if (nMisbehavior >= GetArg("-banscore", 100))
449     {
450         int64 banTime = GetTime()+GetArg("-bantime", 60*60*24);  // Default 24-hour ban
451         {
452             LOCK(cs_setBanned);
453             if (setBanned[addr] < banTime)
454                 setBanned[addr] = banTime;
455         }
456         CloseSocketDisconnect();
457         printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
458         return true;
459     }
460     return false;
461 }
462
463
464
465
466
467
468
469
470
471
472
473
474 void ThreadSocketHandler(void* parg)
475 {
476     IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
477     try
478     {
479         vnThreadsRunning[THREAD_SOCKETHANDLER]++;
480         ThreadSocketHandler2(parg);
481         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
482     }
483     catch (std::exception& e) {
484         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
485         PrintException(&e, "ThreadSocketHandler()");
486     } catch (...) {
487         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
488         throw; // support pthread_cancel()
489     }
490     printf("ThreadSocketHandler exiting\n");
491 }
492
493 void ThreadSocketHandler2(void* parg)
494 {
495     printf("ThreadSocketHandler started\n");
496     list<CNode*> vNodesDisconnected;
497     unsigned int nPrevNodeCount = 0;
498
499     loop
500     {
501         //
502         // Disconnect nodes
503         //
504         {
505             LOCK(cs_vNodes);
506             // Disconnect unused nodes
507             vector<CNode*> vNodesCopy = vNodes;
508             BOOST_FOREACH(CNode* pnode, vNodesCopy)
509             {
510                 if (pnode->fDisconnect ||
511                     (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
512                 {
513                     // remove from vNodes
514                     vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
515
516                     if (pnode->fHasGrant)
517                         semOutbound->post();
518                     pnode->fHasGrant = false;
519
520                     // close socket and cleanup
521                     pnode->CloseSocketDisconnect();
522                     pnode->Cleanup();
523
524                     // hold in disconnected pool until all refs are released
525                     pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
526                     if (pnode->fNetworkNode || pnode->fInbound)
527                         pnode->Release();
528                     vNodesDisconnected.push_back(pnode);
529                 }
530             }
531
532             // Delete disconnected nodes
533             list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
534             BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
535             {
536                 // wait until threads are done using it
537                 if (pnode->GetRefCount() <= 0)
538                 {
539                     bool fDelete = false;
540                     {
541                         TRY_LOCK(pnode->cs_vSend, lockSend);
542                         if (lockSend)
543                         {
544                             TRY_LOCK(pnode->cs_vRecv, lockRecv);
545                             if (lockRecv)
546                             {
547                                 TRY_LOCK(pnode->cs_mapRequests, lockReq);
548                                 if (lockReq)
549                                 {
550                                     TRY_LOCK(pnode->cs_inventory, lockInv);
551                                     if (lockInv)
552                                         fDelete = true;
553                                 }
554                             }
555                         }
556                     }
557                     if (fDelete)
558                     {
559                         vNodesDisconnected.remove(pnode);
560                         delete pnode;
561                     }
562                 }
563             }
564         }
565         if (vNodes.size() != nPrevNodeCount)
566         {
567             nPrevNodeCount = vNodes.size();
568             MainFrameRepaint();
569         }
570
571
572         //
573         // Find which sockets have data to receive
574         //
575         struct timeval timeout;
576         timeout.tv_sec  = 0;
577         timeout.tv_usec = 50000; // frequency to poll pnode->vSend
578
579         fd_set fdsetRecv;
580         fd_set fdsetSend;
581         fd_set fdsetError;
582         FD_ZERO(&fdsetRecv);
583         FD_ZERO(&fdsetSend);
584         FD_ZERO(&fdsetError);
585         SOCKET hSocketMax = 0;
586
587         if(hListenSocket != INVALID_SOCKET)
588             FD_SET(hListenSocket, &fdsetRecv);
589         hSocketMax = max(hSocketMax, hListenSocket);
590         {
591             LOCK(cs_vNodes);
592             BOOST_FOREACH(CNode* pnode, vNodes)
593             {
594                 if (pnode->hSocket == INVALID_SOCKET)
595                     continue;
596                 FD_SET(pnode->hSocket, &fdsetRecv);
597                 FD_SET(pnode->hSocket, &fdsetError);
598                 hSocketMax = max(hSocketMax, pnode->hSocket);
599                 {
600                     TRY_LOCK(pnode->cs_vSend, lockSend);
601                     if (lockSend && !pnode->vSend.empty())
602                         FD_SET(pnode->hSocket, &fdsetSend);
603                 }
604             }
605         }
606
607         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
608         int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
609         vnThreadsRunning[THREAD_SOCKETHANDLER]++;
610         if (fShutdown)
611             return;
612         if (nSelect == SOCKET_ERROR)
613         {
614             int nErr = WSAGetLastError();
615             if (hSocketMax != INVALID_SOCKET)
616             {
617                 printf("socket select error %d\n", nErr);
618                 for (unsigned int i = 0; i <= hSocketMax; i++)
619                     FD_SET(i, &fdsetRecv);
620             }
621             FD_ZERO(&fdsetSend);
622             FD_ZERO(&fdsetError);
623             Sleep(timeout.tv_usec/1000);
624         }
625
626
627         //
628         // Accept new connections
629         //
630         if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
631         {
632             struct sockaddr_in sockaddr;
633             socklen_t len = sizeof(sockaddr);
634             SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
635             CAddress addr;
636             int nInbound = 0;
637
638             if (hSocket != INVALID_SOCKET)
639                 addr = CAddress(sockaddr);
640
641             {
642                 LOCK(cs_vNodes);
643                 BOOST_FOREACH(CNode* pnode, vNodes)
644                     if (pnode->fInbound)
645                         nInbound++;
646             }
647
648             if (hSocket == INVALID_SOCKET)
649             {
650                 if (WSAGetLastError() != WSAEWOULDBLOCK)
651                     printf("socket error accept failed: %d\n", WSAGetLastError());
652             }
653             else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
654             {
655                 {
656                     LOCK(cs_setservAddNodeAddresses);
657                     if (!setservAddNodeAddresses.count(addr))
658                         closesocket(hSocket);
659                 }
660             }
661             else if (CNode::IsBanned(addr))
662             {
663                 printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
664                 closesocket(hSocket);
665             }
666             else
667             {
668                 printf("accepted connection %s\n", addr.ToString().c_str());
669                 CNode* pnode = new CNode(hSocket, addr, true);
670                 pnode->AddRef();
671                 {
672                     LOCK(cs_vNodes);
673                     vNodes.push_back(pnode);
674                 }
675             }
676         }
677
678
679         //
680         // Service each socket
681         //
682         vector<CNode*> vNodesCopy;
683         {
684             LOCK(cs_vNodes);
685             vNodesCopy = vNodes;
686             BOOST_FOREACH(CNode* pnode, vNodesCopy)
687                 pnode->AddRef();
688         }
689         BOOST_FOREACH(CNode* pnode, vNodesCopy)
690         {
691             if (fShutdown)
692                 return;
693
694             //
695             // Receive
696             //
697             if (pnode->hSocket == INVALID_SOCKET)
698                 continue;
699             if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
700             {
701                 TRY_LOCK(pnode->cs_vRecv, lockRecv);
702                 if (lockRecv)
703                 {
704                     CDataStream& vRecv = pnode->vRecv;
705                     unsigned int nPos = vRecv.size();
706
707                     if (nPos > ReceiveBufferSize()) {
708                         if (!pnode->fDisconnect)
709                             printf("socket recv flood control disconnect (%d bytes)\n", vRecv.size());
710                         pnode->CloseSocketDisconnect();
711                     }
712                     else {
713                         // typical socket buffer is 8K-64K
714                         char pchBuf[0x10000];
715                         int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
716                         if (nBytes > 0)
717                         {
718                             vRecv.resize(nPos + nBytes);
719                             memcpy(&vRecv[nPos], pchBuf, nBytes);
720                             pnode->nLastRecv = GetTime();
721                         }
722                         else if (nBytes == 0)
723                         {
724                             // socket closed gracefully
725                             if (!pnode->fDisconnect)
726                                 printf("socket closed\n");
727                             pnode->CloseSocketDisconnect();
728                         }
729                         else if (nBytes < 0)
730                         {
731                             // error
732                             int nErr = WSAGetLastError();
733                             if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
734                             {
735                                 if (!pnode->fDisconnect)
736                                     printf("socket recv error %d\n", nErr);
737                                 pnode->CloseSocketDisconnect();
738                             }
739                         }
740                     }
741                 }
742             }
743
744             //
745             // Send
746             //
747             if (pnode->hSocket == INVALID_SOCKET)
748                 continue;
749             if (FD_ISSET(pnode->hSocket, &fdsetSend))
750             {
751                 TRY_LOCK(pnode->cs_vSend, lockSend);
752                 if (lockSend)
753                 {
754                     CDataStream& vSend = pnode->vSend;
755                     if (!vSend.empty())
756                     {
757                         int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
758                         if (nBytes > 0)
759                         {
760                             vSend.erase(vSend.begin(), vSend.begin() + nBytes);
761                             pnode->nLastSend = GetTime();
762                         }
763                         else if (nBytes < 0)
764                         {
765                             // error
766                             int nErr = WSAGetLastError();
767                             if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
768                             {
769                                 printf("socket send error %d\n", nErr);
770                                 pnode->CloseSocketDisconnect();
771                             }
772                         }
773                         if (vSend.size() > SendBufferSize()) {
774                             if (!pnode->fDisconnect)
775                                 printf("socket send flood control disconnect (%d bytes)\n", vSend.size());
776                             pnode->CloseSocketDisconnect();
777                         }
778                     }
779                 }
780             }
781
782             //
783             // Inactivity checking
784             //
785             if (pnode->vSend.empty())
786                 pnode->nLastSendEmpty = GetTime();
787             if (GetTime() - pnode->nTimeConnected > 60)
788             {
789                 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
790                 {
791                     printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
792                     pnode->fDisconnect = true;
793                 }
794                 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
795                 {
796                     printf("socket not sending\n");
797                     pnode->fDisconnect = true;
798                 }
799                 else if (GetTime() - pnode->nLastRecv > 90*60)
800                 {
801                     printf("socket inactivity timeout\n");
802                     pnode->fDisconnect = true;
803                 }
804             }
805         }
806         {
807             LOCK(cs_vNodes);
808             BOOST_FOREACH(CNode* pnode, vNodesCopy)
809                 pnode->Release();
810         }
811
812         Sleep(10);
813     }
814 }
815
816
817
818
819
820
821
822
823
824 #ifdef USE_UPNP
825 void ThreadMapPort(void* parg)
826 {
827     IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg));
828     try
829     {
830         vnThreadsRunning[THREAD_UPNP]++;
831         ThreadMapPort2(parg);
832         vnThreadsRunning[THREAD_UPNP]--;
833     }
834     catch (std::exception& e) {
835         vnThreadsRunning[THREAD_UPNP]--;
836         PrintException(&e, "ThreadMapPort()");
837     } catch (...) {
838         vnThreadsRunning[THREAD_UPNP]--;
839         PrintException(NULL, "ThreadMapPort()");
840     }
841     printf("ThreadMapPort exiting\n");
842 }
843
844 void ThreadMapPort2(void* parg)
845 {
846     printf("ThreadMapPort started\n");
847
848     char port[6];
849     sprintf(port, "%d", GetListenPort());
850
851     const char * multicastif = 0;
852     const char * minissdpdpath = 0;
853     struct UPNPDev * devlist = 0;
854     char lanaddr[64];
855
856 #ifndef UPNPDISCOVER_SUCCESS
857     /* miniupnpc 1.5 */
858     devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
859 #else
860     /* miniupnpc 1.6 */
861     int error = 0;
862     devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
863 #endif
864
865     struct UPNPUrls urls;
866     struct IGDdatas data;
867     int r;
868
869     r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
870     if (r == 1)
871     {
872         if (!addrLocalHost.IsRoutable())
873         {
874             char externalIPAddress[40];
875             r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
876             if(r != UPNPCOMMAND_SUCCESS)
877                 printf("UPnP: GetExternalIPAddress() returned %d\n", r);
878             else
879             {
880                 if(externalIPAddress[0])
881                 {
882                     printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
883                     CAddress addrExternalFromUPnP(CService(externalIPAddress, 0), nLocalServices);
884                     if (addrExternalFromUPnP.IsRoutable())
885                         addrLocalHost = addrExternalFromUPnP;
886                 }
887                 else
888                     printf("UPnP: GetExternalIPAddress failed.\n");
889             }
890         }
891
892         string strDesc = "NovaCoin " + FormatFullVersion();
893 #ifndef UPNPDISCOVER_SUCCESS
894         /* miniupnpc 1.5 */
895         r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
896                             port, port, lanaddr, strDesc.c_str(), "TCP", 0);
897 #else
898         /* miniupnpc 1.6 */
899         r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
900                             port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
901 #endif
902
903         if(r!=UPNPCOMMAND_SUCCESS)
904             printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
905                 port, port, lanaddr, r, strupnperror(r));
906         else
907             printf("UPnP Port Mapping successful.\n");
908         int i = 1;
909         loop {
910             if (fShutdown || !fUseUPnP)
911             {
912                 r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port, "TCP", 0);
913                 printf("UPNP_DeletePortMapping() returned : %d\n", r);
914                 freeUPNPDevlist(devlist); devlist = 0;
915                 FreeUPNPUrls(&urls);
916                 return;
917             }
918             if (i % 600 == 0) // Refresh every 20 minutes
919             {
920 #ifndef UPNPDISCOVER_SUCCESS
921                 /* miniupnpc 1.5 */
922                 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
923                                     port, port, lanaddr, strDesc.c_str(), "TCP", 0);
924 #else
925                 /* miniupnpc 1.6 */
926                 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
927                                     port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
928 #endif
929
930                 if(r!=UPNPCOMMAND_SUCCESS)
931                     printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
932                         port, port, lanaddr, r, strupnperror(r));
933                 else
934                     printf("UPnP Port Mapping successful.\n");;
935             }
936             Sleep(2000);
937             i++;
938         }
939     } else {
940         printf("No valid UPnP IGDs found\n");
941         freeUPNPDevlist(devlist); devlist = 0;
942         if (r != 0)
943             FreeUPNPUrls(&urls);
944         loop {
945             if (fShutdown || !fUseUPnP)
946                 return;
947             Sleep(2000);
948         }
949     }
950 }
951
952 void MapPort(bool fMapPort)
953 {
954     if (fUseUPnP != fMapPort)
955     {
956         fUseUPnP = fMapPort;
957     }
958     if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1)
959     {
960         if (!CreateThread(ThreadMapPort, NULL))
961             printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
962     }
963 }
964 #else
965 void MapPort(bool /* unused fMapPort */)
966 {
967     // Intentionally left blank.
968 }
969 #endif
970
971
972
973
974
975
976
977
978
979 // DNS seeds
980 // Each pair gives a source name and a seed name.
981 // The first name is used as information source for addrman.
982 // The second name should resolve to a list of seed addresses.
983 // testnet dns seed begins with 't', all else are ppcoin dns seeds.
984 static const char *strDNSSeed[][2] = {
985     {"seed", "xxx"}
986 };
987
988 void ThreadDNSAddressSeed(void* parg)
989 {
990     IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg));
991     try
992     {
993         vnThreadsRunning[THREAD_DNSSEED]++;
994         ThreadDNSAddressSeed2(parg);
995         vnThreadsRunning[THREAD_DNSSEED]--;
996     }
997     catch (std::exception& e) {
998         vnThreadsRunning[THREAD_DNSSEED]--;
999         PrintException(&e, "ThreadDNSAddressSeed()");
1000     } catch (...) {
1001         vnThreadsRunning[THREAD_DNSSEED]--;
1002         throw; // support pthread_cancel()
1003     }
1004     printf("ThreadDNSAddressSeed exiting\n");
1005 }
1006
1007 void ThreadDNSAddressSeed2(void* parg)
1008 {
1009     printf("ThreadDNSAddressSeed started\n");
1010     int found = 0;
1011
1012     if (true && !fTestNet)
1013     {
1014         printf("Loading addresses from DNS seeds (could take a while)\n");
1015
1016         for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
1017             if (fTestNet && strDNSSeed[seed_idx][1][0] != 't') continue;
1018             if ((!fTestNet) && strDNSSeed[seed_idx][1][0] == 't') continue;
1019
1020             vector<CNetAddr> vaddr;
1021             vector<CAddress> vAdd;
1022             if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
1023             {
1024                 BOOST_FOREACH(CNetAddr& ip, vaddr)
1025                 {
1026                     int nOneDay = 24*3600;
1027                     CAddress addr = CAddress(CService(ip, GetDefaultPort()));
1028                     addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
1029                     vAdd.push_back(addr);
1030                     found++;
1031                 }
1032             }
1033             addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
1034         }
1035     }
1036
1037     printf("%d addresses found from DNS seeds\n", found);
1038 }
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051 unsigned int pnSeed[] =
1052 {
1053     0x90EF78BC,
1054 };
1055
1056 void DumpAddresses()
1057 {
1058     CAddrDB adb;
1059     adb.WriteAddrman(addrman);
1060 }
1061
1062 void ThreadDumpAddress2(void* parg)
1063 {
1064     vnThreadsRunning[THREAD_DUMPADDRESS]++;
1065     while (!fShutdown)
1066     {
1067         DumpAddresses();
1068         vnThreadsRunning[THREAD_DUMPADDRESS]--;
1069         Sleep(100000);
1070         vnThreadsRunning[THREAD_DUMPADDRESS]++;
1071     }
1072     vnThreadsRunning[THREAD_DUMPADDRESS]--;
1073 }
1074
1075 void ThreadDumpAddress(void* parg)
1076 {
1077     IMPLEMENT_RANDOMIZE_STACK(ThreadDumpAddress(parg));
1078     try
1079     {
1080         ThreadDumpAddress2(parg);
1081     }
1082     catch (std::exception& e) {
1083         PrintException(&e, "ThreadDumpAddress()");
1084     }
1085     printf("ThreadDumpAddress exiting\n");
1086 }
1087
1088 void ThreadOpenConnections(void* parg)
1089 {
1090     IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
1091     try
1092     {
1093         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1094         ThreadOpenConnections2(parg);
1095         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1096     }
1097     catch (std::exception& e) {
1098         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1099         PrintException(&e, "ThreadOpenConnections()");
1100     } catch (...) {
1101         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1102         PrintException(NULL, "ThreadOpenConnections()");
1103     }
1104     printf("ThreadOpenConnections exiting\n");
1105 }
1106
1107 void ThreadOpenConnections2(void* parg)
1108 {
1109     printf("ThreadOpenConnections started\n");
1110
1111     // Connect to specific addresses
1112     if (mapArgs.count("-connect"))
1113     {
1114         for (int64 nLoop = 0;; nLoop++)
1115         {
1116             BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
1117             {
1118                 CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
1119                 if (addr.IsValid())
1120                     OpenNetworkConnection(addr, false);
1121                 for (int i = 0; i < 10 && i < nLoop; i++)
1122                 {
1123                     Sleep(500);
1124                     if (fShutdown)
1125                         return;
1126                 }
1127             }
1128         }
1129     }
1130
1131     // Initiate network connections
1132     int64 nStart = GetTime();
1133     loop
1134     {
1135         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1136         Sleep(500);
1137         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1138         if (fShutdown)
1139             return;
1140
1141
1142         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1143         semOutbound->wait();
1144         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1145         if (fShutdown)
1146             return;
1147
1148         // Add seed nodes if IRC isn't working
1149         bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
1150         if (addrman.size()==0 && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
1151         {
1152             std::vector<CAddress> vAdd;
1153             for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
1154             {
1155                 // It'll only connect to one or two seed nodes because once it connects,
1156                 // it'll get a pile of addresses with newer timestamps.
1157                 // Seed nodes are given a random 'last seen time' of between one and two
1158                 // weeks ago.
1159                 const int64 nOneWeek = 7*24*60*60;
1160                 struct in_addr ip;
1161                 memcpy(&ip, &pnSeed[i], sizeof(ip));
1162                 CAddress addr(CService(ip, GetDefaultPort()));
1163                 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1164                 vAdd.push_back(addr);
1165             }
1166             addrman.Add(vAdd, CNetAddr("127.0.0.1"));
1167         }
1168
1169         //
1170         // Choose an address to connect to based on most recently seen
1171         //
1172         CAddress addrConnect;
1173
1174         // Only connect to one address per a.b.?.? range.
1175         // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
1176         int nOutbound = 0;
1177         set<vector<unsigned char> > setConnected;
1178         {
1179             LOCK(cs_vNodes);
1180             BOOST_FOREACH(CNode* pnode, vNodes) {
1181                 setConnected.insert(pnode->addr.GetGroup());
1182                 if (!pnode->fInbound)
1183                     nOutbound++;
1184             }
1185         }
1186
1187         int64 nANow = GetAdjustedTime();
1188
1189         int nTries = 0;
1190         loop
1191         {
1192             // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
1193             CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
1194
1195             // if we selected an invalid address, restart
1196             if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || addr == addrLocalHost)
1197                 break;
1198
1199             nTries++;
1200
1201             // only consider very recently tried nodes after 30 failed attempts
1202             if (nANow - addr.nLastTry < 600 && nTries < 30)
1203                 continue;
1204
1205             // do not allow non-default ports, unless after 50 invalid addresses selected already
1206             if (addr.GetPort() != GetDefaultPort() && nTries < 50)
1207                 continue;
1208
1209             addrConnect = addr;
1210             break;
1211         }
1212
1213         if (addrConnect.IsValid())
1214             OpenNetworkConnection(addrConnect);
1215         else
1216             semOutbound->post();
1217     }
1218 }
1219
1220 void ThreadOpenAddedConnections(void* parg)
1221 {
1222     IMPLEMENT_RANDOMIZE_STACK(ThreadOpenAddedConnections(parg));
1223     try
1224     {
1225         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1226         ThreadOpenAddedConnections2(parg);
1227         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1228     }
1229     catch (std::exception& e) {
1230         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1231         PrintException(&e, "ThreadOpenAddedConnections()");
1232     } catch (...) {
1233         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1234         PrintException(NULL, "ThreadOpenAddedConnections()");
1235     }
1236     printf("ThreadOpenAddedConnections exiting\n");
1237 }
1238
1239 void ThreadOpenAddedConnections2(void* parg)
1240 {
1241     printf("ThreadOpenAddedConnections started\n");
1242
1243     if (mapArgs.count("-addnode") == 0)
1244         return;
1245
1246     vector<vector<CService> > vservAddressesToAdd(0);
1247     BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"])
1248     {
1249         vector<CService> vservNode(0);
1250         if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0))
1251         {
1252             vservAddressesToAdd.push_back(vservNode);
1253             {
1254                 LOCK(cs_setservAddNodeAddresses);
1255                 BOOST_FOREACH(CService& serv, vservNode)
1256                     setservAddNodeAddresses.insert(serv);
1257             }
1258         }
1259     }
1260     loop
1261     {
1262         vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd;
1263         // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
1264         // (keeping in mind that addnode entries can have many IPs if fAllowDNS)
1265         {
1266             LOCK(cs_vNodes);
1267             BOOST_FOREACH(CNode* pnode, vNodes)
1268                 for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
1269                     BOOST_FOREACH(CService& addrNode, *(it))
1270                         if (pnode->addr == addrNode)
1271                         {
1272                             it = vservConnectAddresses.erase(it);
1273                             it--;
1274                             break;
1275                         }
1276         }
1277         BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
1278         {
1279             semOutbound->wait();
1280             OpenNetworkConnection(CAddress(*(vserv.begin())));
1281             Sleep(500);
1282             if (fShutdown)
1283                 return;
1284         }
1285         if (fShutdown)
1286             return;
1287         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1288         Sleep(120000); // Retry every 2 minutes
1289         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1290         if (fShutdown)
1291             return;
1292     }
1293 }
1294
1295 bool static ReleaseGrant(bool fUseGrant) {
1296     if (fUseGrant)
1297         semOutbound->post();
1298     return false;
1299 }
1300
1301 // only call this function when semOutbound has been waited for
1302 bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant)
1303 {
1304     //
1305     // Initiate outbound network connection
1306     //
1307     if (fShutdown)
1308         return false;
1309     if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
1310         FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
1311         return ReleaseGrant(fUseGrant);
1312
1313     vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1314     CNode* pnode = ConnectNode(addrConnect);
1315     vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1316     if (fShutdown)
1317         return false;
1318     if (!pnode)
1319         return ReleaseGrant(fUseGrant);
1320     if (pnode->fHasGrant) {
1321         // node already has connection grant, release the one that was passed to us
1322         ReleaseGrant(fUseGrant);
1323     } else {
1324         pnode->fHasGrant = fUseGrant;
1325     }
1326     pnode->fNetworkNode = true;
1327
1328     return true;
1329 }
1330
1331
1332
1333
1334
1335
1336
1337
1338 void ThreadMessageHandler(void* parg)
1339 {
1340     IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
1341     try
1342     {
1343         vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1344         ThreadMessageHandler2(parg);
1345         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1346     }
1347     catch (std::exception& e) {
1348         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1349         PrintException(&e, "ThreadMessageHandler()");
1350     } catch (...) {
1351         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1352         PrintException(NULL, "ThreadMessageHandler()");
1353     }
1354     printf("ThreadMessageHandler exiting\n");
1355 }
1356
1357 void ThreadMessageHandler2(void* parg)
1358 {
1359     printf("ThreadMessageHandler started\n");
1360     SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1361     while (!fShutdown)
1362     {
1363         vector<CNode*> vNodesCopy;
1364         {
1365             LOCK(cs_vNodes);
1366             vNodesCopy = vNodes;
1367             BOOST_FOREACH(CNode* pnode, vNodesCopy)
1368                 pnode->AddRef();
1369         }
1370
1371         // Poll the connected nodes for messages
1372         CNode* pnodeTrickle = NULL;
1373         if (!vNodesCopy.empty())
1374             pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
1375         BOOST_FOREACH(CNode* pnode, vNodesCopy)
1376         {
1377             // Receive messages
1378             {
1379                 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1380                 if (lockRecv)
1381                     ProcessMessages(pnode);
1382             }
1383             if (fShutdown)
1384                 return;
1385
1386             // Send messages
1387             {
1388                 TRY_LOCK(pnode->cs_vSend, lockSend);
1389                 if (lockSend)
1390                     SendMessages(pnode, pnode == pnodeTrickle);
1391             }
1392             if (fShutdown)
1393                 return;
1394         }
1395
1396         {
1397             LOCK(cs_vNodes);
1398             BOOST_FOREACH(CNode* pnode, vNodesCopy)
1399                 pnode->Release();
1400         }
1401
1402         // Wait and allow messages to bunch up.
1403         // Reduce vnThreadsRunning so StopNode has permission to exit while
1404         // we're sleeping, but we must always check fShutdown after doing this.
1405         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1406         Sleep(100);
1407         if (fRequestShutdown)
1408             StartShutdown();
1409         vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1410         if (fShutdown)
1411             return;
1412     }
1413 }
1414
1415 // ppcoin: stake minter thread
1416 void static ThreadStakeMinter(void* parg)
1417 {
1418     printf("ThreadStakeMinter started\n");
1419     CWallet* pwallet = (CWallet*)parg;
1420     try
1421     {
1422         vnThreadsRunning[THREAD_MINTER]++;
1423         BitcoinMiner(pwallet, true);
1424         vnThreadsRunning[THREAD_MINTER]--;
1425     }
1426     catch (std::exception& e) {
1427         vnThreadsRunning[THREAD_MINTER]--;
1428         PrintException(&e, "ThreadStakeMinter()");
1429     } catch (...) {
1430         vnThreadsRunning[THREAD_MINTER]--;
1431         PrintException(NULL, "ThreadStakeMinter()");
1432     }
1433     printf("ThreadStakeMinter exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINTER]);
1434 }
1435
1436
1437
1438
1439
1440
1441 bool BindListenPort(string& strError)
1442 {
1443     strError = "";
1444     int nOne = 1;
1445     addrLocalHost.SetPort(GetListenPort());
1446
1447 #ifdef WIN32
1448     // Initialize Windows Sockets
1449     WSADATA wsadata;
1450     int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
1451     if (ret != NO_ERROR)
1452     {
1453         strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
1454         printf("%s\n", strError.c_str());
1455         return false;
1456     }
1457 #endif
1458
1459     // Create socket for listening for incoming connections
1460     hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1461     if (hListenSocket == INVALID_SOCKET)
1462     {
1463         strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
1464         printf("%s\n", strError.c_str());
1465         return false;
1466     }
1467
1468 #ifdef SO_NOSIGPIPE
1469     // Different way of disabling SIGPIPE on BSD
1470     setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
1471 #endif
1472
1473 #ifndef WIN32
1474     // Allow binding if the port is still in TIME_WAIT state after
1475     // the program was closed and restarted.  Not an issue on windows.
1476     setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
1477 #endif
1478
1479 #ifdef WIN32
1480     // Set to nonblocking, incoming connections will also inherit this
1481     if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
1482 #else
1483     if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
1484 #endif
1485     {
1486         strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
1487         printf("%s\n", strError.c_str());
1488         return false;
1489     }
1490
1491     // The sockaddr_in structure specifies the address family,
1492     // IP address, and port for the socket that is being bound
1493     struct sockaddr_in sockaddr;
1494     memset(&sockaddr, 0, sizeof(sockaddr));
1495     sockaddr.sin_family = AF_INET;
1496     sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
1497     sockaddr.sin_port = htons(GetListenPort());
1498     if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
1499     {
1500         int nErr = WSAGetLastError();
1501         if (nErr == WSAEADDRINUSE)
1502             strError = strprintf(_("Unable to bind to port %d on this computer.  NovaCoin is probably already running."), ntohs(sockaddr.sin_port));
1503         else
1504             strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
1505         printf("%s\n", strError.c_str());
1506         return false;
1507     }
1508     printf("Bound to port %d\n", ntohs(sockaddr.sin_port));
1509
1510     // Listen for incoming connections
1511     if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1512     {
1513         strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
1514         printf("%s\n", strError.c_str());
1515         return false;
1516     }
1517
1518     return true;
1519 }
1520
1521 void StartNode(void* parg)
1522 {
1523     if (semOutbound == NULL) {
1524         // initialize semaphore
1525         int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
1526         semOutbound = new CSemaphore(nMaxOutbound);
1527     }
1528
1529 #ifdef USE_UPNP
1530 #if USE_UPNP
1531     fUseUPnP = GetBoolArg("-upnp", true);
1532 #else
1533     fUseUPnP = GetBoolArg("-upnp", false);
1534 #endif
1535 #endif
1536
1537     if (pnodeLocalHost == NULL)
1538         pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
1539
1540 #ifdef WIN32
1541     // Get local host ip
1542     char pszHostName[1000] = "";
1543     if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1544     {
1545         vector<CNetAddr> vaddr;
1546         if (LookupHost(pszHostName, vaddr))
1547         {
1548             BOOST_FOREACH (const CNetAddr &addr, vaddr)
1549             {
1550                 if (!addr.IsLocal())
1551                 {
1552                     addrLocalHost.SetIP(addr);
1553                     break;
1554                 }
1555             }
1556         }
1557     }
1558 #else
1559     // Get local host ip
1560     struct ifaddrs* myaddrs;
1561     if (getifaddrs(&myaddrs) == 0)
1562     {
1563         for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1564         {
1565             if (ifa->ifa_addr == NULL) continue;
1566             if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1567             if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1568             if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
1569             char pszIP[100];
1570             if (ifa->ifa_addr->sa_family == AF_INET)
1571             {
1572                 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
1573                 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
1574                     printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
1575
1576                 // Take the first IP that isn't loopback 127.x.x.x
1577                 CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices);
1578                 if (addr.IsValid() && !addr.IsLocal())
1579                 {
1580                     addrLocalHost = addr;
1581                     break;
1582                 }
1583             }
1584             else if (ifa->ifa_addr->sa_family == AF_INET6)
1585             {
1586                 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
1587                 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
1588                     printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
1589             }
1590         }
1591         freeifaddrs(myaddrs);
1592     }
1593 #endif
1594     printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
1595
1596     if (fUseProxy || mapArgs.count("-connect") || fNoListen)
1597     {
1598         // Proxies can't take incoming connections
1599         addrLocalHost.SetIP(CNetAddr("0.0.0.0"));
1600         printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
1601     }
1602     else
1603     {
1604         CreateThread(ThreadGetMyExternalIP, NULL);
1605     }
1606
1607     //
1608     // Start threads
1609     //
1610
1611 /*
1612     if (!GetBoolArg("-dnsseed", true))
1613         printf("DNS seeding disabled\n");
1614     else
1615         if (!CreateThread(ThreadDNSAddressSeed, NULL))
1616             printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n");
1617 */
1618
1619     if (GetBoolArg("-dnsseed", false))
1620         printf("DNS seeding NYI\n");
1621
1622     // Map ports with UPnP
1623     if (fHaveUPnP)
1624         MapPort(fUseUPnP);
1625
1626     // Get addresses from IRC and advertise ours
1627     if (!CreateThread(ThreadIRCSeed, NULL))
1628         printf("Error: CreateThread(ThreadIRCSeed) failed\n");
1629
1630     // Send and receive from sockets, accept connections
1631     if (!CreateThread(ThreadSocketHandler, NULL))
1632         printf("Error: CreateThread(ThreadSocketHandler) failed\n");
1633
1634     // Initiate outbound connections from -addnode
1635     if (!CreateThread(ThreadOpenAddedConnections, NULL))
1636         printf("Error: CreateThread(ThreadOpenAddedConnections) failed\n");
1637
1638     // Initiate outbound connections
1639     if (!CreateThread(ThreadOpenConnections, NULL))
1640         printf("Error: CreateThread(ThreadOpenConnections) failed\n");
1641
1642     // Process messages
1643     if (!CreateThread(ThreadMessageHandler, NULL))
1644         printf("Error: CreateThread(ThreadMessageHandler) failed\n");
1645
1646     // Dump network addresses
1647     if (!CreateThread(ThreadDumpAddress, NULL))
1648         printf("Error; CreateThread(ThreadDumpAddress) failed\n");
1649
1650     // Generate coins in the background
1651     GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain);
1652
1653     // ppcoin: mint proof-of-stake blocks in the background
1654     if (!CreateThread(ThreadStakeMinter, pwalletMain))
1655         printf("Error: CreateThread(ThreadStakeMinter) failed\n");
1656 }
1657
1658 bool StopNode()
1659 {
1660     printf("StopNode()\n");
1661     fShutdown = true;
1662     nTransactionsUpdated++;
1663     int64 nStart = GetTime();
1664     if (semOutbound)
1665         for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
1666             semOutbound->post();
1667     do
1668     {
1669         int nThreadsRunning = 0;
1670         for (int n = 0; n < THREAD_MAX; n++)
1671             nThreadsRunning += vnThreadsRunning[n];
1672         if (nThreadsRunning == 0)
1673             break;
1674         if (GetTime() - nStart > 20)
1675             break;
1676         Sleep(20);
1677     } while(true);
1678     if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
1679     if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
1680     if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
1681     if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n");
1682     if (vnThreadsRunning[THREAD_RPCSERVER] > 0) printf("ThreadRPCServer still running\n");
1683     if (fHaveUPnP && vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
1684     if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
1685     if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
1686     if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
1687     if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStakeMinter still running\n");
1688     while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCSERVER] > 0)
1689         Sleep(20);
1690     Sleep(50);
1691     DumpAddresses();
1692     return true;
1693 }
1694
1695 class CNetCleanup
1696 {
1697 public:
1698     CNetCleanup()
1699     {
1700     }
1701     ~CNetCleanup()
1702     {
1703         // Close sockets
1704         BOOST_FOREACH(CNode* pnode, vNodes)
1705             if (pnode->hSocket != INVALID_SOCKET)
1706                 closesocket(pnode->hSocket);
1707         if (hListenSocket != INVALID_SOCKET)
1708             if (closesocket(hListenSocket) == SOCKET_ERROR)
1709                 printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
1710
1711 #ifdef WIN32
1712         // Shutdown Windows Sockets
1713         WSACleanup();
1714 #endif
1715     }
1716 }
1717 instance_of_cnetcleanup;