always make 8 outbound connections even if have inbound,
[novacoin.git] / net.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto\r
2 // Distributed under the MIT/X11 software license, see the accompanying\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.\r
4 \r
5 #include "headers.h"\r
6 \r
7 static const int MAX_OUTBOUND_CONNECTIONS = 8;\r
8 \r
9 void ThreadMessageHandler2(void* parg);\r
10 void ThreadSocketHandler2(void* parg);\r
11 void ThreadOpenConnections2(void* parg);\r
12 bool OpenNetworkConnection(const CAddress& addrConnect);\r
13 \r
14 \r
15 \r
16 \r
17 \r
18 //\r
19 // Global state variables\r
20 //\r
21 bool fClient = false;\r
22 uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);\r
23 CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices);\r
24 CNode* pnodeLocalHost = NULL;\r
25 uint64 nLocalHostNonce = 0;\r
26 array<int, 10> vnThreadsRunning;\r
27 SOCKET hListenSocket = INVALID_SOCKET;\r
28 int64 nThreadSocketHandlerHeartbeat = INT64_MAX;\r
29 \r
30 vector<CNode*> vNodes;\r
31 CCriticalSection cs_vNodes;\r
32 map<vector<unsigned char>, CAddress> mapAddresses;\r
33 CCriticalSection cs_mapAddresses;\r
34 map<CInv, CDataStream> mapRelay;\r
35 deque<pair<int64, CInv> > vRelayExpiration;\r
36 CCriticalSection cs_mapRelay;\r
37 map<CInv, int64> mapAlreadyAskedFor;\r
38 \r
39 // Settings\r
40 int fUseProxy = false;\r
41 CAddress addrProxy("127.0.0.1:9050");\r
42 \r
43 \r
44 \r
45 \r
46 \r
47 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)\r
48 {\r
49     // Filter out duplicate requests\r
50     if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)\r
51         return;\r
52     pindexLastGetBlocksBegin = pindexBegin;\r
53     hashLastGetBlocksEnd = hashEnd;\r
54 \r
55     PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);\r
56 }\r
57 \r
58 \r
59 \r
60 \r
61 \r
62 bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)\r
63 {\r
64     hSocketRet = INVALID_SOCKET;\r
65 \r
66     SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
67     if (hSocket == INVALID_SOCKET)\r
68         return false;\r
69 #if defined(__BSD__) || defined(__WXMAC_OSX__)\r
70     int set = 1;\r
71     setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));\r
72 #endif\r
73 \r
74     bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168));\r
75     bool fProxy = (fUseProxy && fRoutable);\r
76     struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());\r
77 \r
78     if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)\r
79     {\r
80         closesocket(hSocket);\r
81         return false;\r
82     }\r
83 \r
84     if (fProxy)\r
85     {\r
86         printf("proxy connecting %s\n", addrConnect.ToStringLog().c_str());\r
87         char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";\r
88         memcpy(pszSocks4IP + 2, &addrConnect.port, 2);\r
89         memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);\r
90         char* pszSocks4 = pszSocks4IP;\r
91         int nSize = sizeof(pszSocks4IP);\r
92 \r
93         int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);\r
94         if (ret != nSize)\r
95         {\r
96             closesocket(hSocket);\r
97             return error("Error sending to proxy");\r
98         }\r
99         char pchRet[8];\r
100         if (recv(hSocket, pchRet, 8, 0) != 8)\r
101         {\r
102             closesocket(hSocket);\r
103             return error("Error reading proxy response");\r
104         }\r
105         if (pchRet[1] != 0x5a)\r
106         {\r
107             closesocket(hSocket);\r
108             if (pchRet[1] != 0x5b)\r
109                 printf("ERROR: Proxy returned error %d\n", pchRet[1]);\r
110             return false;\r
111         }\r
112         printf("proxy connected %s\n", addrConnect.ToStringLog().c_str());\r
113     }\r
114 \r
115     hSocketRet = hSocket;\r
116     return true;\r
117 }\r
118 \r
119 \r
120 \r
121 bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)\r
122 {\r
123     SOCKET hSocket;\r
124     if (!ConnectSocket(addrConnect, hSocket))\r
125         return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());\r
126 \r
127     send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);\r
128 \r
129     string strLine;\r
130     while (RecvLine(hSocket, strLine))\r
131     {\r
132         if (strLine.empty())\r
133         {\r
134             loop\r
135             {\r
136                 if (!RecvLine(hSocket, strLine))\r
137                 {\r
138                     closesocket(hSocket);\r
139                     return false;\r
140                 }\r
141                 if (strLine.find(pszKeyword) != -1)\r
142                 {\r
143                     strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));\r
144                     break;\r
145                 }\r
146             }\r
147             closesocket(hSocket);\r
148             if (strLine.find("<"))\r
149                 strLine = strLine.substr(0, strLine.find("<"));\r
150             strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));\r
151             while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))\r
152                 strLine.resize(strLine.size()-1);\r
153             CAddress addr(strLine.c_str());\r
154             printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());\r
155             if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())\r
156                 return false;\r
157             ipRet = addr.ip;\r
158             return true;\r
159         }\r
160     }\r
161     closesocket(hSocket);\r
162     return error("GetMyExternalIP() : connection closed");\r
163 }\r
164 \r
165 \r
166 bool GetMyExternalIP(unsigned int& ipRet)\r
167 {\r
168     CAddress addrConnect;\r
169     const char* pszGet;\r
170     const char* pszKeyword;\r
171 \r
172     if (fUseProxy)\r
173         return false;\r
174 \r
175     for (int nLookup = 0; nLookup <= 1; nLookup++)\r
176     for (int nHost = 1; nHost <= 2; nHost++)\r
177     {\r
178         if (nHost == 1)\r
179         {\r
180             addrConnect = CAddress("70.86.96.218:80"); // www.ipaddressworld.com\r
181 \r
182             if (nLookup == 1)\r
183             {\r
184                 struct hostent* phostent = gethostbyname("www.ipaddressworld.com");\r
185                 if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])\r
186                     addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80));\r
187             }\r
188 \r
189             pszGet = "GET /ip.php HTTP/1.1\r\n"\r
190                      "Host: www.ipaddressworld.com\r\n"\r
191                      "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"\r
192                      "Connection: close\r\n"\r
193                      "\r\n";\r
194 \r
195             pszKeyword = "IP:";\r
196         }\r
197         else if (nHost == 2)\r
198         {\r
199             addrConnect = CAddress("208.78.68.70:80"); // checkip.dyndns.org\r
200 \r
201             if (nLookup == 1)\r
202             {\r
203                 struct hostent* phostent = gethostbyname("checkip.dyndns.org");\r
204                 if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])\r
205                     addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80));\r
206             }\r
207 \r
208             pszGet = "GET / HTTP/1.1\r\n"\r
209                      "Host: checkip.dyndns.org\r\n"\r
210                      "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"\r
211                      "Connection: close\r\n"\r
212                      "\r\n";\r
213 \r
214             pszKeyword = "Address:";\r
215         }\r
216 \r
217         if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))\r
218             return true;\r
219     }\r
220 \r
221     return false;\r
222 }\r
223 \r
224 \r
225 \r
226 \r
227 \r
228 bool AddAddress(CAddress addr)\r
229 {\r
230     if (!addr.IsRoutable())\r
231         return false;\r
232     if (addr.ip == addrLocalHost.ip)\r
233         return false;\r
234     CRITICAL_BLOCK(cs_mapAddresses)\r
235     {\r
236         map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());\r
237         if (it == mapAddresses.end())\r
238         {\r
239             // New address\r
240             printf("AddAddress(%s)\n", addr.ToStringLog().c_str());\r
241             mapAddresses.insert(make_pair(addr.GetKey(), addr));\r
242             CAddrDB().WriteAddress(addr);\r
243             return true;\r
244         }\r
245         else\r
246         {\r
247             bool fUpdated = false;\r
248             CAddress& addrFound = (*it).second;\r
249             if ((addrFound.nServices | addr.nServices) != addrFound.nServices)\r
250             {\r
251                 // Services have been added\r
252                 addrFound.nServices |= addr.nServices;\r
253                 fUpdated = true;\r
254             }\r
255             bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);\r
256             int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);\r
257             if (addrFound.nTime < addr.nTime - nUpdateInterval)\r
258             {\r
259                 // Periodically update most recently seen time\r
260                 addrFound.nTime = addr.nTime;\r
261                 fUpdated = true;\r
262             }\r
263             if (fUpdated)\r
264                 CAddrDB().WriteAddress(addrFound);\r
265         }\r
266     }\r
267     return false;\r
268 }\r
269 \r
270 void AddressCurrentlyConnected(const CAddress& addr)\r
271 {\r
272     CRITICAL_BLOCK(cs_mapAddresses)\r
273     {\r
274         // Only if it's been published already\r
275         map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());\r
276         if (it != mapAddresses.end())\r
277         {\r
278             CAddress& addrFound = (*it).second;\r
279             int64 nUpdateInterval = 20 * 60;\r
280             if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)\r
281             {\r
282                 // Periodically update most recently seen time\r
283                 addrFound.nTime = GetAdjustedTime();\r
284                 CAddrDB addrdb;\r
285                 addrdb.WriteAddress(addrFound);\r
286             }\r
287         }\r
288     }\r
289 }\r
290 \r
291 \r
292 \r
293 \r
294 \r
295 void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)\r
296 {\r
297     // If the dialog might get closed before the reply comes back,\r
298     // call this in the destructor so it doesn't get called after it's deleted.\r
299     CRITICAL_BLOCK(cs_vNodes)\r
300     {\r
301         foreach(CNode* pnode, vNodes)\r
302         {\r
303             CRITICAL_BLOCK(pnode->cs_mapRequests)\r
304             {\r
305                 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)\r
306                 {\r
307                     CRequestTracker& tracker = (*mi).second;\r
308                     if (tracker.fn == fn && tracker.param1 == param1)\r
309                         pnode->mapRequests.erase(mi++);\r
310                     else\r
311                         mi++;\r
312                 }\r
313             }\r
314         }\r
315     }\r
316 }\r
317 \r
318 \r
319 \r
320 \r
321 \r
322 \r
323 \r
324 //\r
325 // Subscription methods for the broadcast and subscription system.\r
326 // Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.\r
327 //\r
328 // The subscription system uses a meet-in-the-middle strategy.\r
329 // With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers\r
330 // subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.\r
331 //\r
332 \r
333 bool AnySubscribed(unsigned int nChannel)\r
334 {\r
335     if (pnodeLocalHost->IsSubscribed(nChannel))\r
336         return true;\r
337     CRITICAL_BLOCK(cs_vNodes)\r
338         foreach(CNode* pnode, vNodes)\r
339             if (pnode->IsSubscribed(nChannel))\r
340                 return true;\r
341     return false;\r
342 }\r
343 \r
344 bool CNode::IsSubscribed(unsigned int nChannel)\r
345 {\r
346     if (nChannel >= vfSubscribe.size())\r
347         return false;\r
348     return vfSubscribe[nChannel];\r
349 }\r
350 \r
351 void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)\r
352 {\r
353     if (nChannel >= vfSubscribe.size())\r
354         return;\r
355 \r
356     if (!AnySubscribed(nChannel))\r
357     {\r
358         // Relay subscribe\r
359         CRITICAL_BLOCK(cs_vNodes)\r
360             foreach(CNode* pnode, vNodes)\r
361                 if (pnode != this)\r
362                     pnode->PushMessage("subscribe", nChannel, nHops);\r
363     }\r
364 \r
365     vfSubscribe[nChannel] = true;\r
366 }\r
367 \r
368 void CNode::CancelSubscribe(unsigned int nChannel)\r
369 {\r
370     if (nChannel >= vfSubscribe.size())\r
371         return;\r
372 \r
373     // Prevent from relaying cancel if wasn't subscribed\r
374     if (!vfSubscribe[nChannel])\r
375         return;\r
376     vfSubscribe[nChannel] = false;\r
377 \r
378     if (!AnySubscribed(nChannel))\r
379     {\r
380         // Relay subscription cancel\r
381         CRITICAL_BLOCK(cs_vNodes)\r
382             foreach(CNode* pnode, vNodes)\r
383                 if (pnode != this)\r
384                     pnode->PushMessage("sub-cancel", nChannel);\r
385     }\r
386 }\r
387 \r
388 \r
389 \r
390 \r
391 \r
392 \r
393 \r
394 \r
395 \r
396 CNode* FindNode(unsigned int ip)\r
397 {\r
398     CRITICAL_BLOCK(cs_vNodes)\r
399     {\r
400         foreach(CNode* pnode, vNodes)\r
401             if (pnode->addr.ip == ip)\r
402                 return (pnode);\r
403     }\r
404     return NULL;\r
405 }\r
406 \r
407 CNode* FindNode(CAddress addr)\r
408 {\r
409     CRITICAL_BLOCK(cs_vNodes)\r
410     {\r
411         foreach(CNode* pnode, vNodes)\r
412             if (pnode->addr == addr)\r
413                 return (pnode);\r
414     }\r
415     return NULL;\r
416 }\r
417 \r
418 CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)\r
419 {\r
420     if (addrConnect.ip == addrLocalHost.ip)\r
421         return NULL;\r
422 \r
423     // Look for an existing connection\r
424     CNode* pnode = FindNode(addrConnect.ip);\r
425     if (pnode)\r
426     {\r
427         if (nTimeout != 0)\r
428             pnode->AddRef(nTimeout);\r
429         else\r
430             pnode->AddRef();\r
431         return pnode;\r
432     }\r
433 \r
434     /// debug print\r
435     printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",\r
436         addrConnect.ToStringLog().c_str(),\r
437         (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,\r
438         (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);\r
439 \r
440     CRITICAL_BLOCK(cs_mapAddresses)\r
441         mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();\r
442 \r
443     // Connect\r
444     SOCKET hSocket;\r
445     if (ConnectSocket(addrConnect, hSocket))\r
446     {\r
447         /// debug print\r
448         printf("connected %s\n", addrConnect.ToStringLog().c_str());\r
449 \r
450         // Set to nonblocking\r
451 #ifdef __WXMSW__\r
452         u_long nOne = 1;\r
453         if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)\r
454             printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());\r
455 #else\r
456         if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)\r
457             printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno);\r
458 #endif\r
459 \r
460         // Add node\r
461         CNode* pnode = new CNode(hSocket, addrConnect, false);\r
462         if (nTimeout != 0)\r
463             pnode->AddRef(nTimeout);\r
464         else\r
465             pnode->AddRef();\r
466         CRITICAL_BLOCK(cs_vNodes)\r
467             vNodes.push_back(pnode);\r
468 \r
469         pnode->nTimeConnected = GetTime();\r
470         return pnode;\r
471     }\r
472     else\r
473     {\r
474         return NULL;\r
475     }\r
476 }\r
477 \r
478 void CNode::CloseSocketDisconnect()\r
479 {\r
480     fDisconnect = true;\r
481     if (hSocket != INVALID_SOCKET)\r
482     {\r
483         if (fDebug)\r
484             printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
485         printf("disconnecting node %s\n", addr.ToStringLog().c_str());\r
486         closesocket(hSocket);\r
487         hSocket = INVALID_SOCKET;\r
488     }\r
489 }\r
490 \r
491 void CNode::Cleanup()\r
492 {\r
493     // All of a nodes broadcasts and subscriptions are automatically torn down\r
494     // when it goes down, so a node has to stay up to keep its broadcast going.\r
495 \r
496     // Cancel subscriptions\r
497     for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)\r
498         if (vfSubscribe[nChannel])\r
499             CancelSubscribe(nChannel);\r
500 }\r
501 \r
502 \r
503 \r
504 \r
505 \r
506 \r
507 \r
508 \r
509 \r
510 \r
511 \r
512 \r
513 \r
514 void ThreadSocketHandler(void* parg)\r
515 {\r
516     IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));\r
517     try\r
518     {\r
519         vnThreadsRunning[0]++;\r
520         ThreadSocketHandler2(parg);\r
521         vnThreadsRunning[0]--;\r
522     }\r
523     catch (std::exception& e) {\r
524         vnThreadsRunning[0]--;\r
525         PrintException(&e, "ThreadSocketHandler()");\r
526     } catch (...) {\r
527         vnThreadsRunning[0]--;\r
528         throw; // support pthread_cancel()\r
529     }\r
530     printf("ThreadSocketHandler exiting\n");\r
531 }\r
532 \r
533 void ThreadSocketHandler2(void* parg)\r
534 {\r
535     printf("ThreadSocketHandler started\n");\r
536     list<CNode*> vNodesDisconnected;\r
537     int nPrevNodeCount = 0;\r
538 \r
539     loop\r
540     {\r
541         //\r
542         // Disconnect nodes\r
543         //\r
544         CRITICAL_BLOCK(cs_vNodes)\r
545         {\r
546             // Disconnect unused nodes\r
547             vector<CNode*> vNodesCopy = vNodes;\r
548             foreach(CNode* pnode, vNodesCopy)\r
549             {\r
550                 if (pnode->fDisconnect ||\r
551                     (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))\r
552                 {\r
553                     // remove from vNodes\r
554                     vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());\r
555 \r
556                     // close socket and cleanup\r
557                     pnode->CloseSocketDisconnect();\r
558                     pnode->Cleanup();\r
559 \r
560                     // hold in disconnected pool until all refs are released\r
561                     pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);\r
562                     if (pnode->fNetworkNode || pnode->fInbound)\r
563                         pnode->Release();\r
564                     vNodesDisconnected.push_back(pnode);\r
565                 }\r
566             }\r
567 \r
568             // Delete disconnected nodes\r
569             list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;\r
570             foreach(CNode* pnode, vNodesDisconnectedCopy)\r
571             {\r
572                 // wait until threads are done using it\r
573                 if (pnode->GetRefCount() <= 0)\r
574                 {\r
575                     bool fDelete = false;\r
576                     TRY_CRITICAL_BLOCK(pnode->cs_vSend)\r
577                      TRY_CRITICAL_BLOCK(pnode->cs_vRecv)\r
578                       TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)\r
579                        TRY_CRITICAL_BLOCK(pnode->cs_inventory)\r
580                         fDelete = true;\r
581                     if (fDelete)\r
582                     {\r
583                         vNodesDisconnected.remove(pnode);\r
584                         delete pnode;\r
585                     }\r
586                 }\r
587             }\r
588         }\r
589         if (vNodes.size() != nPrevNodeCount)\r
590         {\r
591             nPrevNodeCount = vNodes.size();\r
592             MainFrameRepaint();\r
593         }\r
594 \r
595 \r
596         //\r
597         // Find which sockets have data to receive\r
598         //\r
599         struct timeval timeout;\r
600         timeout.tv_sec  = 0;\r
601         timeout.tv_usec = 50000; // frequency to poll pnode->vSend\r
602 \r
603         fd_set fdsetRecv;\r
604         fd_set fdsetSend;\r
605         fd_set fdsetError;\r
606         FD_ZERO(&fdsetRecv);\r
607         FD_ZERO(&fdsetSend);\r
608         FD_ZERO(&fdsetError);\r
609         SOCKET hSocketMax = 0;\r
610         FD_SET(hListenSocket, &fdsetRecv);\r
611         hSocketMax = max(hSocketMax, hListenSocket);\r
612         CRITICAL_BLOCK(cs_vNodes)\r
613         {\r
614             foreach(CNode* pnode, vNodes)\r
615             {\r
616                 if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)\r
617                     continue;\r
618                 FD_SET(pnode->hSocket, &fdsetRecv);\r
619                 FD_SET(pnode->hSocket, &fdsetError);\r
620                 hSocketMax = max(hSocketMax, pnode->hSocket);\r
621                 TRY_CRITICAL_BLOCK(pnode->cs_vSend)\r
622                     if (!pnode->vSend.empty())\r
623                         FD_SET(pnode->hSocket, &fdsetSend);\r
624             }\r
625         }\r
626 \r
627         vnThreadsRunning[0]--;\r
628         int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);\r
629         vnThreadsRunning[0]++;\r
630         if (fShutdown)\r
631             return;\r
632         if (nSelect == SOCKET_ERROR)\r
633         {\r
634             int nErr = WSAGetLastError();\r
635             printf("socket select error %d\n", nErr);\r
636             for (int i = 0; i <= hSocketMax; i++)\r
637                 FD_SET(i, &fdsetRecv);\r
638             FD_ZERO(&fdsetSend);\r
639             FD_ZERO(&fdsetError);\r
640             Sleep(timeout.tv_usec/1000);\r
641         }\r
642 \r
643 \r
644         //\r
645         // Accept new connections\r
646         //\r
647         if (FD_ISSET(hListenSocket, &fdsetRecv))\r
648         {\r
649             struct sockaddr_in sockaddr;\r
650             socklen_t len = sizeof(sockaddr);\r
651             SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);\r
652             CAddress addr(sockaddr);\r
653             if (hSocket == INVALID_SOCKET)\r
654             {\r
655                 if (WSAGetLastError() != WSAEWOULDBLOCK)\r
656                     printf("socket error accept failed: %d\n", WSAGetLastError());\r
657             }\r
658             else if (mapArgs.count("-maxconnections") && (int)vNodes.size() >= atoi(mapArgs["-maxconnections"]) - MAX_OUTBOUND_CONNECTIONS)\r
659             {\r
660                 closesocket(hSocket);\r
661             }\r
662             else\r
663             {\r
664                 printf("accepted connection %s\n", addr.ToStringLog().c_str());\r
665                 CNode* pnode = new CNode(hSocket, addr, true);\r
666                 pnode->AddRef();\r
667                 CRITICAL_BLOCK(cs_vNodes)\r
668                     vNodes.push_back(pnode);\r
669             }\r
670         }\r
671 \r
672 \r
673         //\r
674         // Service each socket\r
675         //\r
676         vector<CNode*> vNodesCopy;\r
677         CRITICAL_BLOCK(cs_vNodes)\r
678         {\r
679             vNodesCopy = vNodes;\r
680             foreach(CNode* pnode, vNodesCopy)\r
681                 pnode->AddRef();\r
682         }\r
683         foreach(CNode* pnode, vNodesCopy)\r
684         {\r
685             if (fShutdown)\r
686                 return;\r
687 \r
688             //\r
689             // Receive\r
690             //\r
691             if (pnode->hSocket == INVALID_SOCKET)\r
692                 continue;\r
693             if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))\r
694             {\r
695                 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)\r
696                 {\r
697                     CDataStream& vRecv = pnode->vRecv;\r
698                     unsigned int nPos = vRecv.size();\r
699 \r
700                     // typical socket buffer is 8K-64K\r
701                     char pchBuf[0x10000];\r
702                     int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);\r
703                     if (nBytes > 0)\r
704                     {\r
705                         vRecv.resize(nPos + nBytes);\r
706                         memcpy(&vRecv[nPos], pchBuf, nBytes);\r
707                         pnode->nLastRecv = GetTime();\r
708                     }\r
709                     else if (nBytes == 0)\r
710                     {\r
711                         // socket closed gracefully\r
712                         if (!pnode->fDisconnect)\r
713                             printf("socket closed\n");\r
714                         pnode->CloseSocketDisconnect();\r
715                     }\r
716                     else if (nBytes < 0)\r
717                     {\r
718                         // error\r
719                         int nErr = WSAGetLastError();\r
720                         if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)\r
721                         {\r
722                             if (!pnode->fDisconnect)\r
723                                 printf("socket recv error %d\n", nErr);\r
724                             pnode->CloseSocketDisconnect();\r
725                         }\r
726                     }\r
727                 }\r
728             }\r
729 \r
730             //\r
731             // Send\r
732             //\r
733             if (pnode->hSocket == INVALID_SOCKET)\r
734                 continue;\r
735             if (FD_ISSET(pnode->hSocket, &fdsetSend))\r
736             {\r
737                 TRY_CRITICAL_BLOCK(pnode->cs_vSend)\r
738                 {\r
739                     CDataStream& vSend = pnode->vSend;\r
740                     if (!vSend.empty())\r
741                     {\r
742                         int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);\r
743                         if (nBytes > 0)\r
744                         {\r
745                             vSend.erase(vSend.begin(), vSend.begin() + nBytes);\r
746                             pnode->nLastSend = GetTime();\r
747                         }\r
748                         else if (nBytes < 0)\r
749                         {\r
750                             // error\r
751                             int nErr = WSAGetLastError();\r
752                             if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)\r
753                             {\r
754                                 printf("socket send error %d\n", nErr);\r
755                                 pnode->CloseSocketDisconnect();\r
756                             }\r
757                         }\r
758                     }\r
759                 }\r
760             }\r
761 \r
762             //\r
763             // Inactivity checking\r
764             //\r
765             if (pnode->vSend.empty())\r
766                 pnode->nLastSendEmpty = GetTime();\r
767             if (GetTime() - pnode->nTimeConnected > 60)\r
768             {\r
769                 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)\r
770                 {\r
771                     printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);\r
772                     pnode->fDisconnect = true;\r
773                 }\r
774                 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)\r
775                 {\r
776                     printf("socket not sending\n");\r
777                     pnode->fDisconnect = true;\r
778                 }\r
779                 else if (GetTime() - pnode->nLastRecv > 90*60)\r
780                 {\r
781                     printf("socket inactivity timeout\n");\r
782                     pnode->fDisconnect = true;\r
783                 }\r
784             }\r
785         }\r
786         CRITICAL_BLOCK(cs_vNodes)\r
787         {\r
788             foreach(CNode* pnode, vNodesCopy)\r
789                 pnode->Release();\r
790         }\r
791 \r
792         nThreadSocketHandlerHeartbeat = GetTime();\r
793         Sleep(10);\r
794     }\r
795 }\r
796 \r
797 \r
798 \r
799 \r
800 \r
801 \r
802 \r
803 \r
804 \r
805 \r
806 \r
807 \r
808 \r
809 unsigned int pnSeed[] =\r
810 {\r
811     0x35218252, 0x9c9c9618, 0xda6bacad, 0xb9aca862, 0x97c235c6,\r
812     0x146f9562, 0xb67b9e4b, 0x87cf4bc0, 0xb83945d0, 0x984333ad,\r
813     0xbbeec555, 0x6f0eb440, 0xe0005318, 0x7797e460, 0xddc60fcc,\r
814     0xb3bbd24a, 0x1ac85746, 0x641846a6, 0x85ee1155, 0xbb2e7a4c,\r
815     0x9cb8514b, 0xfc342648, 0x62958fae, 0xd0a8c87a, 0xa800795b,\r
816     0xda8c814e, 0x256a0c80, 0x3f23ec63, 0xd565df43, 0x997d9044,\r
817     0xaa121448, 0xbed8688e, 0x59d09a5e, 0xb2931243, 0x3730ba18,\r
818     0xdd3462d0, 0x4e4d1448, 0x171df645, 0x84ee1155,\r
819     0x248ac445, 0x0e634444, 0x0ded1b63, 0x30c01e60,\r
820     0xa2b9a094, 0x29e4fd43, 0x9ce61b4c, 0xdae09744,\r
821 };\r
822 \r
823 \r
824 \r
825 void ThreadOpenConnections(void* parg)\r
826 {\r
827     IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));\r
828     try\r
829     {\r
830         vnThreadsRunning[1]++;\r
831         ThreadOpenConnections2(parg);\r
832         vnThreadsRunning[1]--;\r
833     }\r
834     catch (std::exception& e) {\r
835         vnThreadsRunning[1]--;\r
836         PrintException(&e, "ThreadOpenConnections()");\r
837     } catch (...) {\r
838         vnThreadsRunning[1]--;\r
839         PrintException(NULL, "ThreadOpenConnections()");\r
840     }\r
841     printf("ThreadOpenConnections exiting\n");\r
842 }\r
843 \r
844 void ThreadOpenConnections2(void* parg)\r
845 {\r
846     printf("ThreadOpenConnections started\n");\r
847 \r
848     // Connect to specific addresses\r
849     if (mapArgs.count("-connect"))\r
850     {\r
851         for (int64 nLoop = 0;; nLoop++)\r
852         {\r
853             foreach(string strAddr, mapMultiArgs["-connect"])\r
854             {\r
855                 CAddress addr(strAddr, NODE_NETWORK);\r
856                 if (addr.IsValid())\r
857                     OpenNetworkConnection(addr);\r
858                 for (int i = 0; i < 10 && i < nLoop; i++)\r
859                 {\r
860                     Sleep(500);\r
861                     if (fShutdown)\r
862                         return;\r
863                 }\r
864             }\r
865         }\r
866     }\r
867 \r
868     // Connect to manually added nodes first\r
869     if (mapArgs.count("-addnode"))\r
870     {\r
871         foreach(string strAddr, mapMultiArgs["-addnode"])\r
872         {\r
873             CAddress addr(strAddr, NODE_NETWORK);\r
874             if (addr.IsValid())\r
875             {\r
876                 OpenNetworkConnection(addr);\r
877                 Sleep(500);\r
878                 if (fShutdown)\r
879                     return;\r
880             }\r
881         }\r
882     }\r
883 \r
884     // Initiate network connections\r
885     int64 nStart = GetTime();\r
886     loop\r
887     {\r
888         // Limit outbound connections\r
889         vnThreadsRunning[1]--;\r
890         Sleep(500);\r
891         loop\r
892         {\r
893             int nOutbound = 0;\r
894             CRITICAL_BLOCK(cs_vNodes)\r
895                 foreach(CNode* pnode, vNodes)\r
896                     if (!pnode->fInbound)\r
897                         nOutbound++;\r
898             int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;\r
899             if (mapArgs.count("-maxconnections"))\r
900                 nMaxOutboundConnections = min(nMaxOutboundConnections, atoi(mapArgs["-maxconnections"]));\r
901             if (nOutbound < nMaxOutboundConnections)\r
902                 break;\r
903             Sleep(2000);\r
904             if (fShutdown)\r
905                 return;\r
906         }\r
907         vnThreadsRunning[1]++;\r
908         if (fShutdown)\r
909             return;\r
910 \r
911         CRITICAL_BLOCK(cs_mapAddresses)\r
912         {\r
913             // Add seed nodes if IRC isn't working\r
914             static bool fSeedUsed;\r
915             bool fTOR = (fUseProxy && addrProxy.port == htons(9050));\r
916             if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR))\r
917             {\r
918                 for (int i = 0; i < ARRAYLEN(pnSeed); i++)\r
919                 {\r
920                     // It'll only connect to one or two seed nodes because once it connects,\r
921                     // it'll get a pile of addresses with newer timestamps.\r
922                     CAddress addr;\r
923                     addr.ip = pnSeed[i];\r
924                     addr.nTime = 0;\r
925                     AddAddress(addr);\r
926                 }\r
927                 fSeedUsed = true;\r
928             }\r
929 \r
930             if (fSeedUsed && mapAddresses.size() > ARRAYLEN(pnSeed) + 100)\r
931             {\r
932                 // Disconnect seed nodes\r
933                 set<unsigned int> setSeed(pnSeed, pnSeed + ARRAYLEN(pnSeed));\r
934                 static int64 nSeedDisconnected;\r
935                 if (nSeedDisconnected == 0)\r
936                 {\r
937                     nSeedDisconnected = GetTime();\r
938                     CRITICAL_BLOCK(cs_vNodes)\r
939                         foreach(CNode* pnode, vNodes)\r
940                             if (setSeed.count(pnode->addr.ip))\r
941                                 pnode->fDisconnect = true;\r
942                 }\r
943 \r
944                 // Keep setting timestamps to 0 so they won't reconnect\r
945                 if (GetTime() - nSeedDisconnected < 60 * 60)\r
946                 {\r
947                     foreach(PAIRTYPE(const vector<unsigned char>, CAddress)& item, mapAddresses)\r
948                     {\r
949                         if (setSeed.count(item.second.ip))\r
950                         {\r
951                             item.second.nTime = 0;\r
952                             CAddrDB().WriteAddress(item.second);\r
953                         }\r
954                     }\r
955                 }\r
956             }\r
957         }\r
958 \r
959 \r
960         //\r
961         // Choose an address to connect to based on most recently seen\r
962         //\r
963         CAddress addrConnect;\r
964         int64 nBest = INT64_MIN;\r
965 \r
966         // Only connect to one address per a.b.?.? range.\r
967         // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.\r
968         set<unsigned int> setConnected;\r
969         CRITICAL_BLOCK(cs_vNodes)\r
970             foreach(CNode* pnode, vNodes)\r
971                 setConnected.insert(pnode->addr.ip & 0x0000ffff);\r
972 \r
973         CRITICAL_BLOCK(cs_mapAddresses)\r
974         {\r
975             foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)\r
976             {\r
977                 const CAddress& addr = item.second;\r
978                 if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))\r
979                     continue;\r
980                 int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;\r
981                 int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;\r
982 \r
983                 // Randomize the order in a deterministic way, putting the standard port first\r
984                 int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);\r
985                 if (addr.port != DEFAULT_PORT)\r
986                     nRandomizer += 2 * 60 * 60;\r
987 \r
988                 // Last seen  Base retry frequency\r
989                 //   <1 hour   10 min\r
990                 //    1 hour    1 hour\r
991                 //    4 hours   2 hours\r
992                 //   24 hours   5 hours\r
993                 //   48 hours   7 hours\r
994                 //    7 days   13 hours\r
995                 //   30 days   27 hours\r
996                 //   90 days   46 hours\r
997                 //  365 days   93 hours\r
998                 int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);\r
999 \r
1000                 // Fast reconnect for one hour after last seen\r
1001                 if (nSinceLastSeen < 60 * 60)\r
1002                     nDelay = 10 * 60;\r
1003 \r
1004                 // Limit retry frequency\r
1005                 if (nSinceLastTry < nDelay)\r
1006                     continue;\r
1007 \r
1008                 // If we have IRC, we'll be notified when they first come online,\r
1009                 // and again every 24 hours by the refresh broadcast.\r
1010                 if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)\r
1011                     continue;\r
1012 \r
1013                 // Only try the old stuff if we don't have enough connections\r
1014                 if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)\r
1015                     continue;\r
1016 \r
1017                 // If multiple addresses are ready, prioritize by time since\r
1018                 // last seen and time since last tried.\r
1019                 int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;\r
1020                 if (nScore > nBest)\r
1021                 {\r
1022                     nBest = nScore;\r
1023                     addrConnect = addr;\r
1024                 }\r
1025             }\r
1026         }\r
1027 \r
1028         if (addrConnect.IsValid())\r
1029             OpenNetworkConnection(addrConnect);\r
1030     }\r
1031 }\r
1032 \r
1033 bool OpenNetworkConnection(const CAddress& addrConnect)\r
1034 {\r
1035     //\r
1036     // Initiate outbound network connection\r
1037     //\r
1038     if (fShutdown)\r
1039         return false;\r
1040     if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))\r
1041         return false;\r
1042 \r
1043     vnThreadsRunning[1]--;\r
1044     CNode* pnode = ConnectNode(addrConnect);\r
1045     vnThreadsRunning[1]++;\r
1046     if (fShutdown)\r
1047         return false;\r
1048     if (!pnode)\r
1049         return false;\r
1050     pnode->fNetworkNode = true;\r
1051 \r
1052     if (addrLocalHost.IsRoutable() && !fUseProxy)\r
1053     {\r
1054         // Advertise our address\r
1055         vector<CAddress> vAddr;\r
1056         vAddr.push_back(addrLocalHost);\r
1057         pnode->PushMessage("addr", vAddr);\r
1058     }\r
1059 \r
1060     // Get as many addresses as we can\r
1061     pnode->PushMessage("getaddr");\r
1062     pnode->fGetAddr = true; // don't relay the results of the getaddr\r
1063 \r
1064     ////// should the one on the receiving end do this too?\r
1065     // Subscribe our local subscription list\r
1066     const unsigned int nHops = 0;\r
1067     for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++)\r
1068         if (pnodeLocalHost->vfSubscribe[nChannel])\r
1069             pnode->PushMessage("subscribe", nChannel, nHops);\r
1070 \r
1071     return true;\r
1072 }\r
1073 \r
1074 \r
1075 \r
1076 \r
1077 \r
1078 \r
1079 \r
1080 \r
1081 void ThreadMessageHandler(void* parg)\r
1082 {\r
1083     IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));\r
1084     try\r
1085     {\r
1086         vnThreadsRunning[2]++;\r
1087         ThreadMessageHandler2(parg);\r
1088         vnThreadsRunning[2]--;\r
1089     }\r
1090     catch (std::exception& e) {\r
1091         vnThreadsRunning[2]--;\r
1092         PrintException(&e, "ThreadMessageHandler()");\r
1093     } catch (...) {\r
1094         vnThreadsRunning[2]--;\r
1095         PrintException(NULL, "ThreadMessageHandler()");\r
1096     }\r
1097     printf("ThreadMessageHandler exiting\n");\r
1098 }\r
1099 \r
1100 void ThreadMessageHandler2(void* parg)\r
1101 {\r
1102     printf("ThreadMessageHandler started\n");\r
1103     SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);\r
1104     while (!fShutdown)\r
1105     {\r
1106         vector<CNode*> vNodesCopy;\r
1107         CRITICAL_BLOCK(cs_vNodes)\r
1108         {\r
1109             vNodesCopy = vNodes;\r
1110             foreach(CNode* pnode, vNodesCopy)\r
1111                 pnode->AddRef();\r
1112         }\r
1113 \r
1114         // Poll the connected nodes for messages\r
1115         CNode* pnodeTrickle = NULL;\r
1116         if (!vNodesCopy.empty())\r
1117             pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];\r
1118         foreach(CNode* pnode, vNodesCopy)\r
1119         {\r
1120             // Receive messages\r
1121             TRY_CRITICAL_BLOCK(pnode->cs_vRecv)\r
1122                 ProcessMessages(pnode);\r
1123             if (fShutdown)\r
1124                 return;\r
1125 \r
1126             // Send messages\r
1127             TRY_CRITICAL_BLOCK(pnode->cs_vSend)\r
1128                 SendMessages(pnode, pnode == pnodeTrickle);\r
1129             if (fShutdown)\r
1130                 return;\r
1131         }\r
1132 \r
1133         CRITICAL_BLOCK(cs_vNodes)\r
1134         {\r
1135             foreach(CNode* pnode, vNodesCopy)\r
1136                 pnode->Release();\r
1137         }\r
1138 \r
1139         // Wait and allow messages to bunch up\r
1140         vnThreadsRunning[2]--;\r
1141         Sleep(100);\r
1142         vnThreadsRunning[2]++;\r
1143         if (fShutdown)\r
1144             return;\r
1145     }\r
1146 }\r
1147 \r
1148 \r
1149 \r
1150 \r
1151 \r
1152 \r
1153 \r
1154 \r
1155 \r
1156 bool BindListenPort(string& strError)\r
1157 {\r
1158     strError = "";\r
1159     int nOne = 1;\r
1160 \r
1161 #ifdef __WXMSW__\r
1162     // Initialize Windows Sockets\r
1163     WSADATA wsadata;\r
1164     int ret = WSAStartup(MAKEWORD(2,2), &wsadata);\r
1165     if (ret != NO_ERROR)\r
1166     {\r
1167         strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);\r
1168         printf("%s\n", strError.c_str());\r
1169         return false;\r
1170     }\r
1171 #endif\r
1172 \r
1173     // Create socket for listening for incoming connections\r
1174     hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
1175     if (hListenSocket == INVALID_SOCKET)\r
1176     {\r
1177         strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());\r
1178         printf("%s\n", strError.c_str());\r
1179         return false;\r
1180     }\r
1181 \r
1182 #if defined(__BSD__) || defined(__WXMAC_OSX__)\r
1183     // Different way of disabling SIGPIPE on BSD\r
1184     setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));\r
1185 #endif\r
1186 \r
1187 #ifndef __WXMSW__\r
1188     // Allow binding if the port is still in TIME_WAIT state after\r
1189     // the program was closed and restarted.  Not an issue on windows.\r
1190     setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));\r
1191 #endif\r
1192 \r
1193 #ifdef __WXMSW__\r
1194     // Set to nonblocking, incoming connections will also inherit this\r
1195     if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)\r
1196 #else\r
1197     if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)\r
1198 #endif\r
1199     {\r
1200         strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());\r
1201         printf("%s\n", strError.c_str());\r
1202         return false;\r
1203     }\r
1204 \r
1205     // The sockaddr_in structure specifies the address family,\r
1206     // IP address, and port for the socket that is being bound\r
1207     struct sockaddr_in sockaddr;\r
1208     memset(&sockaddr, 0, sizeof(sockaddr));\r
1209     sockaddr.sin_family = AF_INET;\r
1210     sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer\r
1211     sockaddr.sin_port = DEFAULT_PORT;\r
1212     if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)\r
1213     {\r
1214         int nErr = WSAGetLastError();\r
1215         if (nErr == WSAEADDRINUSE)\r
1216             strError = strprintf("Unable to bind to port %d on this computer.  Bitcoin is probably already running.", ntohs(sockaddr.sin_port));\r
1217         else\r
1218             strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);\r
1219         printf("%s\n", strError.c_str());\r
1220         return false;\r
1221     }\r
1222     printf("Bound to port %d\n", ntohs(sockaddr.sin_port));\r
1223 \r
1224     // Listen for incoming connections\r
1225     if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)\r
1226     {\r
1227         strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());\r
1228         printf("%s\n", strError.c_str());\r
1229         return false;\r
1230     }\r
1231 \r
1232     return true;\r
1233 }\r
1234 \r
1235 void StartNode(void* parg)\r
1236 {\r
1237     if (pnodeLocalHost == NULL)\r
1238         pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));\r
1239 \r
1240 #ifdef __WXMSW__\r
1241     // Get local host ip\r
1242     char pszHostName[1000] = "";\r
1243     if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)\r
1244     {\r
1245         struct hostent* phostent = gethostbyname(pszHostName);\r
1246         if (phostent)\r
1247         {\r
1248             // Take the first IP that isn't loopback 127.x.x.x\r
1249             for (int i = 0; phostent->h_addr_list[i] != NULL; i++)\r
1250                 printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());\r
1251             for (int i = 0; phostent->h_addr_list[i] != NULL; i++)\r
1252             {\r
1253                 CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);\r
1254                 if (addr.IsValid() && addr.GetByte(3) != 127)\r
1255                 {\r
1256                     addrLocalHost = addr;\r
1257                     break;\r
1258                 }\r
1259             }\r
1260         }\r
1261     }\r
1262 #else\r
1263     // Get local host ip\r
1264     struct ifaddrs* myaddrs;\r
1265     if (getifaddrs(&myaddrs) == 0)\r
1266     {\r
1267         for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)\r
1268         {\r
1269             if (ifa->ifa_addr == NULL) continue;\r
1270             if ((ifa->ifa_flags & IFF_UP) == 0) continue;\r
1271             if (strcmp(ifa->ifa_name, "lo") == 0) continue;\r
1272             if (strcmp(ifa->ifa_name, "lo0") == 0) continue;\r
1273             char pszIP[100];\r
1274             if (ifa->ifa_addr->sa_family == AF_INET)\r
1275             {\r
1276                 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);\r
1277                 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)\r
1278                     printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);\r
1279 \r
1280                 // Take the first IP that isn't loopback 127.x.x.x\r
1281                 CAddress addr(*(unsigned int*)&s4->sin_addr, DEFAULT_PORT, nLocalServices);\r
1282                 if (addr.IsValid() && addr.GetByte(3) != 127)\r
1283                 {\r
1284                     addrLocalHost = addr;\r
1285                     break;\r
1286                 }\r
1287             }\r
1288             else if (ifa->ifa_addr->sa_family == AF_INET6)\r
1289             {\r
1290                 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);\r
1291                 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)\r
1292                     printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);\r
1293             }\r
1294         }\r
1295         freeifaddrs(myaddrs);\r
1296     }\r
1297 #endif\r
1298     printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());\r
1299 \r
1300     // Get our external IP address for incoming connections\r
1301     if (fUseProxy)\r
1302     {\r
1303         // Proxies can't take incoming connections\r
1304         addrLocalHost.ip = CAddress("0.0.0.0").ip;\r
1305         printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());\r
1306     }\r
1307     else\r
1308     {\r
1309         if (addrIncoming.IsValid())\r
1310             addrLocalHost.ip = addrIncoming.ip;\r
1311 \r
1312         if (GetMyExternalIP(addrLocalHost.ip))\r
1313         {\r
1314             addrIncoming = addrLocalHost;\r
1315             CWalletDB().WriteSetting("addrIncoming", addrIncoming);\r
1316             printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());\r
1317         }\r
1318     }\r
1319 \r
1320     //\r
1321     // Start threads\r
1322     //\r
1323 \r
1324     // Get addresses from IRC and advertise ours\r
1325     if (!CreateThread(ThreadIRCSeed, NULL))\r
1326         printf("Error: CreateThread(ThreadIRCSeed) failed\n");\r
1327 \r
1328     // Send and receive from sockets, accept connections\r
1329     pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);\r
1330 \r
1331     // Initiate outbound connections\r
1332     if (!CreateThread(ThreadOpenConnections, NULL))\r
1333         printf("Error: CreateThread(ThreadOpenConnections) failed\n");\r
1334 \r
1335     // Process messages\r
1336     if (!CreateThread(ThreadMessageHandler, NULL))\r
1337         printf("Error: CreateThread(ThreadMessageHandler) failed\n");\r
1338 \r
1339     // Generate coins in the background\r
1340     GenerateBitcoins(fGenerateBitcoins);\r
1341 \r
1342     //\r
1343     // Thread monitoring\r
1344     // Not really needed anymore, the cause of the hanging was fixed\r
1345     //\r
1346     loop\r
1347     {\r
1348         Sleep(1000);\r
1349         if (fShutdown)\r
1350             return;\r
1351         if (GetTime() - nThreadSocketHandlerHeartbeat > 15 * 60)\r
1352         {\r
1353             // First see if closing sockets will free it\r
1354             printf("*** ThreadSocketHandler is stopped ***\n");\r
1355             CRITICAL_BLOCK(cs_vNodes)\r
1356             {\r
1357                 foreach(CNode* pnode, vNodes)\r
1358                 {\r
1359                     bool fGot = false;\r
1360                     TRY_CRITICAL_BLOCK(pnode->cs_vRecv)\r
1361                         TRY_CRITICAL_BLOCK(pnode->cs_vSend)\r
1362                             fGot = true;\r
1363                     if (!fGot)\r
1364                     {\r
1365                         printf("*** closing socket\n");\r
1366                         pnode->CloseSocketDisconnect();\r
1367                     }\r
1368                 }\r
1369             }\r
1370             Sleep(10000);\r
1371             if (fShutdown)\r
1372                 return;\r
1373             if (GetTime() - nThreadSocketHandlerHeartbeat < 60)\r
1374                 continue;\r
1375 \r
1376             // Hopefully it never comes to this.\r
1377             // We know it'll always be hung in the recv or send call.\r
1378             // cs_vRecv or cs_vSend may be left permanently unreleased,\r
1379             // but we always only use TRY_CRITICAL_SECTION on them.\r
1380             printf("*** Restarting ThreadSocketHandler ***\n");\r
1381             TerminateThread(hThreadSocketHandler, 0);\r
1382             #ifdef __WXMSW__\r
1383             CloseHandle(hThreadSocketHandler);\r
1384             #endif\r
1385             vnThreadsRunning[0] = 0;\r
1386 \r
1387             // Restart\r
1388             hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);\r
1389             nThreadSocketHandlerHeartbeat = GetTime();\r
1390         }\r
1391     }\r
1392 }\r
1393 \r
1394 bool StopNode()\r
1395 {\r
1396     printf("StopNode()\n");\r
1397     fShutdown = true;\r
1398     nTransactionsUpdated++;\r
1399     int64 nStart = GetTime();\r
1400     while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0)\r
1401     {\r
1402         if (GetTime() - nStart > 20)\r
1403             break;\r
1404         Sleep(20);\r
1405     }\r
1406     if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");\r
1407     if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");\r
1408     if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");\r
1409     if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");\r
1410     if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");\r
1411     while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)\r
1412         Sleep(20);\r
1413     Sleep(50);\r
1414 \r
1415     return true;\r
1416 }\r
1417 \r
1418 class CNetCleanup\r
1419 {\r
1420 public:\r
1421     CNetCleanup()\r
1422     {\r
1423     }\r
1424     ~CNetCleanup()\r
1425     {\r
1426         // Close sockets\r
1427         foreach(CNode* pnode, vNodes)\r
1428             if (pnode->hSocket != INVALID_SOCKET)\r
1429                 closesocket(pnode->hSocket);\r
1430         if (hListenSocket != INVALID_SOCKET)\r
1431             if (closesocket(hListenSocket) == SOCKET_ERROR)\r
1432                 printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());\r
1433 \r
1434 #ifdef __WXMSW__\r
1435         // Shutdown Windows Sockets\r
1436         WSACleanup();\r
1437 #endif\r
1438     }\r
1439 }\r
1440 instance_of_cnetcleanup;\r