Merge remote branch 'refs/remotes/svn/trunk' into svn
[bitcoinplatinum.git] / net.cpp
blob82b3ffb157f3179f9c9b1f2cd373e00fb866e7b4
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
5 #include "headers.h"
7 static const int MAX_OUTBOUND_CONNECTIONS = 8;
9 void ThreadMessageHandler2(void* parg);
10 void ThreadSocketHandler2(void* parg);
11 void ThreadOpenConnections2(void* parg);
12 bool OpenNetworkConnection(const CAddress& addrConnect);
19 // Global state variables
21 bool fClient = false;
22 uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
23 CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices);
24 CNode* pnodeLocalHost = NULL;
25 uint64 nLocalHostNonce = 0;
26 array<int, 10> vnThreadsRunning;
27 SOCKET hListenSocket = INVALID_SOCKET;
29 vector<CNode*> vNodes;
30 CCriticalSection cs_vNodes;
31 map<vector<unsigned char>, CAddress> mapAddresses;
32 CCriticalSection cs_mapAddresses;
33 map<CInv, CDataStream> mapRelay;
34 deque<pair<int64, CInv> > vRelayExpiration;
35 CCriticalSection cs_mapRelay;
36 map<CInv, int64> mapAlreadyAskedFor;
38 // Settings
39 int fUseProxy = false;
40 CAddress addrProxy("127.0.0.1:9050");
46 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
48 // Filter out duplicate requests
49 if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
50 return;
51 pindexLastGetBlocksBegin = pindexBegin;
52 hashLastGetBlocksEnd = hashEnd;
54 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
61 bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
63 hSocketRet = INVALID_SOCKET;
65 SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
66 if (hSocket == INVALID_SOCKET)
67 return false;
68 #ifdef BSD
69 int set = 1;
70 setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
71 #endif
73 bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168));
74 bool fProxy = (fUseProxy && fRoutable);
75 struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
77 if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
79 closesocket(hSocket);
80 return false;
83 if (fProxy)
85 printf("proxy connecting %s\n", addrConnect.ToStringLog().c_str());
86 char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
87 memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
88 memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
89 char* pszSocks4 = pszSocks4IP;
90 int nSize = sizeof(pszSocks4IP);
92 int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
93 if (ret != nSize)
95 closesocket(hSocket);
96 return error("Error sending to proxy");
98 char pchRet[8];
99 if (recv(hSocket, pchRet, 8, 0) != 8)
101 closesocket(hSocket);
102 return error("Error reading proxy response");
104 if (pchRet[1] != 0x5a)
106 closesocket(hSocket);
107 if (pchRet[1] != 0x5b)
108 printf("ERROR: Proxy returned error %d\n", pchRet[1]);
109 return false;
111 printf("proxy connected %s\n", addrConnect.ToStringLog().c_str());
114 hSocketRet = hSocket;
115 return true;
120 bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
122 SOCKET hSocket;
123 if (!ConnectSocket(addrConnect, hSocket))
124 return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());
126 send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);
128 string strLine;
129 while (RecvLine(hSocket, strLine))
131 if (strLine.empty())
133 loop
135 if (!RecvLine(hSocket, strLine))
137 closesocket(hSocket);
138 return false;
140 if (strLine.find(pszKeyword) != -1)
142 strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
143 break;
146 closesocket(hSocket);
147 if (strLine.find("<"))
148 strLine = strLine.substr(0, strLine.find("<"));
149 strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
150 while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
151 strLine.resize(strLine.size()-1);
152 CAddress addr(strLine.c_str());
153 printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
154 if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
155 return false;
156 ipRet = addr.ip;
157 return true;
160 closesocket(hSocket);
161 return error("GetMyExternalIP() : connection closed");
165 bool GetMyExternalIP(unsigned int& ipRet)
167 CAddress addrConnect;
168 const char* pszGet;
169 const char* pszKeyword;
171 if (fUseProxy)
172 return false;
174 for (int nLookup = 0; nLookup <= 1; nLookup++)
175 for (int nHost = 1; nHost <= 2; nHost++)
177 if (nHost == 1)
179 addrConnect = CAddress("70.86.96.218:80"); // www.ipaddressworld.com
181 if (nLookup == 1)
183 struct hostent* phostent = gethostbyname("www.ipaddressworld.com");
184 if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
185 addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80));
188 pszGet = "GET /ip.php HTTP/1.1\r\n"
189 "Host: www.ipaddressworld.com\r\n"
190 "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
191 "Connection: close\r\n"
192 "\r\n";
194 pszKeyword = "IP:";
196 else if (nHost == 2)
198 addrConnect = CAddress("208.78.68.70:80"); // checkip.dyndns.org
200 if (nLookup == 1)
202 struct hostent* phostent = gethostbyname("checkip.dyndns.org");
203 if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
204 addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80));
207 pszGet = "GET / HTTP/1.1\r\n"
208 "Host: checkip.dyndns.org\r\n"
209 "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
210 "Connection: close\r\n"
211 "\r\n";
213 pszKeyword = "Address:";
216 if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
217 return true;
220 return false;
227 bool AddAddress(CAddress addr)
229 if (!addr.IsRoutable())
230 return false;
231 if (addr.ip == addrLocalHost.ip)
232 return false;
233 CRITICAL_BLOCK(cs_mapAddresses)
235 map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
236 if (it == mapAddresses.end())
238 // New address
239 printf("AddAddress(%s)\n", addr.ToStringLog().c_str());
240 mapAddresses.insert(make_pair(addr.GetKey(), addr));
241 CAddrDB().WriteAddress(addr);
242 return true;
244 else
246 bool fUpdated = false;
247 CAddress& addrFound = (*it).second;
248 if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
250 // Services have been added
251 addrFound.nServices |= addr.nServices;
252 fUpdated = true;
254 bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
255 int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
256 if (addrFound.nTime < addr.nTime - nUpdateInterval)
258 // Periodically update most recently seen time
259 addrFound.nTime = addr.nTime;
260 fUpdated = true;
262 if (fUpdated)
263 CAddrDB().WriteAddress(addrFound);
266 return false;
269 void AddressCurrentlyConnected(const CAddress& addr)
271 CRITICAL_BLOCK(cs_mapAddresses)
273 // Only if it's been published already
274 map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
275 if (it != mapAddresses.end())
277 CAddress& addrFound = (*it).second;
278 int64 nUpdateInterval = 20 * 60;
279 if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
281 // Periodically update most recently seen time
282 addrFound.nTime = GetAdjustedTime();
283 CAddrDB addrdb;
284 addrdb.WriteAddress(addrFound);
294 void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
296 // If the dialog might get closed before the reply comes back,
297 // call this in the destructor so it doesn't get called after it's deleted.
298 CRITICAL_BLOCK(cs_vNodes)
300 foreach(CNode* pnode, vNodes)
302 CRITICAL_BLOCK(pnode->cs_mapRequests)
304 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
306 CRequestTracker& tracker = (*mi).second;
307 if (tracker.fn == fn && tracker.param1 == param1)
308 pnode->mapRequests.erase(mi++);
309 else
310 mi++;
324 // Subscription methods for the broadcast and subscription system.
325 // Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
327 // The subscription system uses a meet-in-the-middle strategy.
328 // With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
329 // subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
332 bool AnySubscribed(unsigned int nChannel)
334 if (pnodeLocalHost->IsSubscribed(nChannel))
335 return true;
336 CRITICAL_BLOCK(cs_vNodes)
337 foreach(CNode* pnode, vNodes)
338 if (pnode->IsSubscribed(nChannel))
339 return true;
340 return false;
343 bool CNode::IsSubscribed(unsigned int nChannel)
345 if (nChannel >= vfSubscribe.size())
346 return false;
347 return vfSubscribe[nChannel];
350 void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
352 if (nChannel >= vfSubscribe.size())
353 return;
355 if (!AnySubscribed(nChannel))
357 // Relay subscribe
358 CRITICAL_BLOCK(cs_vNodes)
359 foreach(CNode* pnode, vNodes)
360 if (pnode != this)
361 pnode->PushMessage("subscribe", nChannel, nHops);
364 vfSubscribe[nChannel] = true;
367 void CNode::CancelSubscribe(unsigned int nChannel)
369 if (nChannel >= vfSubscribe.size())
370 return;
372 // Prevent from relaying cancel if wasn't subscribed
373 if (!vfSubscribe[nChannel])
374 return;
375 vfSubscribe[nChannel] = false;
377 if (!AnySubscribed(nChannel))
379 // Relay subscription cancel
380 CRITICAL_BLOCK(cs_vNodes)
381 foreach(CNode* pnode, vNodes)
382 if (pnode != this)
383 pnode->PushMessage("sub-cancel", nChannel);
395 CNode* FindNode(unsigned int ip)
397 CRITICAL_BLOCK(cs_vNodes)
399 foreach(CNode* pnode, vNodes)
400 if (pnode->addr.ip == ip)
401 return (pnode);
403 return NULL;
406 CNode* FindNode(CAddress addr)
408 CRITICAL_BLOCK(cs_vNodes)
410 foreach(CNode* pnode, vNodes)
411 if (pnode->addr == addr)
412 return (pnode);
414 return NULL;
417 CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
419 if (addrConnect.ip == addrLocalHost.ip)
420 return NULL;
422 // Look for an existing connection
423 CNode* pnode = FindNode(addrConnect.ip);
424 if (pnode)
426 if (nTimeout != 0)
427 pnode->AddRef(nTimeout);
428 else
429 pnode->AddRef();
430 return pnode;
433 /// debug print
434 printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
435 addrConnect.ToStringLog().c_str(),
436 (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
437 (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
439 CRITICAL_BLOCK(cs_mapAddresses)
440 mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
442 // Connect
443 SOCKET hSocket;
444 if (ConnectSocket(addrConnect, hSocket))
446 /// debug print
447 printf("connected %s\n", addrConnect.ToStringLog().c_str());
449 // Set to nonblocking
450 #ifdef __WXMSW__
451 u_long nOne = 1;
452 if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
453 printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
454 #else
455 if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
456 printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno);
457 #endif
459 // Add node
460 CNode* pnode = new CNode(hSocket, addrConnect, false);
461 if (nTimeout != 0)
462 pnode->AddRef(nTimeout);
463 else
464 pnode->AddRef();
465 CRITICAL_BLOCK(cs_vNodes)
466 vNodes.push_back(pnode);
468 pnode->nTimeConnected = GetTime();
469 return pnode;
471 else
473 return NULL;
477 void CNode::CloseSocketDisconnect()
479 fDisconnect = true;
480 if (hSocket != INVALID_SOCKET)
482 if (fDebug)
483 printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
484 printf("disconnecting node %s\n", addr.ToStringLog().c_str());
485 closesocket(hSocket);
486 hSocket = INVALID_SOCKET;
490 void CNode::Cleanup()
492 // All of a nodes broadcasts and subscriptions are automatically torn down
493 // when it goes down, so a node has to stay up to keep its broadcast going.
495 // Cancel subscriptions
496 for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
497 if (vfSubscribe[nChannel])
498 CancelSubscribe(nChannel);
513 void ThreadSocketHandler(void* parg)
515 IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
518 vnThreadsRunning[0]++;
519 ThreadSocketHandler2(parg);
520 vnThreadsRunning[0]--;
522 catch (std::exception& e) {
523 vnThreadsRunning[0]--;
524 PrintException(&e, "ThreadSocketHandler()");
525 } catch (...) {
526 vnThreadsRunning[0]--;
527 throw; // support pthread_cancel()
529 printf("ThreadSocketHandler exiting\n");
532 void ThreadSocketHandler2(void* parg)
534 printf("ThreadSocketHandler started\n");
535 list<CNode*> vNodesDisconnected;
536 int nPrevNodeCount = 0;
538 loop
541 // Disconnect nodes
543 CRITICAL_BLOCK(cs_vNodes)
545 // Disconnect unused nodes
546 vector<CNode*> vNodesCopy = vNodes;
547 foreach(CNode* pnode, vNodesCopy)
549 if (pnode->fDisconnect ||
550 (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
552 // remove from vNodes
553 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
555 // close socket and cleanup
556 pnode->CloseSocketDisconnect();
557 pnode->Cleanup();
559 // hold in disconnected pool until all refs are released
560 pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
561 if (pnode->fNetworkNode || pnode->fInbound)
562 pnode->Release();
563 vNodesDisconnected.push_back(pnode);
567 // Delete disconnected nodes
568 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
569 foreach(CNode* pnode, vNodesDisconnectedCopy)
571 // wait until threads are done using it
572 if (pnode->GetRefCount() <= 0)
574 bool fDelete = false;
575 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
576 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
577 TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
578 TRY_CRITICAL_BLOCK(pnode->cs_inventory)
579 fDelete = true;
580 if (fDelete)
582 vNodesDisconnected.remove(pnode);
583 delete pnode;
588 if (vNodes.size() != nPrevNodeCount)
590 nPrevNodeCount = vNodes.size();
591 MainFrameRepaint();
596 // Find which sockets have data to receive
598 struct timeval timeout;
599 timeout.tv_sec = 0;
600 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
602 fd_set fdsetRecv;
603 fd_set fdsetSend;
604 fd_set fdsetError;
605 FD_ZERO(&fdsetRecv);
606 FD_ZERO(&fdsetSend);
607 FD_ZERO(&fdsetError);
608 SOCKET hSocketMax = 0;
609 FD_SET(hListenSocket, &fdsetRecv);
610 hSocketMax = max(hSocketMax, hListenSocket);
611 CRITICAL_BLOCK(cs_vNodes)
613 foreach(CNode* pnode, vNodes)
615 if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)
616 continue;
617 FD_SET(pnode->hSocket, &fdsetRecv);
618 FD_SET(pnode->hSocket, &fdsetError);
619 hSocketMax = max(hSocketMax, pnode->hSocket);
620 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
621 if (!pnode->vSend.empty())
622 FD_SET(pnode->hSocket, &fdsetSend);
626 vnThreadsRunning[0]--;
627 int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
628 vnThreadsRunning[0]++;
629 if (fShutdown)
630 return;
631 if (nSelect == SOCKET_ERROR)
633 int nErr = WSAGetLastError();
634 printf("socket select error %d\n", nErr);
635 for (int i = 0; i <= hSocketMax; i++)
636 FD_SET(i, &fdsetRecv);
637 FD_ZERO(&fdsetSend);
638 FD_ZERO(&fdsetError);
639 Sleep(timeout.tv_usec/1000);
644 // Accept new connections
646 if (FD_ISSET(hListenSocket, &fdsetRecv))
648 struct sockaddr_in sockaddr;
649 socklen_t len = sizeof(sockaddr);
650 SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
651 CAddress addr(sockaddr);
652 if (hSocket == INVALID_SOCKET)
654 if (WSAGetLastError() != WSAEWOULDBLOCK)
655 printf("socket error accept failed: %d\n", WSAGetLastError());
657 else if (mapArgs.count("-maxconnections") && (int)vNodes.size() >= atoi(mapArgs["-maxconnections"]) - MAX_OUTBOUND_CONNECTIONS)
659 closesocket(hSocket);
661 else
663 printf("accepted connection %s\n", addr.ToStringLog().c_str());
664 CNode* pnode = new CNode(hSocket, addr, true);
665 pnode->AddRef();
666 CRITICAL_BLOCK(cs_vNodes)
667 vNodes.push_back(pnode);
673 // Service each socket
675 vector<CNode*> vNodesCopy;
676 CRITICAL_BLOCK(cs_vNodes)
678 vNodesCopy = vNodes;
679 foreach(CNode* pnode, vNodesCopy)
680 pnode->AddRef();
682 foreach(CNode* pnode, vNodesCopy)
684 if (fShutdown)
685 return;
688 // Receive
690 if (pnode->hSocket == INVALID_SOCKET)
691 continue;
692 if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
694 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
696 CDataStream& vRecv = pnode->vRecv;
697 unsigned int nPos = vRecv.size();
699 // typical socket buffer is 8K-64K
700 char pchBuf[0x10000];
701 int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
702 if (nBytes > 0)
704 vRecv.resize(nPos + nBytes);
705 memcpy(&vRecv[nPos], pchBuf, nBytes);
706 pnode->nLastRecv = GetTime();
708 else if (nBytes == 0)
710 // socket closed gracefully
711 if (!pnode->fDisconnect)
712 printf("socket closed\n");
713 pnode->CloseSocketDisconnect();
715 else if (nBytes < 0)
717 // error
718 int nErr = WSAGetLastError();
719 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
721 if (!pnode->fDisconnect)
722 printf("socket recv error %d\n", nErr);
723 pnode->CloseSocketDisconnect();
730 // Send
732 if (pnode->hSocket == INVALID_SOCKET)
733 continue;
734 if (FD_ISSET(pnode->hSocket, &fdsetSend))
736 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
738 CDataStream& vSend = pnode->vSend;
739 if (!vSend.empty())
741 int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
742 if (nBytes > 0)
744 vSend.erase(vSend.begin(), vSend.begin() + nBytes);
745 pnode->nLastSend = GetTime();
747 else if (nBytes < 0)
749 // error
750 int nErr = WSAGetLastError();
751 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
753 printf("socket send error %d\n", nErr);
754 pnode->CloseSocketDisconnect();
762 // Inactivity checking
764 if (pnode->vSend.empty())
765 pnode->nLastSendEmpty = GetTime();
766 if (GetTime() - pnode->nTimeConnected > 60)
768 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
770 printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
771 pnode->fDisconnect = true;
773 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
775 printf("socket not sending\n");
776 pnode->fDisconnect = true;
778 else if (GetTime() - pnode->nLastRecv > 90*60)
780 printf("socket inactivity timeout\n");
781 pnode->fDisconnect = true;
785 CRITICAL_BLOCK(cs_vNodes)
787 foreach(CNode* pnode, vNodesCopy)
788 pnode->Release();
791 Sleep(10);
807 unsigned int pnSeed[] =
809 // 2010/06
810 0x35218252, 0x9c9c9618, 0xda6bacad, 0xb9aca862, 0x97c235c6,
811 0x146f9562, 0xb67b9e4b, 0x87cf4bc0, 0xb83945d0, 0x984333ad,
812 0xbbeec555, 0x6f0eb440, 0xe0005318, 0x7797e460, 0xddc60fcc,
813 0xb3bbd24a, 0x1ac85746, 0x641846a6, 0x85ee1155, 0xbb2e7a4c,
814 0x9cb8514b, 0xfc342648, 0x62958fae, 0xd0a8c87a, 0xa800795b,
815 0xda8c814e, 0x256a0c80, 0x3f23ec63, 0xd565df43, 0x997d9044,
816 0xaa121448, 0xbed8688e, 0x59d09a5e, 0xb2931243, 0x3730ba18,
817 0xdd3462d0, 0x4e4d1448, 0x171df645, 0x84ee1155,
818 0x248ac445, 0x0e634444, 0x0ded1b63, 0x30c01e60,
819 0xa2b9a094, 0x29e4fd43, 0x9ce61b4c, 0xdae09744,
821 // 2010/08
822 0x5ae6bf43, 0x460be257, 0x7245c0cf, 0x4e0f028d, 0x26501760, 0x38643255, 0x67094f4f, 0x480449b8,
823 0x16545143, 0x1f082e5a, 0xaa428018, 0xe411e793, 0x14c1f862, 0x2726105b, 0x9b33ea50, 0xeeef86ca,
824 0xe3210d44, 0x0dca8b63, 0x3f9dfb18, 0x860340ad, 0xf33ba17a, 0x9018375c, 0x1de4e353, 0x0fa52dcb,
825 0x89c4555b, 0x109cf37b, 0x28c55b40, 0x04c801ae, 0x275c1e80, 0x6f7f745d, 0x7a2a5653, 0xa28e26d8,
826 0xa4e65db2, 0x99a06580, 0xf253ba44, 0x82cf6ab8, 0x859c2e8e, 0xf71a815d, 0xc18f1454, 0x71c8a943,
827 0x90d24e18, 0x311789b2, 0x74aba645, 0xde0bbfc3, 0xad724fad, 0xbf1ae15e, 0xbaa6fb54, 0x06e4d145,
828 0x51528645, 0x72120cd4, 0xd4cfd145, 0x0a7afed8, 0x9b9a5fad, 0x9e9ff45e, 0x10128355, 0xd44e8646,
829 0x04a07b47, 0x5fc9d547, 0xe0491e45, 0xbac21b41, 0x7aa31bae, 0x10483c5f, 0x94a23055, 0x73d9dc47,
830 0x1a99c247, 0x822fe847, 0x7e57ba48, 0xb19ea843, 0xa60621b2, 0x778cf163, 0x125c6556, 0xf94ba44f,
831 0xa61a0948, 0x6c839e4b, 0x29af5348, 0x68d84845, 0x752b95c3, 0xcf0d4663, 0x08e11e56, 0x75109550,
832 0x5f24b94c, 0x42426d4d, 0xfbbc0a4c, 0x70a9a246, 0xda7837cb, 0xae2a986d, 0xe283c358, 0x0c7ca954,
833 0x8e9bde59, 0x61521760, 0x6884444c, 0xa194e548, 0x9b8809cc, 0x16e96a8f, 0x956ff859, 0xfad5e555,
834 0x0ea70c80, 0x5b4ce26d, 0x7984444c, 0x1080d24a, 0x22a686cf, 0x6bf8c2ad, 0xb0f7485f, 0x06b66e56,
835 0x668373bc, 0x75506279, 0x3868694e, 0x12a5954b, 0x3a8b62d1, 0xb74fcbad, 0xa7dc3360, 0xc070b359,
836 0xa2b87242, 0xc45cab7c, 0x69882050, 0x14a5464b, 0x386acad5, 0x80b85db2, 0x1f78a062, 0xc608c55b,
837 0x4257d543, 0x7636ad80, 0x4432d655, 0xb2114d4b, 0x32639bd9, 0xadd75db2, 0x9be5a362, 0x6831bc5e,
838 0xf7f77046, 0x8f35ba81, 0x09bb4e59, 0xd0fb6b4e, 0xc5daa445, 0x9c611618, 0x355dcc62, 0xf2cf435e,
839 0x31e72c46, 0xdd8a43ad, 0x171f9c5b, 0xb4c2e355, 0xbe8af945, 0x613d3942, 0xe6f9e863, 0x7a3d855f,
840 0xa66adc47, 0x261089b2, 0x5a27105b, 0x6c28105b, 0xdd247946, 0xe6c3a445, 0x43a1ec63, 0x99b4dd5f,
841 0xb6834347, 0x5e9649bc, 0xf9dd545d, 0x6ae4c15b, 0xa5318a47, 0x7984ec47, 0x93a73b63, 0x0c60195f,
842 0xa5c85e4b, 0xa0a36dc2, 0x0739a95e, 0x3d44c15b, 0xfb940f4b, 0xd67c9148, 0x614f9876, 0x0a241c5f,
843 0xad9da74c, 0x4459abc8, 0x12e71b5f, 0x1c534a5d, 0x8ff5fc50, 0x2ca8864b, 0xd894fd80, 0x82ab3160,
844 0x390d804e, 0x2cf310cc, 0x680dad80, 0x691be15e, 0x5a8f4652, 0xaad0784d, 0x0d2431ad,
849 void ThreadOpenConnections(void* parg)
851 IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
854 vnThreadsRunning[1]++;
855 ThreadOpenConnections2(parg);
856 vnThreadsRunning[1]--;
858 catch (std::exception& e) {
859 vnThreadsRunning[1]--;
860 PrintException(&e, "ThreadOpenConnections()");
861 } catch (...) {
862 vnThreadsRunning[1]--;
863 PrintException(NULL, "ThreadOpenConnections()");
865 printf("ThreadOpenConnections exiting\n");
868 void ThreadOpenConnections2(void* parg)
870 printf("ThreadOpenConnections started\n");
872 // Connect to specific addresses
873 if (mapArgs.count("-connect"))
875 for (int64 nLoop = 0;; nLoop++)
877 foreach(string strAddr, mapMultiArgs["-connect"])
879 CAddress addr(strAddr, NODE_NETWORK);
880 if (addr.IsValid())
881 OpenNetworkConnection(addr);
882 for (int i = 0; i < 10 && i < nLoop; i++)
884 Sleep(500);
885 if (fShutdown)
886 return;
892 // Connect to manually added nodes first
893 if (mapArgs.count("-addnode"))
895 foreach(string strAddr, mapMultiArgs["-addnode"])
897 CAddress addr(strAddr, NODE_NETWORK);
898 if (addr.IsValid())
900 OpenNetworkConnection(addr);
901 Sleep(500);
902 if (fShutdown)
903 return;
908 // Initiate network connections
909 int64 nStart = GetTime();
910 loop
912 // Limit outbound connections
913 vnThreadsRunning[1]--;
914 Sleep(500);
915 loop
917 int nOutbound = 0;
918 CRITICAL_BLOCK(cs_vNodes)
919 foreach(CNode* pnode, vNodes)
920 if (!pnode->fInbound)
921 nOutbound++;
922 int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
923 if (mapArgs.count("-maxconnections"))
924 nMaxOutboundConnections = min(nMaxOutboundConnections, atoi(mapArgs["-maxconnections"]));
925 if (nOutbound < nMaxOutboundConnections)
926 break;
927 Sleep(2000);
928 if (fShutdown)
929 return;
931 vnThreadsRunning[1]++;
932 if (fShutdown)
933 return;
935 CRITICAL_BLOCK(cs_mapAddresses)
937 // Add seed nodes if IRC isn't working
938 static bool fSeedUsed;
939 bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
940 if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR))
942 for (int i = 0; i < ARRAYLEN(pnSeed); i++)
944 // It'll only connect to one or two seed nodes because once it connects,
945 // it'll get a pile of addresses with newer timestamps.
946 CAddress addr;
947 addr.ip = pnSeed[i];
948 addr.nTime = 0;
949 AddAddress(addr);
951 fSeedUsed = true;
954 if (fSeedUsed && mapAddresses.size() > ARRAYLEN(pnSeed) + 100)
956 // Disconnect seed nodes
957 set<unsigned int> setSeed(pnSeed, pnSeed + ARRAYLEN(pnSeed));
958 static int64 nSeedDisconnected;
959 if (nSeedDisconnected == 0)
961 nSeedDisconnected = GetTime();
962 CRITICAL_BLOCK(cs_vNodes)
963 foreach(CNode* pnode, vNodes)
964 if (setSeed.count(pnode->addr.ip))
965 pnode->fDisconnect = true;
968 // Keep setting timestamps to 0 so they won't reconnect
969 if (GetTime() - nSeedDisconnected < 60 * 60)
971 foreach(PAIRTYPE(const vector<unsigned char>, CAddress)& item, mapAddresses)
973 if (setSeed.count(item.second.ip))
975 item.second.nTime = 0;
976 CAddrDB().WriteAddress(item.second);
985 // Choose an address to connect to based on most recently seen
987 CAddress addrConnect;
988 int64 nBest = INT64_MIN;
990 // Only connect to one address per a.b.?.? range.
991 // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
992 set<unsigned int> setConnected;
993 CRITICAL_BLOCK(cs_vNodes)
994 foreach(CNode* pnode, vNodes)
995 setConnected.insert(pnode->addr.ip & 0x0000ffff);
997 CRITICAL_BLOCK(cs_mapAddresses)
999 foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
1001 const CAddress& addr = item.second;
1002 if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
1003 continue;
1004 int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
1005 int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
1007 // Randomize the order in a deterministic way, putting the standard port first
1008 int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
1009 if (addr.port != DEFAULT_PORT)
1010 nRandomizer += 2 * 60 * 60;
1012 // Last seen Base retry frequency
1013 // <1 hour 10 min
1014 // 1 hour 1 hour
1015 // 4 hours 2 hours
1016 // 24 hours 5 hours
1017 // 48 hours 7 hours
1018 // 7 days 13 hours
1019 // 30 days 27 hours
1020 // 90 days 46 hours
1021 // 365 days 93 hours
1022 int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
1024 // Fast reconnect for one hour after last seen
1025 if (nSinceLastSeen < 60 * 60)
1026 nDelay = 10 * 60;
1028 // Limit retry frequency
1029 if (nSinceLastTry < nDelay)
1030 continue;
1032 // If we have IRC, we'll be notified when they first come online,
1033 // and again every 24 hours by the refresh broadcast.
1034 if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
1035 continue;
1037 // Only try the old stuff if we don't have enough connections
1038 if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
1039 continue;
1041 // If multiple addresses are ready, prioritize by time since
1042 // last seen and time since last tried.
1043 int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
1044 if (nScore > nBest)
1046 nBest = nScore;
1047 addrConnect = addr;
1052 if (addrConnect.IsValid())
1053 OpenNetworkConnection(addrConnect);
1057 bool OpenNetworkConnection(const CAddress& addrConnect)
1060 // Initiate outbound network connection
1062 if (fShutdown)
1063 return false;
1064 if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
1065 return false;
1067 vnThreadsRunning[1]--;
1068 CNode* pnode = ConnectNode(addrConnect);
1069 vnThreadsRunning[1]++;
1070 if (fShutdown)
1071 return false;
1072 if (!pnode)
1073 return false;
1074 pnode->fNetworkNode = true;
1076 if (addrLocalHost.IsRoutable() && !fUseProxy)
1078 // Advertise our address
1079 vector<CAddress> vAddr;
1080 vAddr.push_back(addrLocalHost);
1081 pnode->PushMessage("addr", vAddr);
1084 // Get as many addresses as we can
1085 pnode->PushMessage("getaddr");
1086 pnode->fGetAddr = true; // don't relay the results of the getaddr
1088 ////// should the one on the receiving end do this too?
1089 // Subscribe our local subscription list
1090 const unsigned int nHops = 0;
1091 for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++)
1092 if (pnodeLocalHost->vfSubscribe[nChannel])
1093 pnode->PushMessage("subscribe", nChannel, nHops);
1095 return true;
1105 void ThreadMessageHandler(void* parg)
1107 IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
1110 vnThreadsRunning[2]++;
1111 ThreadMessageHandler2(parg);
1112 vnThreadsRunning[2]--;
1114 catch (std::exception& e) {
1115 vnThreadsRunning[2]--;
1116 PrintException(&e, "ThreadMessageHandler()");
1117 } catch (...) {
1118 vnThreadsRunning[2]--;
1119 PrintException(NULL, "ThreadMessageHandler()");
1121 printf("ThreadMessageHandler exiting\n");
1124 void ThreadMessageHandler2(void* parg)
1126 printf("ThreadMessageHandler started\n");
1127 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1128 while (!fShutdown)
1130 vector<CNode*> vNodesCopy;
1131 CRITICAL_BLOCK(cs_vNodes)
1133 vNodesCopy = vNodes;
1134 foreach(CNode* pnode, vNodesCopy)
1135 pnode->AddRef();
1138 // Poll the connected nodes for messages
1139 CNode* pnodeTrickle = NULL;
1140 if (!vNodesCopy.empty())
1141 pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
1142 foreach(CNode* pnode, vNodesCopy)
1144 // Receive messages
1145 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
1146 ProcessMessages(pnode);
1147 if (fShutdown)
1148 return;
1150 // Send messages
1151 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
1152 SendMessages(pnode, pnode == pnodeTrickle);
1153 if (fShutdown)
1154 return;
1157 CRITICAL_BLOCK(cs_vNodes)
1159 foreach(CNode* pnode, vNodesCopy)
1160 pnode->Release();
1163 // Wait and allow messages to bunch up.
1164 // Reduce vnThreadsRunning so StopNode has permission to exit while
1165 // we're sleeping, but we must always check fShutdown after doing this.
1166 vnThreadsRunning[2]--;
1167 Sleep(100);
1168 if (fRequestShutdown)
1169 Shutdown(NULL);
1170 vnThreadsRunning[2]++;
1171 if (fShutdown)
1172 return;
1184 bool BindListenPort(string& strError)
1186 strError = "";
1187 int nOne = 1;
1189 #ifdef __WXMSW__
1190 // Initialize Windows Sockets
1191 WSADATA wsadata;
1192 int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
1193 if (ret != NO_ERROR)
1195 strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
1196 printf("%s\n", strError.c_str());
1197 return false;
1199 #endif
1201 // Create socket for listening for incoming connections
1202 hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1203 if (hListenSocket == INVALID_SOCKET)
1205 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
1206 printf("%s\n", strError.c_str());
1207 return false;
1210 #ifdef BSD
1211 // Different way of disabling SIGPIPE on BSD
1212 setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
1213 #endif
1215 #ifndef __WXMSW__
1216 // Allow binding if the port is still in TIME_WAIT state after
1217 // the program was closed and restarted. Not an issue on windows.
1218 setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
1219 #endif
1221 #ifdef __WXMSW__
1222 // Set to nonblocking, incoming connections will also inherit this
1223 if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
1224 #else
1225 if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
1226 #endif
1228 strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
1229 printf("%s\n", strError.c_str());
1230 return false;
1233 // The sockaddr_in structure specifies the address family,
1234 // IP address, and port for the socket that is being bound
1235 struct sockaddr_in sockaddr;
1236 memset(&sockaddr, 0, sizeof(sockaddr));
1237 sockaddr.sin_family = AF_INET;
1238 sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
1239 sockaddr.sin_port = DEFAULT_PORT;
1240 if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
1242 int nErr = WSAGetLastError();
1243 if (nErr == WSAEADDRINUSE)
1244 strError = strprintf("Unable to bind to port %d on this computer. Bitcoin is probably already running.", ntohs(sockaddr.sin_port));
1245 else
1246 strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
1247 printf("%s\n", strError.c_str());
1248 return false;
1250 printf("Bound to port %d\n", ntohs(sockaddr.sin_port));
1252 // Listen for incoming connections
1253 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1255 strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
1256 printf("%s\n", strError.c_str());
1257 return false;
1260 return true;
1263 void StartNode(void* parg)
1265 if (pnodeLocalHost == NULL)
1266 pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));
1268 #ifdef __WXMSW__
1269 // Get local host ip
1270 char pszHostName[1000] = "";
1271 if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1273 struct hostent* phostent = gethostbyname(pszHostName);
1274 if (phostent)
1276 // Take the first IP that isn't loopback 127.x.x.x
1277 for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
1278 printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());
1279 for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
1281 CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);
1282 if (addr.IsValid() && addr.GetByte(3) != 127)
1284 addrLocalHost = addr;
1285 break;
1290 #else
1291 // Get local host ip
1292 struct ifaddrs* myaddrs;
1293 if (getifaddrs(&myaddrs) == 0)
1295 for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1297 if (ifa->ifa_addr == NULL) continue;
1298 if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1299 if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1300 if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
1301 char pszIP[100];
1302 if (ifa->ifa_addr->sa_family == AF_INET)
1304 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
1305 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
1306 printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
1308 // Take the first IP that isn't loopback 127.x.x.x
1309 CAddress addr(*(unsigned int*)&s4->sin_addr, DEFAULT_PORT, nLocalServices);
1310 if (addr.IsValid() && addr.GetByte(3) != 127)
1312 addrLocalHost = addr;
1313 break;
1316 else if (ifa->ifa_addr->sa_family == AF_INET6)
1318 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
1319 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
1320 printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
1323 freeifaddrs(myaddrs);
1325 #endif
1326 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
1328 // Get our external IP address for incoming connections
1329 if (fUseProxy)
1331 // Proxies can't take incoming connections
1332 addrLocalHost.ip = CAddress("0.0.0.0").ip;
1333 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
1335 else
1337 if (addrIncoming.IsValid())
1338 addrLocalHost.ip = addrIncoming.ip;
1340 if (GetMyExternalIP(addrLocalHost.ip))
1342 addrIncoming = addrLocalHost;
1343 CWalletDB().WriteSetting("addrIncoming", addrIncoming);
1344 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
1349 // Start threads
1352 // Get addresses from IRC and advertise ours
1353 if (!CreateThread(ThreadIRCSeed, NULL))
1354 printf("Error: CreateThread(ThreadIRCSeed) failed\n");
1356 // Send and receive from sockets, accept connections
1357 pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
1359 // Initiate outbound connections
1360 if (!CreateThread(ThreadOpenConnections, NULL))
1361 printf("Error: CreateThread(ThreadOpenConnections) failed\n");
1363 // Process messages
1364 if (!CreateThread(ThreadMessageHandler, NULL))
1365 printf("Error: CreateThread(ThreadMessageHandler) failed\n");
1367 // Generate coins in the background
1368 GenerateBitcoins(fGenerateBitcoins);
1371 bool StopNode()
1373 printf("StopNode()\n");
1374 fShutdown = true;
1375 nTransactionsUpdated++;
1376 int64 nStart = GetTime();
1377 while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0)
1379 if (GetTime() - nStart > 20)
1380 break;
1381 Sleep(20);
1383 if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
1384 if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
1385 if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
1386 if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
1387 if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
1388 while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
1389 Sleep(20);
1390 Sleep(50);
1392 return true;
1395 class CNetCleanup
1397 public:
1398 CNetCleanup()
1401 ~CNetCleanup()
1403 // Close sockets
1404 foreach(CNode* pnode, vNodes)
1405 if (pnode->hSocket != INVALID_SOCKET)
1406 closesocket(pnode->hSocket);
1407 if (hListenSocket != INVALID_SOCKET)
1408 if (closesocket(hListenSocket) == SOCKET_ERROR)
1409 printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
1411 #ifdef __WXMSW__
1412 // Shutdown Windows Sockets
1413 WSACleanup();
1414 #endif
1417 instance_of_cnetcleanup;