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