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