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
7 static const int MAX_OUTBOUND_CONNECTIONS = 8;
\r
9 void ThreadMessageHandler2(void* parg);
\r
10 void ThreadSocketHandler2(void* parg);
\r
11 void ThreadOpenConnections2(void* parg);
\r
12 bool OpenNetworkConnection(const CAddress& addrConnect);
\r
19 // Global state variables
\r
21 bool fClient = false;
\r
22 uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
\r
23 CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices);
\r
24 CNode* pnodeLocalHost = NULL;
\r
25 uint64 nLocalHostNonce = 0;
\r
26 array<int, 10> vnThreadsRunning;
\r
27 SOCKET hListenSocket = INVALID_SOCKET;
\r
28 int64 nThreadSocketHandlerHeartbeat = INT64_MAX;
\r
30 vector<CNode*> vNodes;
\r
31 CCriticalSection cs_vNodes;
\r
32 map<vector<unsigned char>, CAddress> mapAddresses;
\r
33 CCriticalSection cs_mapAddresses;
\r
34 map<CInv, CDataStream> mapRelay;
\r
35 deque<pair<int64, CInv> > vRelayExpiration;
\r
36 CCriticalSection cs_mapRelay;
\r
37 map<CInv, int64> mapAlreadyAskedFor;
\r
40 int fUseProxy = false;
\r
41 CAddress addrProxy("127.0.0.1:9050");
\r
47 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
\r
49 // Filter out duplicate requests
\r
50 if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
\r
52 pindexLastGetBlocksBegin = pindexBegin;
\r
53 hashLastGetBlocksEnd = hashEnd;
\r
55 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
\r
62 bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
\r
64 hSocketRet = INVALID_SOCKET;
\r
66 SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
\r
67 if (hSocket == INVALID_SOCKET)
\r
69 #if defined(__BSD__) || defined(__WXMAC_OSX__)
\r
71 setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
\r
74 bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168));
\r
75 bool fProxy = (fUseProxy && fRoutable);
\r
76 struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
\r
78 if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
\r
80 closesocket(hSocket);
\r
86 printf("proxy connecting %s\n", addrConnect.ToStringLog().c_str());
\r
87 char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
\r
88 memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
\r
89 memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
\r
90 char* pszSocks4 = pszSocks4IP;
\r
91 int nSize = sizeof(pszSocks4IP);
\r
93 int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
\r
96 closesocket(hSocket);
\r
97 return error("Error sending to proxy");
\r
100 if (recv(hSocket, pchRet, 8, 0) != 8)
\r
102 closesocket(hSocket);
\r
103 return error("Error reading proxy response");
\r
105 if (pchRet[1] != 0x5a)
\r
107 closesocket(hSocket);
\r
108 if (pchRet[1] != 0x5b)
\r
109 printf("ERROR: Proxy returned error %d\n", pchRet[1]);
\r
112 printf("proxy connected %s\n", addrConnect.ToStringLog().c_str());
\r
115 hSocketRet = hSocket;
\r
121 bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
\r
124 if (!ConnectSocket(addrConnect, hSocket))
\r
125 return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());
\r
127 send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);
\r
130 while (RecvLine(hSocket, strLine))
\r
132 if (strLine.empty())
\r
136 if (!RecvLine(hSocket, strLine))
\r
138 closesocket(hSocket);
\r
141 if (strLine.find(pszKeyword) != -1)
\r
143 strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
\r
147 closesocket(hSocket);
\r
148 if (strLine.find("<"))
\r
149 strLine = strLine.substr(0, strLine.find("<"));
\r
150 strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
\r
151 while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
\r
152 strLine.resize(strLine.size()-1);
\r
153 CAddress addr(strLine.c_str());
\r
154 printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
\r
155 if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
\r
161 closesocket(hSocket);
\r
162 return error("GetMyExternalIP() : connection closed");
\r
166 bool GetMyExternalIP(unsigned int& ipRet)
\r
168 CAddress addrConnect;
\r
169 const char* pszGet;
\r
170 const char* pszKeyword;
\r
175 for (int nLookup = 0; nLookup <= 1; nLookup++)
\r
176 for (int nHost = 1; nHost <= 2; nHost++)
\r
180 addrConnect = CAddress("70.86.96.218:80"); // www.ipaddressworld.com
\r
184 struct hostent* phostent = gethostbyname("www.ipaddressworld.com");
\r
185 if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
\r
186 addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80));
\r
189 pszGet = "GET /ip.php HTTP/1.1\r\n"
\r
190 "Host: www.ipaddressworld.com\r\n"
\r
191 "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
\r
192 "Connection: close\r\n"
\r
195 pszKeyword = "IP:";
\r
197 else if (nHost == 2)
\r
199 addrConnect = CAddress("208.78.68.70:80"); // checkip.dyndns.org
\r
203 struct hostent* phostent = gethostbyname("checkip.dyndns.org");
\r
204 if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
\r
205 addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80));
\r
208 pszGet = "GET / HTTP/1.1\r\n"
\r
209 "Host: checkip.dyndns.org\r\n"
\r
210 "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
\r
211 "Connection: close\r\n"
\r
214 pszKeyword = "Address:";
\r
217 if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
\r
228 bool AddAddress(CAddress addr)
\r
230 if (!addr.IsRoutable())
\r
232 if (addr.ip == addrLocalHost.ip)
\r
234 CRITICAL_BLOCK(cs_mapAddresses)
\r
236 map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
\r
237 if (it == mapAddresses.end())
\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
247 bool fUpdated = false;
\r
248 CAddress& addrFound = (*it).second;
\r
249 if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
\r
251 // Services have been added
\r
252 addrFound.nServices |= addr.nServices;
\r
255 bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
\r
256 int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
\r
257 if (addrFound.nTime < addr.nTime - nUpdateInterval)
\r
259 // Periodically update most recently seen time
\r
260 addrFound.nTime = addr.nTime;
\r
264 CAddrDB().WriteAddress(addrFound);
\r
270 void AddressCurrentlyConnected(const CAddress& addr)
\r
272 CRITICAL_BLOCK(cs_mapAddresses)
\r
274 // Only if it's been published already
\r
275 map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
\r
276 if (it != mapAddresses.end())
\r
278 CAddress& addrFound = (*it).second;
\r
279 int64 nUpdateInterval = 20 * 60;
\r
280 if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
\r
282 // Periodically update most recently seen time
\r
283 addrFound.nTime = GetAdjustedTime();
\r
285 addrdb.WriteAddress(addrFound);
\r
295 void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
\r
297 // If the dialog might get closed before the reply comes back,
\r
298 // call this in the destructor so it doesn't get called after it's deleted.
\r
299 CRITICAL_BLOCK(cs_vNodes)
\r
301 foreach(CNode* pnode, vNodes)
\r
303 CRITICAL_BLOCK(pnode->cs_mapRequests)
\r
305 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
\r
307 CRequestTracker& tracker = (*mi).second;
\r
308 if (tracker.fn == fn && tracker.param1 == param1)
\r
309 pnode->mapRequests.erase(mi++);
\r
325 // Subscription methods for the broadcast and subscription system.
\r
326 // Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
\r
328 // The subscription system uses a meet-in-the-middle strategy.
\r
329 // With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
\r
330 // subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
\r
333 bool AnySubscribed(unsigned int nChannel)
\r
335 if (pnodeLocalHost->IsSubscribed(nChannel))
\r
337 CRITICAL_BLOCK(cs_vNodes)
\r
338 foreach(CNode* pnode, vNodes)
\r
339 if (pnode->IsSubscribed(nChannel))
\r
344 bool CNode::IsSubscribed(unsigned int nChannel)
\r
346 if (nChannel >= vfSubscribe.size())
\r
348 return vfSubscribe[nChannel];
\r
351 void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
\r
353 if (nChannel >= vfSubscribe.size())
\r
356 if (!AnySubscribed(nChannel))
\r
359 CRITICAL_BLOCK(cs_vNodes)
\r
360 foreach(CNode* pnode, vNodes)
\r
362 pnode->PushMessage("subscribe", nChannel, nHops);
\r
365 vfSubscribe[nChannel] = true;
\r
368 void CNode::CancelSubscribe(unsigned int nChannel)
\r
370 if (nChannel >= vfSubscribe.size())
\r
373 // Prevent from relaying cancel if wasn't subscribed
\r
374 if (!vfSubscribe[nChannel])
\r
376 vfSubscribe[nChannel] = false;
\r
378 if (!AnySubscribed(nChannel))
\r
380 // Relay subscription cancel
\r
381 CRITICAL_BLOCK(cs_vNodes)
\r
382 foreach(CNode* pnode, vNodes)
\r
384 pnode->PushMessage("sub-cancel", nChannel);
\r
396 CNode* FindNode(unsigned int ip)
\r
398 CRITICAL_BLOCK(cs_vNodes)
\r
400 foreach(CNode* pnode, vNodes)
\r
401 if (pnode->addr.ip == ip)
\r
407 CNode* FindNode(CAddress addr)
\r
409 CRITICAL_BLOCK(cs_vNodes)
\r
411 foreach(CNode* pnode, vNodes)
\r
412 if (pnode->addr == addr)
\r
418 CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
\r
420 if (addrConnect.ip == addrLocalHost.ip)
\r
423 // Look for an existing connection
\r
424 CNode* pnode = FindNode(addrConnect.ip);
\r
428 pnode->AddRef(nTimeout);
\r
435 printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
\r
436 addrConnect.ToStringLog().c_str(),
\r
437 (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
\r
438 (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
\r
440 CRITICAL_BLOCK(cs_mapAddresses)
\r
441 mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
\r
445 if (ConnectSocket(addrConnect, hSocket))
\r
448 printf("connected %s\n", addrConnect.ToStringLog().c_str());
\r
450 // Set to nonblocking
\r
453 if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
\r
454 printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
\r
456 if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
\r
457 printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno);
\r
461 CNode* pnode = new CNode(hSocket, addrConnect, false);
\r
463 pnode->AddRef(nTimeout);
\r
466 CRITICAL_BLOCK(cs_vNodes)
\r
467 vNodes.push_back(pnode);
\r
469 pnode->nTimeConnected = GetTime();
\r
478 void CNode::CloseSocketDisconnect()
\r
480 fDisconnect = true;
\r
481 if (hSocket != INVALID_SOCKET)
\r
484 printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
\r
485 printf("disconnecting node %s\n", addr.ToStringLog().c_str());
\r
486 closesocket(hSocket);
\r
487 hSocket = INVALID_SOCKET;
\r
491 void CNode::Cleanup()
\r
493 // All of a nodes broadcasts and subscriptions are automatically torn down
\r
494 // when it goes down, so a node has to stay up to keep its broadcast going.
\r
496 // Cancel subscriptions
\r
497 for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
\r
498 if (vfSubscribe[nChannel])
\r
499 CancelSubscribe(nChannel);
\r
514 void ThreadSocketHandler(void* parg)
\r
516 IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
\r
519 vnThreadsRunning[0]++;
\r
520 ThreadSocketHandler2(parg);
\r
521 vnThreadsRunning[0]--;
\r
523 catch (std::exception& e) {
\r
524 vnThreadsRunning[0]--;
\r
525 PrintException(&e, "ThreadSocketHandler()");
\r
527 vnThreadsRunning[0]--;
\r
528 throw; // support pthread_cancel()
\r
530 printf("ThreadSocketHandler exiting\n");
\r
533 void ThreadSocketHandler2(void* parg)
\r
535 printf("ThreadSocketHandler started\n");
\r
536 list<CNode*> vNodesDisconnected;
\r
537 int nPrevNodeCount = 0;
\r
542 // Disconnect nodes
\r
544 CRITICAL_BLOCK(cs_vNodes)
\r
546 // Disconnect unused nodes
\r
547 vector<CNode*> vNodesCopy = vNodes;
\r
548 foreach(CNode* pnode, vNodesCopy)
\r
550 if (pnode->fDisconnect ||
\r
551 (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
\r
553 // remove from vNodes
\r
554 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
\r
556 // close socket and cleanup
\r
557 pnode->CloseSocketDisconnect();
\r
560 // hold in disconnected pool until all refs are released
\r
561 pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
\r
562 if (pnode->fNetworkNode || pnode->fInbound)
\r
564 vNodesDisconnected.push_back(pnode);
\r
568 // Delete disconnected nodes
\r
569 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
\r
570 foreach(CNode* pnode, vNodesDisconnectedCopy)
\r
572 // wait until threads are done using it
\r
573 if (pnode->GetRefCount() <= 0)
\r
575 bool fDelete = false;
\r
576 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
\r
577 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
\r
578 TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
\r
579 TRY_CRITICAL_BLOCK(pnode->cs_inventory)
\r
583 vNodesDisconnected.remove(pnode);
\r
589 if (vNodes.size() != nPrevNodeCount)
\r
591 nPrevNodeCount = vNodes.size();
\r
592 MainFrameRepaint();
\r
597 // Find which sockets have data to receive
\r
599 struct timeval timeout;
\r
600 timeout.tv_sec = 0;
\r
601 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
\r
606 FD_ZERO(&fdsetRecv);
\r
607 FD_ZERO(&fdsetSend);
\r
608 FD_ZERO(&fdsetError);
\r
609 SOCKET hSocketMax = 0;
\r
610 FD_SET(hListenSocket, &fdsetRecv);
\r
611 hSocketMax = max(hSocketMax, hListenSocket);
\r
612 CRITICAL_BLOCK(cs_vNodes)
\r
614 foreach(CNode* pnode, vNodes)
\r
616 if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)
\r
618 FD_SET(pnode->hSocket, &fdsetRecv);
\r
619 FD_SET(pnode->hSocket, &fdsetError);
\r
620 hSocketMax = max(hSocketMax, pnode->hSocket);
\r
621 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
\r
622 if (!pnode->vSend.empty())
\r
623 FD_SET(pnode->hSocket, &fdsetSend);
\r
627 vnThreadsRunning[0]--;
\r
628 int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
\r
629 vnThreadsRunning[0]++;
\r
632 if (nSelect == SOCKET_ERROR)
\r
634 int nErr = WSAGetLastError();
\r
635 printf("socket select error %d\n", nErr);
\r
636 for (int i = 0; i <= hSocketMax; i++)
\r
637 FD_SET(i, &fdsetRecv);
\r
638 FD_ZERO(&fdsetSend);
\r
639 FD_ZERO(&fdsetError);
\r
640 Sleep(timeout.tv_usec/1000);
\r
645 // Accept new connections
\r
647 if (FD_ISSET(hListenSocket, &fdsetRecv))
\r
649 struct sockaddr_in sockaddr;
\r
650 socklen_t len = sizeof(sockaddr);
\r
651 SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
\r
652 CAddress addr(sockaddr);
\r
653 if (hSocket == INVALID_SOCKET)
\r
655 if (WSAGetLastError() != WSAEWOULDBLOCK)
\r
656 printf("socket error accept failed: %d\n", WSAGetLastError());
\r
658 else if (mapArgs.count("-maxconnections") && (int)vNodes.size() >= atoi(mapArgs["-maxconnections"]) - MAX_OUTBOUND_CONNECTIONS)
\r
660 closesocket(hSocket);
\r
664 printf("accepted connection %s\n", addr.ToStringLog().c_str());
\r
665 CNode* pnode = new CNode(hSocket, addr, true);
\r
667 CRITICAL_BLOCK(cs_vNodes)
\r
668 vNodes.push_back(pnode);
\r
674 // Service each socket
\r
676 vector<CNode*> vNodesCopy;
\r
677 CRITICAL_BLOCK(cs_vNodes)
\r
679 vNodesCopy = vNodes;
\r
680 foreach(CNode* pnode, vNodesCopy)
\r
683 foreach(CNode* pnode, vNodesCopy)
\r
691 if (pnode->hSocket == INVALID_SOCKET)
\r
693 if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
\r
695 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
\r
697 CDataStream& vRecv = pnode->vRecv;
\r
698 unsigned int nPos = vRecv.size();
\r
700 // typical socket buffer is 8K-64K
\r
701 char pchBuf[0x10000];
\r
702 int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
\r
705 vRecv.resize(nPos + nBytes);
\r
706 memcpy(&vRecv[nPos], pchBuf, nBytes);
\r
707 pnode->nLastRecv = GetTime();
\r
709 else if (nBytes == 0)
\r
711 // socket closed gracefully
\r
712 if (!pnode->fDisconnect)
\r
713 printf("socket closed\n");
\r
714 pnode->CloseSocketDisconnect();
\r
716 else if (nBytes < 0)
\r
719 int nErr = WSAGetLastError();
\r
720 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
\r
722 if (!pnode->fDisconnect)
\r
723 printf("socket recv error %d\n", nErr);
\r
724 pnode->CloseSocketDisconnect();
\r
733 if (pnode->hSocket == INVALID_SOCKET)
\r
735 if (FD_ISSET(pnode->hSocket, &fdsetSend))
\r
737 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
\r
739 CDataStream& vSend = pnode->vSend;
\r
740 if (!vSend.empty())
\r
742 int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
\r
745 vSend.erase(vSend.begin(), vSend.begin() + nBytes);
\r
746 pnode->nLastSend = GetTime();
\r
748 else if (nBytes < 0)
\r
751 int nErr = WSAGetLastError();
\r
752 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
\r
754 printf("socket send error %d\n", nErr);
\r
755 pnode->CloseSocketDisconnect();
\r
763 // Inactivity checking
\r
765 if (pnode->vSend.empty())
\r
766 pnode->nLastSendEmpty = GetTime();
\r
767 if (GetTime() - pnode->nTimeConnected > 60)
\r
769 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
\r
771 printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
\r
772 pnode->fDisconnect = true;
\r
774 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
\r
776 printf("socket not sending\n");
\r
777 pnode->fDisconnect = true;
\r
779 else if (GetTime() - pnode->nLastRecv > 90*60)
\r
781 printf("socket inactivity timeout\n");
\r
782 pnode->fDisconnect = true;
\r
786 CRITICAL_BLOCK(cs_vNodes)
\r
788 foreach(CNode* pnode, vNodesCopy)
\r
792 nThreadSocketHandlerHeartbeat = GetTime();
\r
809 unsigned int pnSeed[] =
\r
811 0x35218252, 0x9c9c9618, 0xda6bacad, 0xb9aca862, 0x97c235c6,
\r
812 0x146f9562, 0xb67b9e4b, 0x87cf4bc0, 0xb83945d0, 0x984333ad,
\r
813 0xbbeec555, 0x6f0eb440, 0xe0005318, 0x7797e460, 0xddc60fcc,
\r
814 0xb3bbd24a, 0x1ac85746, 0x641846a6, 0x85ee1155, 0xbb2e7a4c,
\r
815 0x9cb8514b, 0xfc342648, 0x62958fae, 0xd0a8c87a, 0xa800795b,
\r
816 0xda8c814e, 0x256a0c80, 0x3f23ec63, 0xd565df43, 0x997d9044,
\r
817 0xaa121448, 0xbed8688e, 0x59d09a5e, 0xb2931243, 0x3730ba18,
\r
818 0xdd3462d0, 0x4e4d1448, 0x171df645, 0x84ee1155,
\r
819 0x248ac445, 0x0e634444, 0x0ded1b63, 0x30c01e60,
\r
820 0xa2b9a094, 0x29e4fd43, 0x9ce61b4c, 0xdae09744,
\r
825 void ThreadOpenConnections(void* parg)
\r
827 IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
\r
830 vnThreadsRunning[1]++;
\r
831 ThreadOpenConnections2(parg);
\r
832 vnThreadsRunning[1]--;
\r
834 catch (std::exception& e) {
\r
835 vnThreadsRunning[1]--;
\r
836 PrintException(&e, "ThreadOpenConnections()");
\r
838 vnThreadsRunning[1]--;
\r
839 PrintException(NULL, "ThreadOpenConnections()");
\r
841 printf("ThreadOpenConnections exiting\n");
\r
844 void ThreadOpenConnections2(void* parg)
\r
846 printf("ThreadOpenConnections started\n");
\r
848 // Connect to specific addresses
\r
849 if (mapArgs.count("-connect"))
\r
851 for (int64 nLoop = 0;; nLoop++)
\r
853 foreach(string strAddr, mapMultiArgs["-connect"])
\r
855 CAddress addr(strAddr, NODE_NETWORK);
\r
856 if (addr.IsValid())
\r
857 OpenNetworkConnection(addr);
\r
858 for (int i = 0; i < 10 && i < nLoop; i++)
\r
868 // Connect to manually added nodes first
\r
869 if (mapArgs.count("-addnode"))
\r
871 foreach(string strAddr, mapMultiArgs["-addnode"])
\r
873 CAddress addr(strAddr, NODE_NETWORK);
\r
874 if (addr.IsValid())
\r
876 OpenNetworkConnection(addr);
\r
884 // Initiate network connections
\r
885 int64 nStart = GetTime();
\r
888 // Limit outbound connections
\r
889 vnThreadsRunning[1]--;
\r
894 CRITICAL_BLOCK(cs_vNodes)
\r
895 foreach(CNode* pnode, vNodes)
\r
896 if (!pnode->fInbound)
\r
898 int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
\r
899 if (mapArgs.count("-maxconnections"))
\r
900 nMaxOutboundConnections = min(nMaxOutboundConnections, atoi(mapArgs["-maxconnections"]));
\r
901 if (nOutbound < nMaxOutboundConnections)
\r
907 vnThreadsRunning[1]++;
\r
911 CRITICAL_BLOCK(cs_mapAddresses)
\r
913 // Add seed nodes if IRC isn't working
\r
914 static bool fSeedUsed;
\r
915 bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
\r
916 if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR))
\r
918 for (int i = 0; i < ARRAYLEN(pnSeed); i++)
\r
920 // It'll only connect to one or two seed nodes because once it connects,
\r
921 // it'll get a pile of addresses with newer timestamps.
\r
923 addr.ip = pnSeed[i];
\r
930 if (fSeedUsed && mapAddresses.size() > ARRAYLEN(pnSeed) + 100)
\r
932 // Disconnect seed nodes
\r
933 set<unsigned int> setSeed(pnSeed, pnSeed + ARRAYLEN(pnSeed));
\r
934 static int64 nSeedDisconnected;
\r
935 if (nSeedDisconnected == 0)
\r
937 nSeedDisconnected = GetTime();
\r
938 CRITICAL_BLOCK(cs_vNodes)
\r
939 foreach(CNode* pnode, vNodes)
\r
940 if (setSeed.count(pnode->addr.ip))
\r
941 pnode->fDisconnect = true;
\r
944 // Keep setting timestamps to 0 so they won't reconnect
\r
945 if (GetTime() - nSeedDisconnected < 60 * 60)
\r
947 foreach(PAIRTYPE(const vector<unsigned char>, CAddress)& item, mapAddresses)
\r
949 if (setSeed.count(item.second.ip))
\r
951 item.second.nTime = 0;
\r
952 CAddrDB().WriteAddress(item.second);
\r
961 // Choose an address to connect to based on most recently seen
\r
963 CAddress addrConnect;
\r
964 int64 nBest = INT64_MIN;
\r
966 // Only connect to one address per a.b.?.? range.
\r
967 // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
\r
968 set<unsigned int> setConnected;
\r
969 CRITICAL_BLOCK(cs_vNodes)
\r
970 foreach(CNode* pnode, vNodes)
\r
971 setConnected.insert(pnode->addr.ip & 0x0000ffff);
\r
973 CRITICAL_BLOCK(cs_mapAddresses)
\r
975 foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
\r
977 const CAddress& addr = item.second;
\r
978 if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
\r
980 int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
\r
981 int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
\r
983 // Randomize the order in a deterministic way, putting the standard port first
\r
984 int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
\r
985 if (addr.port != DEFAULT_PORT)
\r
986 nRandomizer += 2 * 60 * 60;
\r
988 // Last seen Base retry frequency
\r
992 // 24 hours 5 hours
\r
993 // 48 hours 7 hours
\r
995 // 30 days 27 hours
\r
996 // 90 days 46 hours
\r
997 // 365 days 93 hours
\r
998 int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
\r
1000 // Fast reconnect for one hour after last seen
\r
1001 if (nSinceLastSeen < 60 * 60)
\r
1004 // Limit retry frequency
\r
1005 if (nSinceLastTry < nDelay)
\r
1008 // If we have IRC, we'll be notified when they first come online,
\r
1009 // and again every 24 hours by the refresh broadcast.
\r
1010 if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
\r
1013 // Only try the old stuff if we don't have enough connections
\r
1014 if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
\r
1017 // If multiple addresses are ready, prioritize by time since
\r
1018 // last seen and time since last tried.
\r
1019 int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
\r
1020 if (nScore > nBest)
\r
1023 addrConnect = addr;
\r
1028 if (addrConnect.IsValid())
\r
1029 OpenNetworkConnection(addrConnect);
\r
1033 bool OpenNetworkConnection(const CAddress& addrConnect)
\r
1036 // Initiate outbound network connection
\r
1040 if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
\r
1043 vnThreadsRunning[1]--;
\r
1044 CNode* pnode = ConnectNode(addrConnect);
\r
1045 vnThreadsRunning[1]++;
\r
1050 pnode->fNetworkNode = true;
\r
1052 if (addrLocalHost.IsRoutable() && !fUseProxy)
\r
1054 // Advertise our address
\r
1055 vector<CAddress> vAddr;
\r
1056 vAddr.push_back(addrLocalHost);
\r
1057 pnode->PushMessage("addr", vAddr);
\r
1060 // Get as many addresses as we can
\r
1061 pnode->PushMessage("getaddr");
\r
1062 pnode->fGetAddr = true; // don't relay the results of the getaddr
\r
1064 ////// should the one on the receiving end do this too?
\r
1065 // Subscribe our local subscription list
\r
1066 const unsigned int nHops = 0;
\r
1067 for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++)
\r
1068 if (pnodeLocalHost->vfSubscribe[nChannel])
\r
1069 pnode->PushMessage("subscribe", nChannel, nHops);
\r
1081 void ThreadMessageHandler(void* parg)
\r
1083 IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
\r
1086 vnThreadsRunning[2]++;
\r
1087 ThreadMessageHandler2(parg);
\r
1088 vnThreadsRunning[2]--;
\r
1090 catch (std::exception& e) {
\r
1091 vnThreadsRunning[2]--;
\r
1092 PrintException(&e, "ThreadMessageHandler()");
\r
1094 vnThreadsRunning[2]--;
\r
1095 PrintException(NULL, "ThreadMessageHandler()");
\r
1097 printf("ThreadMessageHandler exiting\n");
\r
1100 void ThreadMessageHandler2(void* parg)
\r
1102 printf("ThreadMessageHandler started\n");
\r
1103 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
\r
1104 while (!fShutdown)
\r
1106 vector<CNode*> vNodesCopy;
\r
1107 CRITICAL_BLOCK(cs_vNodes)
\r
1109 vNodesCopy = vNodes;
\r
1110 foreach(CNode* pnode, vNodesCopy)
\r
1114 // Poll the connected nodes for messages
\r
1115 CNode* pnodeTrickle = NULL;
\r
1116 if (!vNodesCopy.empty())
\r
1117 pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
\r
1118 foreach(CNode* pnode, vNodesCopy)
\r
1120 // Receive messages
\r
1121 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
\r
1122 ProcessMessages(pnode);
\r
1127 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
\r
1128 SendMessages(pnode, pnode == pnodeTrickle);
\r
1133 CRITICAL_BLOCK(cs_vNodes)
\r
1135 foreach(CNode* pnode, vNodesCopy)
\r
1139 // Wait and allow messages to bunch up
\r
1140 vnThreadsRunning[2]--;
\r
1142 vnThreadsRunning[2]++;
\r
1156 bool BindListenPort(string& strError)
\r
1162 // Initialize Windows Sockets
\r
1164 int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
\r
1165 if (ret != NO_ERROR)
\r
1167 strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
\r
1168 printf("%s\n", strError.c_str());
\r
1173 // Create socket for listening for incoming connections
\r
1174 hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
\r
1175 if (hListenSocket == INVALID_SOCKET)
\r
1177 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
\r
1178 printf("%s\n", strError.c_str());
\r
1182 #if defined(__BSD__) || defined(__WXMAC_OSX__)
\r
1183 // Different way of disabling SIGPIPE on BSD
\r
1184 setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
\r
1188 // Allow binding if the port is still in TIME_WAIT state after
\r
1189 // the program was closed and restarted. Not an issue on windows.
\r
1190 setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
\r
1194 // Set to nonblocking, incoming connections will also inherit this
\r
1195 if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
\r
1197 if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
\r
1200 strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
\r
1201 printf("%s\n", strError.c_str());
\r
1205 // The sockaddr_in structure specifies the address family,
\r
1206 // IP address, and port for the socket that is being bound
\r
1207 struct sockaddr_in sockaddr;
\r
1208 memset(&sockaddr, 0, sizeof(sockaddr));
\r
1209 sockaddr.sin_family = AF_INET;
\r
1210 sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
\r
1211 sockaddr.sin_port = DEFAULT_PORT;
\r
1212 if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
\r
1214 int nErr = WSAGetLastError();
\r
1215 if (nErr == WSAEADDRINUSE)
\r
1216 strError = strprintf("Unable to bind to port %d on this computer. Bitcoin is probably already running.", ntohs(sockaddr.sin_port));
\r
1218 strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
\r
1219 printf("%s\n", strError.c_str());
\r
1222 printf("Bound to port %d\n", ntohs(sockaddr.sin_port));
\r
1224 // Listen for incoming connections
\r
1225 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
\r
1227 strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
\r
1228 printf("%s\n", strError.c_str());
\r
1235 void StartNode(void* parg)
\r
1237 if (pnodeLocalHost == NULL)
\r
1238 pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));
\r
1241 // Get local host ip
\r
1242 char pszHostName[1000] = "";
\r
1243 if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
\r
1245 struct hostent* phostent = gethostbyname(pszHostName);
\r
1248 // Take the first IP that isn't loopback 127.x.x.x
\r
1249 for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
\r
1250 printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());
\r
1251 for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
\r
1253 CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);
\r
1254 if (addr.IsValid() && addr.GetByte(3) != 127)
\r
1256 addrLocalHost = addr;
\r
1263 // Get local host ip
\r
1264 struct ifaddrs* myaddrs;
\r
1265 if (getifaddrs(&myaddrs) == 0)
\r
1267 for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
\r
1269 if (ifa->ifa_addr == NULL) continue;
\r
1270 if ((ifa->ifa_flags & IFF_UP) == 0) continue;
\r
1271 if (strcmp(ifa->ifa_name, "lo") == 0) continue;
\r
1272 if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
\r
1274 if (ifa->ifa_addr->sa_family == AF_INET)
\r
1276 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
\r
1277 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
\r
1278 printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
\r
1280 // Take the first IP that isn't loopback 127.x.x.x
\r
1281 CAddress addr(*(unsigned int*)&s4->sin_addr, DEFAULT_PORT, nLocalServices);
\r
1282 if (addr.IsValid() && addr.GetByte(3) != 127)
\r
1284 addrLocalHost = addr;
\r
1288 else if (ifa->ifa_addr->sa_family == AF_INET6)
\r
1290 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
\r
1291 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
\r
1292 printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
\r
1295 freeifaddrs(myaddrs);
\r
1298 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
\r
1300 // Get our external IP address for incoming connections
\r
1303 // Proxies can't take incoming connections
\r
1304 addrLocalHost.ip = CAddress("0.0.0.0").ip;
\r
1305 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
\r
1309 if (addrIncoming.IsValid())
\r
1310 addrLocalHost.ip = addrIncoming.ip;
\r
1312 if (GetMyExternalIP(addrLocalHost.ip))
\r
1314 addrIncoming = addrLocalHost;
\r
1315 CWalletDB().WriteSetting("addrIncoming", addrIncoming);
\r
1316 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
\r
1324 // Get addresses from IRC and advertise ours
\r
1325 if (!CreateThread(ThreadIRCSeed, NULL))
\r
1326 printf("Error: CreateThread(ThreadIRCSeed) failed\n");
\r
1328 // Send and receive from sockets, accept connections
\r
1329 pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
\r
1331 // Initiate outbound connections
\r
1332 if (!CreateThread(ThreadOpenConnections, NULL))
\r
1333 printf("Error: CreateThread(ThreadOpenConnections) failed\n");
\r
1335 // Process messages
\r
1336 if (!CreateThread(ThreadMessageHandler, NULL))
\r
1337 printf("Error: CreateThread(ThreadMessageHandler) failed\n");
\r
1339 // Generate coins in the background
\r
1340 GenerateBitcoins(fGenerateBitcoins);
\r
1343 // Thread monitoring
\r
1344 // Not really needed anymore, the cause of the hanging was fixed
\r
1351 if (GetTime() - nThreadSocketHandlerHeartbeat > 15 * 60)
\r
1353 // First see if closing sockets will free it
\r
1354 printf("*** ThreadSocketHandler is stopped ***\n");
\r
1355 CRITICAL_BLOCK(cs_vNodes)
\r
1357 foreach(CNode* pnode, vNodes)
\r
1359 bool fGot = false;
\r
1360 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
\r
1361 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
\r
1365 printf("*** closing socket\n");
\r
1366 pnode->CloseSocketDisconnect();
\r
1373 if (GetTime() - nThreadSocketHandlerHeartbeat < 60)
\r
1376 // Hopefully it never comes to this.
\r
1377 // We know it'll always be hung in the recv or send call.
\r
1378 // cs_vRecv or cs_vSend may be left permanently unreleased,
\r
1379 // but we always only use TRY_CRITICAL_SECTION on them.
\r
1380 printf("*** Restarting ThreadSocketHandler ***\n");
\r
1381 TerminateThread(hThreadSocketHandler, 0);
\r
1383 CloseHandle(hThreadSocketHandler);
\r
1385 vnThreadsRunning[0] = 0;
\r
1388 hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
\r
1389 nThreadSocketHandlerHeartbeat = GetTime();
\r
1396 printf("StopNode()\n");
\r
1398 nTransactionsUpdated++;
\r
1399 int64 nStart = GetTime();
\r
1400 while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0)
\r
1402 if (GetTime() - nStart > 20)
\r
1406 if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
\r
1407 if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
\r
1408 if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
\r
1409 if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
\r
1410 if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
\r
1411 while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
\r
1427 foreach(CNode* pnode, vNodes)
\r
1428 if (pnode->hSocket != INVALID_SOCKET)
\r
1429 closesocket(pnode->hSocket);
\r
1430 if (hListenSocket != INVALID_SOCKET)
\r
1431 if (closesocket(hListenSocket) == SOCKET_ERROR)
\r
1432 printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
\r
1435 // Shutdown Windows Sockets
\r
1440 instance_of_cnetcleanup;
\r