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