1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
11 #include "ui_interface.h"
17 static const int MAX_OUTBOUND_CONNECTIONS = 16;
19 void ThreadMessageHandler2(void* parg);
20 void ThreadSocketHandler2(void* parg);
21 void ThreadOpenConnections2(void* parg);
22 void ThreadOpenAddedConnections2(void* parg);
23 void ThreadDNSAddressSeed2(void* parg);
25 // Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
26 // Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
28 #ifndef PROTECTION_LEVEL_UNRESTRICTED
29 #define PROTECTION_LEVEL_UNRESTRICTED 10
31 #ifndef IPV6_PROTECTION_LEVEL
32 #define IPV6_PROTECTION_LEVEL 23
37 // Global state variables
40 bool fDiscover = true;
41 uint64_t nLocalServices = (fClient ? 0 : NODE_NETWORK);
42 CCriticalSection cs_mapLocalHost;
43 map<CNetAddr, LocalServiceInfo> mapLocalHost;
44 static bool vfReachable[NET_MAX] = {};
45 static bool vfLimited[NET_MAX] = {};
46 static CNode* pnodeLocalHost = NULL;
47 static CNode* pnodeSync = NULL;
48 CAddress addrSeenByPeer(CService("0.0.0.0", nPortZero), nLocalServices);
49 uint64_t nLocalHostNonce = 0;
50 array<int, THREAD_MAX> vnThreadsRunning;
51 static vector<SOCKET> vhListenSocket;
54 vector<CNode*> vNodes;
55 CCriticalSection cs_vNodes;
56 map<CInv, CDataStream> mapRelay;
57 deque<pair<int64_t, CInv> > vRelayExpiration;
58 CCriticalSection cs_mapRelay;
59 map<CInv, int64_t> mapAlreadyAskedFor;
61 static deque<string> vOneShots;
62 CCriticalSection cs_vOneShots;
64 set<CNetAddr> setservAddNodeAddresses;
65 CCriticalSection cs_setservAddNodeAddresses;
67 vector<string> vAddedNodes;
68 CCriticalSection cs_vAddedNodes;
70 static CSemaphore *semOutbound = NULL;
72 void AddOneShot(string strDest)
75 vOneShots.push_back(strDest);
78 uint16_t GetListenPort()
80 return static_cast<uint16_t>(GetArg("-port", GetDefaultPort()));
83 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
85 // Filter out duplicate requests
86 if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
88 pindexLastGetBlocksBegin = pindexBegin;
89 hashLastGetBlocksEnd = hashEnd;
91 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
94 // find 'best' local address for a particular peer
95 bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
101 int nBestReachability = -1;
103 LOCK(cs_mapLocalHost);
104 for (auto it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
106 int nScore = (*it).second.nScore;
107 int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
108 if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
110 addr = CService((*it).first, (*it).second.nPort);
111 nBestReachability = nReachability;
116 return nBestScore >= 0;
119 // get best local address for a particular peer as a CAddress
120 CAddress GetLocalAddress(const CNetAddr *paddrPeer)
122 CAddress ret(CService("0.0.0.0", nPortZero), 0);
124 if (GetLocal(addr, paddrPeer))
126 ret = CAddress(addr);
127 ret.nServices = nLocalServices;
128 ret.nTime = GetAdjustedTime();
133 bool RecvLine(SOCKET hSocket, string& strLine)
139 int nBytes = recv(hSocket, &c, 1, 0);
147 if (strLine.size() >= 9000)
150 else if (nBytes <= 0)
156 int nErr = WSAGetLastError();
157 if (nErr == WSAEMSGSIZE)
159 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
165 if (!strLine.empty())
170 printf("socket closed\n");
176 int nErr = WSAGetLastError();
177 printf("recv failed: %s\n", NetworkErrorString(nErr).c_str());
184 // used when scores of local addresses may have changed
185 // pushes better local address to peers
186 void static AdvertizeLocal()
189 for(CNode* pnode : vNodes)
191 if (pnode->fSuccessfullyConnected)
193 auto addrLocal = GetLocalAddress(&pnode->addr);
194 if (addrLocal.IsRoutable() && (CService)addrLocal != pnode->addrLocal)
196 pnode->PushAddress(addrLocal);
197 pnode->addrLocal = addrLocal;
203 void SetReachable(enum Network net, bool fFlag)
205 LOCK(cs_mapLocalHost);
206 vfReachable[net] = fFlag;
207 if (net == NET_IPV6 && fFlag)
208 vfReachable[NET_IPV4] = true;
211 int GetnScore(const CService& addr)
213 LOCK(cs_mapLocalHost);
214 if (mapLocalHost.count(addr) == LOCAL_NONE)
216 return mapLocalHost[addr].nScore;
220 // Is our peer's addrLocal potentially useful as an external IP source?
221 bool IsPeerAddrLocalGood(CNode *pnode)
223 return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() &&
224 !IsLimited(pnode->addrLocal.GetNetwork());
227 // pushes our own address to a peer
228 void AdvertiseLocal(CNode *pnode)
230 if (!fNoListen && pnode->fSuccessfullyConnected)
232 auto addrLocal = GetLocalAddress(&pnode->addr);
233 // If discovery is enabled, sometimes give our peer the address it
234 // tells us that it sees us as in case it has a better idea of our
235 // address than we do.
236 if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
237 GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
239 addrLocal.SetIP(pnode->addrLocal);
241 if (addrLocal.IsRoutable())
243 printf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString().c_str());
244 pnode->PushAddress(addrLocal);
249 // learn a new local address
250 bool AddLocal(const CService& addr, int nScore)
252 if (!addr.IsRoutable())
255 if (!fDiscover && nScore < LOCAL_MANUAL)
261 printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore);
264 LOCK(cs_mapLocalHost);
265 bool fAlready = mapLocalHost.count(addr) > 0;
266 LocalServiceInfo &info = mapLocalHost[addr];
267 if (!fAlready || nScore >= info.nScore) {
268 info.nScore = nScore + (fAlready ? 1 : 0);
269 info.nPort = addr.GetPort();
271 SetReachable(addr.GetNetwork());
279 bool AddLocal(const CNetAddr &addr, int nScore)
281 return AddLocal(CService(addr, GetListenPort()), nScore);
284 /** Make a particular network entirely off-limits (no automatic connects to it) */
285 void SetLimited(enum Network net, bool fLimited)
287 if (net == NET_UNROUTABLE)
289 LOCK(cs_mapLocalHost);
290 vfLimited[net] = fLimited;
293 bool IsLimited(enum Network net)
295 LOCK(cs_mapLocalHost);
296 return vfLimited[net];
299 bool IsLimited(const CNetAddr &addr)
301 return IsLimited(addr.GetNetwork());
304 /** vote for a local address */
305 bool SeenLocal(const CService& addr)
308 LOCK(cs_mapLocalHost);
309 if (mapLocalHost.count(addr) == 0)
311 mapLocalHost[addr].nScore++;
319 /** check whether a given address is potentially local */
320 bool IsLocal(const CService& addr)
322 LOCK(cs_mapLocalHost);
323 return mapLocalHost.count(addr) > 0;
326 /** check whether a given address is in a network we can probably connect to */
327 bool IsReachable(const CNetAddr& addr)
329 LOCK(cs_mapLocalHost);
330 enum Network net = addr.GetNetwork();
331 return vfReachable[net] && !vfLimited[net];
334 extern int GetExternalIPbySTUN(uint64_t rnd, struct sockaddr_in *mapped, const char **srv);
336 // We now get our external IP from the IRC server first and only use this as a backup
337 bool GetMyExternalIP(CNetAddr& ipRet)
339 struct sockaddr_in mapped = {};
340 auto rnd = GetRand(numeric_limits<uint64_t>::max());
342 int rc = GetExternalIPbySTUN(rnd, &mapped, &srv);
344 ipRet = CNetAddr(mapped.sin_addr);
346 printf("GetExternalIPbySTUN(%" PRIu64 ") returned %s in attempt %d; Server=%s\n", rnd, ipRet.ToStringIP().c_str(), rc, srv);
353 void ThreadGetMyExternalIP(void* parg)
355 // Make this thread recognisable as the external IP detection thread
356 RenameThread("novacoin-ext-ip");
358 CNetAddr addrLocalHost;
359 if (GetMyExternalIP(addrLocalHost))
361 printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
362 AddLocal(addrLocalHost, LOCAL_HTTP);
366 void AddressCurrentlyConnected(const CService& addr)
368 addrman.Connected(addr);
374 uint64_t CNode::nTotalBytesRecv = 0;
375 uint64_t CNode::nTotalBytesSent = 0;
376 CCriticalSection CNode::cs_totalBytesRecv;
377 CCriticalSection CNode::cs_totalBytesSent;
379 CNode* FindNode(const CNetAddr& ip)
382 for(CNode* pnode : vNodes)
383 if ((CNetAddr)pnode->addr == ip)
388 CNode* FindNode(string addrName)
391 for(CNode* pnode : vNodes)
392 if (pnode->addrName == addrName)
397 CNode* FindNode(const CService& addr)
400 for(CNode* pnode : vNodes)
401 if ((CService)pnode->addr == addr)
406 CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64_t nTimeout)
408 if (pszDest == NULL) {
409 if (IsLocal(addrConnect))
412 // Look for an existing connection
413 CNode* pnode = FindNode((CService)addrConnect);
417 pnode->AddRef(nTimeout);
426 printf("trying connection %s lastseen=%.1fhrs\n",
427 pszDest ? pszDest : addrConnect.ToString().c_str(),
428 pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
432 if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, GetDefaultPort()) : ConnectSocket(addrConnect, hSocket))
434 addrman.Attempt(addrConnect);
437 printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str());
439 // Set to non-blocking
442 if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
443 printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %s\n", NetworkErrorString(WSAGetLastError()).c_str());
445 if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
446 printf("ConnectSocket() : fcntl non-blocking setting failed, error %s\n", NetworkErrorString(errno).c_str());
450 CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
452 pnode->AddRef(nTimeout);
458 vNodes.push_back(pnode);
461 pnode->nTimeConnected = GetTime();
470 CNode::CNode(SOCKET hSocketIn, CAddress addrIn, string addrNameIn, bool fInboundIn) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION)
478 nLastSendEmpty = GetTime();
479 nTimeConnected = GetTime();
481 nMessageStart = numeric_limits<uint32_t>::max();
483 addrName = addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn;
487 fClient = false; // set by version message
488 fInbound = fInboundIn;
489 fNetworkNode = false;
490 fSuccessfullyConnected = false;
495 pindexLastGetBlocksBegin = 0;
496 hashLastGetBlocksEnd = 0;
497 nStartingHeight = -1;
498 nNextLocalAddrSend = 0;
504 hashCheckpointKnown = 0;
505 setInventoryKnown.max_size((size_t)SendBufferSize() / 1000);
507 // Be shy and don't send version until we hear
508 if (hSocket != INVALID_SOCKET && !fInbound)
514 if (hSocket != INVALID_SOCKET)
516 CloseSocket(hSocket);
520 int CNode::GetRefCount()
522 return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
525 CNode* CNode::AddRef(int64_t nTimeout)
528 nReleaseTime = max(nReleaseTime, GetTime() + nTimeout);
534 void CNode::Release()
539 void CNode::AddAddressKnown(const CAddress& addr)
541 setAddrKnown.insert(addr);
544 void CNode::PushAddress(const CAddress& addr)
546 // Known checking here is only to save space from duplicates.
547 // SendMessages will filter it again for knowns that were added
548 // after addresses were pushed.
549 if (addr.IsValid() && !setAddrKnown.count(addr))
550 vAddrToSend.push_back(addr);
553 void CNode::AddInventoryKnown(const CInv& inv)
557 setInventoryKnown.insert(inv);
561 void CNode::PushInventory(const CInv& inv)
565 if (!setInventoryKnown.count(inv))
566 vInventoryToSend.push_back(inv);
570 void CNode::AskFor(const CInv& inv)
572 // We're using mapAskFor as a priority queue,
573 // the key is the earliest time the request can be sent
574 int64_t& nRequestTime = mapAlreadyAskedFor[inv];
576 printf("askfor %s %" PRId64 " (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str());
578 // Make sure not to reuse time indexes to keep things in the same order
579 int64_t nNow = (GetTime() - 1) * 1000000;
580 static int64_t nLastTime;
582 nNow = max(nNow, nLastTime);
585 // Each retry is 2 minutes after the last
586 nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow);
587 mapAskFor.insert({ nRequestTime, inv });
590 void CNode::BeginMessage(const char* pszCommand)
592 ENTER_CRITICAL_SECTION(cs_vSend);
593 if (nHeaderStart != -1)
595 nHeaderStart = (int32_t)vSend.size();
596 vSend << CMessageHeader(pszCommand, 0);
597 nMessageStart = (uint32_t)vSend.size();
599 printf("sending: %s ", pszCommand);
602 void CNode::AbortMessage()
604 if (nHeaderStart < 0)
606 vSend.resize(nHeaderStart);
608 nMessageStart = numeric_limits<uint32_t>::max();
609 LEAVE_CRITICAL_SECTION(cs_vSend);
612 printf("(aborted)\n");
615 void CNode::EndMessage()
617 if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
619 printf("dropmessages DROPPING SEND MESSAGE\n");
624 if (nHeaderStart < 0)
628 uint32_t nSize = (uint32_t) vSend.size() - nMessageStart;
629 memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::MESSAGE_SIZE_OFFSET, &nSize, sizeof(nSize));
632 auto hash = Hash(vSend.begin() + nMessageStart, vSend.end());
633 uint32_t nChecksum = 0;
634 memcpy(&nChecksum, &hash, sizeof(nChecksum));
635 assert(nMessageStart - nHeaderStart >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
636 memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::CHECKSUM_OFFSET, &nChecksum, sizeof(nChecksum));
639 printf("(%d bytes)\n", nSize);
643 nMessageStart = numeric_limits<uint32_t>::max();
644 LEAVE_CRITICAL_SECTION(cs_vSend);
647 void CNode::EndMessageAbortIfEmpty()
649 if (nHeaderStart < 0)
651 int nSize = (int) vSend.size() - nMessageStart;
658 void CNode::CloseSocketDisconnect()
661 if (hSocket != INVALID_SOCKET)
663 printf("disconnecting node %s\n", addrName.c_str());
664 CloseSocket(hSocket);
668 // in case this fails, we'll empty the recv buffer when the CNode is deleted
669 TRY_LOCK(cs_vRecv, lockRecv);
673 // if this was the sync node, we'll need a new one
674 if (this == pnodeSync)
678 void CNode::Cleanup()
683 void CNode::PushVersion()
685 auto nTime = GetAdjustedTime();
686 CAddress addrYou, addrMe;
688 bool fHidden = false;
690 if (mapArgs.count("-torname")) {
691 // Our hidden service address
692 CService addrTorName(mapArgs["-torname"], GetListenPort());
694 if (addrTorName.IsValid()) {
696 addrMe = CAddress(addrTorName);
703 addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", nPortZero)));
704 addrMe = GetLocalAddress(&addr);
707 RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
708 printf("send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString().c_str(), addrYou.ToString().c_str(), addr.ToString().c_str());
709 PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
710 nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, vector<string>()), nBestHeight);
717 map<CNetAddr, int64_t> CNode::setBanned;
718 CCriticalSection CNode::cs_setBanned;
720 void CNode::ClearBanned()
725 bool CNode::IsBanned(const CNetAddr& ip)
727 bool fResult = false;
730 auto i = setBanned.find(ip);
731 if (i != setBanned.end())
733 auto t = (*i).second;
741 bool CNode::Misbehaving(int howmuch)
745 printf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch);
749 nMisbehavior += howmuch;
750 if (nMisbehavior >= GetArgInt("-banscore", 100))
752 auto banTime = GetTime()+GetArg("-bantime", nOneDay); // Default 24-hour ban
753 printf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
756 if (setBanned[addr] < banTime)
757 setBanned[addr] = banTime;
759 CloseSocketDisconnect();
762 printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
767 #define X(name) stats.name = name
768 void CNode::copyStats(CNodeStats &stats)
783 stats.fSyncNode = (this == pnodeSync);
788 void ThreadSocketHandler(void* parg)
790 // Make this thread recognisable as the networking thread
791 RenameThread("novacoin-net");
795 vnThreadsRunning[THREAD_SOCKETHANDLER]++;
796 ThreadSocketHandler2(parg);
797 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
799 catch (exception& e) {
800 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
801 PrintException(&e, "ThreadSocketHandler()");
803 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
804 throw; // support pthread_cancel()
806 printf("ThreadSocketHandler exited\n");
809 static list<CNode*> vNodesDisconnected;
811 void ThreadSocketHandler2(void* parg)
813 printf("ThreadSocketHandler started\n");
814 size_t nPrevNodeCount = 0;
822 // Disconnect unused nodes
823 vector<CNode*> vNodesCopy = vNodes;
824 for(CNode* pnode : vNodesCopy)
826 if (pnode->fDisconnect ||
827 (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
829 // remove from vNodes
830 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
832 // release outbound grant (if any)
833 pnode->grantOutbound.Release();
835 // close socket and cleanup
836 pnode->CloseSocketDisconnect();
839 // hold in disconnected pool until all refs are released
840 pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
841 if (pnode->fNetworkNode || pnode->fInbound)
843 vNodesDisconnected.push_back(pnode);
847 // Delete disconnected nodes
848 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
849 for(CNode* pnode : vNodesDisconnectedCopy)
851 // wait until threads are done using it
852 if (pnode->GetRefCount() <= 0)
854 bool fDelete = false;
856 TRY_LOCK(pnode->cs_vSend, lockSend);
859 TRY_LOCK(pnode->cs_vRecv, lockRecv);
862 TRY_LOCK(pnode->cs_mapRequests, lockReq);
865 TRY_LOCK(pnode->cs_inventory, lockInv);
874 vNodesDisconnected.remove(pnode);
880 if (vNodes.size() != nPrevNodeCount)
882 nPrevNodeCount = vNodes.size();
883 uiInterface.NotifyNumConnectionsChanged(vNodes.size());
888 // Find which sockets have data to receive
890 struct timeval timeout;
892 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
899 FD_ZERO(&fdsetError);
900 SOCKET hSocketMax = 0;
901 bool have_fds = false;
903 for(SOCKET hListenSocket : vhListenSocket) {
904 FD_SET(hListenSocket, &fdsetRecv);
905 hSocketMax = max(hSocketMax, hListenSocket);
910 for(CNode* pnode : vNodes)
912 if (pnode->hSocket == INVALID_SOCKET)
914 FD_SET(pnode->hSocket, &fdsetRecv);
915 FD_SET(pnode->hSocket, &fdsetError);
916 hSocketMax = max(hSocketMax, pnode->hSocket);
919 TRY_LOCK(pnode->cs_vSend, lockSend);
920 if (lockSend && !pnode->vSend.empty())
921 FD_SET(pnode->hSocket, &fdsetSend);
926 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
927 int nSelect = select(have_fds ? hSocketMax + 1 : 0,
928 &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
929 vnThreadsRunning[THREAD_SOCKETHANDLER]++;
932 if (nSelect == SOCKET_ERROR)
936 int nErr = WSAGetLastError();
937 printf("socket select error %s\n", NetworkErrorString(nErr).c_str());
938 for (unsigned int i = 0; i <= hSocketMax; i++)
939 FD_SET(i, &fdsetRecv);
942 FD_ZERO(&fdsetError);
943 Sleep(timeout.tv_usec/1000);
948 // Accept new connections
950 for(SOCKET hListenSocket : vhListenSocket)
951 if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
953 struct sockaddr_storage sockaddr;
954 socklen_t len = sizeof(sockaddr);
955 SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
959 if (hSocket != INVALID_SOCKET)
960 if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
961 printf("Warning: Unknown socket family\n");
965 for(CNode* pnode : vNodes)
970 if (hSocket == INVALID_SOCKET)
972 int nErr = WSAGetLastError();
973 if (nErr != WSAEWOULDBLOCK)
974 printf("socket error accept failed: %s\n", NetworkErrorString(nErr).c_str());
976 else if (nInbound >= GetArgInt("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
978 printf("connection from %s dropped (overall limit)\n", addr.ToString().c_str());
979 CloseSocket(hSocket);
981 else if (CNode::IsBanned(addr))
983 printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
984 CloseSocket(hSocket);
988 printf("accepted connection %s\n", addr.ToString().c_str());
989 CNode* pnode = new CNode(hSocket, addr, "", true);
993 vNodes.push_back(pnode);
1000 // Service each socket
1002 vector<CNode*> vNodesCopy;
1005 vNodesCopy = vNodes;
1006 for(CNode* pnode : vNodesCopy)
1009 for(CNode* pnode : vNodesCopy)
1017 if (pnode->hSocket == INVALID_SOCKET)
1019 if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
1021 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1024 CDataStream& vRecv = pnode->vRecv;
1025 uint64_t nPos = vRecv.size();
1027 if (nPos > ReceiveBufferSize()) {
1028 if (!pnode->fDisconnect)
1029 printf("socket recv flood control disconnect (%" PRIszu " bytes)\n", vRecv.size());
1030 pnode->CloseSocketDisconnect();
1033 // typical socket buffer is 8K-64K
1034 char pchBuf[0x10000];
1035 int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
1038 vRecv.resize(nPos + nBytes);
1039 memcpy(&vRecv[nPos], pchBuf, nBytes);
1040 pnode->nLastRecv = GetTime();
1041 pnode->nRecvBytes += nBytes;
1042 pnode->RecordBytesRecv(nBytes);
1044 else if (nBytes == 0)
1046 // socket closed gracefully
1047 if (!pnode->fDisconnect)
1048 printf("socket closed\n");
1049 pnode->CloseSocketDisconnect();
1051 else if (nBytes < 0)
1054 int nErr = WSAGetLastError();
1055 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
1057 if (!pnode->fDisconnect)
1058 printf("socket recv error %s\n", NetworkErrorString(nErr).c_str());
1059 pnode->CloseSocketDisconnect();
1069 if (pnode->hSocket == INVALID_SOCKET)
1071 if (FD_ISSET(pnode->hSocket, &fdsetSend))
1073 TRY_LOCK(pnode->cs_vSend, lockSend);
1076 CDataStream& vSend = pnode->vSend;
1079 int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
1082 vSend.erase(vSend.begin(), vSend.begin() + nBytes);
1083 pnode->nLastSend = GetTime();
1084 pnode->nSendBytes += nBytes;
1085 pnode->RecordBytesSent(nBytes);
1087 else if (nBytes < 0)
1090 int nErr = WSAGetLastError();
1091 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
1093 printf("socket send error %s\n", NetworkErrorString(nErr).c_str());
1094 pnode->CloseSocketDisconnect();
1102 // Inactivity checking
1104 if (pnode->vSend.empty())
1105 pnode->nLastSendEmpty = GetTime();
1106 if (GetTime() - pnode->nTimeConnected > 60)
1108 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
1110 printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
1111 pnode->fDisconnect = true;
1113 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
1115 printf("socket not sending\n");
1116 pnode->fDisconnect = true;
1118 else if (GetTime() - pnode->nLastRecv > 90*60)
1120 printf("socket inactivity timeout\n");
1121 pnode->fDisconnect = true;
1127 for(CNode* pnode : vNodesCopy)
1135 void ThreadDNSAddressSeed(void* parg)
1137 // Make this thread recognisable as the DNS seeding thread
1138 RenameThread("novacoin-dnsseed");
1142 vnThreadsRunning[THREAD_DNSSEED]++;
1143 ThreadDNSAddressSeed2(parg);
1144 vnThreadsRunning[THREAD_DNSSEED]--;
1146 catch (exception& e) {
1147 vnThreadsRunning[THREAD_DNSSEED]--;
1148 PrintException(&e, "ThreadDNSAddressSeed()");
1150 vnThreadsRunning[THREAD_DNSSEED]--;
1151 throw; // support pthread_cancel()
1153 printf("ThreadDNSAddressSeed exited\n");
1156 void ThreadDNSAddressSeed2(void* parg)
1158 printf("ThreadDNSAddressSeed started\n");
1164 // Each pair gives a source name and a seed name.
1165 // The first name is used as information source for addrman.
1166 // The second name should resolve to a list of seed addresses.
1167 static const vector<pair <string, string> > vstrDNSSeed = {
1168 { "node.novacoin.karelia.pro", "dnsseed.novacoin.karelia.pro" },
1169 { "novacoin.ru", "dnsseed.novacoin.ru" },
1170 { "novacoin.ru", "testseed.novacoin.ru" },
1171 { "novaco.in", "dnsseed.novaco.in" },
1173 printf("Loading addresses from DNS seeds (could take a while)\n");
1175 for (unsigned int seed_idx = 0; seed_idx < vstrDNSSeed.size(); seed_idx++) {
1176 if (HaveNameProxy()) {
1177 AddOneShot(vstrDNSSeed[seed_idx].second);
1179 vector<CNetAddr> vaddr;
1180 vector<CAddress> vAdd;
1181 if (LookupHost(vstrDNSSeed[seed_idx].second, vaddr))
1183 for(CNetAddr& ip : vaddr)
1185 auto addr = CAddress(CService(ip, GetDefaultPort()));
1186 addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
1187 vAdd.push_back(addr);
1191 addrman.Add(vAdd, CNetAddr(vstrDNSSeed[seed_idx].first, true));
1196 printf("%d addresses found from DNS seeds\n", found);
1199 void DumpAddresses()
1201 auto nStart = GetTimeMillis();
1206 printf("Flushed %d addresses to peers.dat %" PRId64 "ms\n",
1207 addrman.size(), GetTimeMillis() - nStart);
1210 void ThreadDumpAddress2(void* parg)
1212 printf("ThreadDumpAddress started\n");
1214 vnThreadsRunning[THREAD_DUMPADDRESS]++;
1218 vnThreadsRunning[THREAD_DUMPADDRESS]--;
1220 vnThreadsRunning[THREAD_DUMPADDRESS]++;
1222 vnThreadsRunning[THREAD_DUMPADDRESS]--;
1225 void ThreadDumpAddress(void* parg)
1227 // Make this thread recognisable as the address dumping thread
1228 RenameThread("novacoin-adrdump");
1232 ThreadDumpAddress2(parg);
1234 catch (exception& e) {
1235 PrintException(&e, "ThreadDumpAddress()");
1237 printf("ThreadDumpAddress exited\n");
1240 void ThreadOpenConnections(void* parg)
1242 // Make this thread recognisable as the connection opening thread
1243 RenameThread("novacoin-opencon");
1247 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1248 ThreadOpenConnections2(parg);
1249 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1251 catch (exception& e) {
1252 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1253 PrintException(&e, "ThreadOpenConnections()");
1255 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1256 PrintException(NULL, "ThreadOpenConnections()");
1258 printf("ThreadOpenConnections exited\n");
1261 void static ProcessOneShot()
1266 if (vOneShots.empty())
1268 strDest = vOneShots.front();
1269 vOneShots.pop_front();
1272 CSemaphoreGrant grant(*semOutbound, true);
1274 if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true))
1275 AddOneShot(strDest);
1279 void ThreadOpenConnections2(void* parg)
1281 printf("ThreadOpenConnections started\n");
1283 // Connect to specific addresses
1284 if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
1286 for (int64_t nLoop = 0;; nLoop++)
1289 for(string strAddr : mapMultiArgs["-connect"])
1292 OpenNetworkConnection(addr, NULL, strAddr.c_str());
1293 for (int i = 0; i < 10 && i < nLoop; i++)
1304 // Initiate network connections
1305 auto nStart = GetTime();
1310 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1312 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1317 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1318 CSemaphoreGrant grant(*semOutbound);
1319 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1323 // Add seed nodes if IRC isn't working
1324 if (!IsLimited(NET_IPV4) && addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
1326 vector<uint32_t> vnSeed =
1328 0x1c542868, 0x3859dd6f, 0x203c2e68, 0xf145a6bc, 0x638a545f, 0x325da346, 0x385da346, 0xfb2b8d5f,
1329 0x52568c5f, 0xa979e65b, 0x8de6485d, 0x9f79e65b, 0x048a861f, 0x3388b55f, 0x6ff0b45e, 0x17e81f5f,
1330 0x6c47bb25, 0x1ecdc852, 0x28263db9, 0x47824e5d, 0x36f1c851, 0x2bf913b2, 0x95923cb3, 0x84e63eb2,
1331 0xefdeedbf, 0x65200092, 0xf36f6805, 0x42692d05, 0x772c1955, 0xb6bf1b4e, 0x7abb5f5d, 0xdb2fa6bc,
1332 0x90e911bf, 0x82de565f, 0x694416b2, 0x0ab600bc, 0xfcecbe6d, 0x24ed9fb2, 0x1bb618c2, 0xc64765bb,
1333 0x4e3d62c3, 0xdba24baa, 0x4b7109b0, 0x12a12cc2, 0xfc01864f, 0x0b69e85b, 0x33922c1f, 0xac611bc6,
1334 0x2a257155, 0x991d5fc0, 0xbfdabcb1, 0x9b73ee55, 0x5bc2b95d, 0xdef0762e, 0x6ab7c936, 0x9c4416b2,
1335 0xd60d864f, 0x03671f1f, 0x3b5da346, 0xc6f5c851, 0x5411b2d4, 0xe7c25702, 0x63474fb0, 0x7e11c854,
1336 0x52381d5f, 0x72fdfe59, 0x51599a05, 0xfb12b2d4, 0xaee4f15e, 0xd0e3f15e, 0x2aa2805f, 0xa1caf15e,
1337 0x34fe425e, 0x46e1f15e, 0xd7c71955, 0xaeeff15e, 0x47c2af55, 0x563d89b2, 0x67980fd9, 0xc9def15e,
1338 0x9cc51eb9, 0xdaa7aa6b, 0x78e6871f, 0x0d5d2cb2, 0x7aedf15e, 0x9bcaf15e, 0xe5f7f15e, 0x501c1759,
1339 0xdfbc4980, 0xa7397f2e, 0x31ea1a02, 0x3a27655e, 0xaa86f05c, 0xdcddf15e, 0x64689cb2, 0xd4bf62d4,
1340 0xf093eab2, 0x98def15e, 0xb6c5f15e, 0x81e8f15e, 0xe5d2fe59, 0xa312786d, 0x4cf9fe59, 0x8a922c1f,
1341 0x00c7fe59, 0x1ade565f, 0x9e4116b2, 0x2c36983e, 0x68f8f15e, 0x51b7eab2, 0x76c51eb9, 0x9edd4980,
1342 0x90ef565f, 0x0dd80857, 0xd513fb94, 0xf5bdeab2, 0xa95277b0, 0x2cf2f15e, 0x1897eab2, 0x924416b2,
1343 0x985c9b59, 0x30aa43d8, 0xf9c6745f, 0xaf862e5f, 0xe0ceeab2, 0xb9b3eab2, 0x6da4eab2, 0xa4fdeab2,
1344 0x0fa6c125, 0xe38bbd05, 0x5d922c1f, 0x9bd0eab2, 0x73025e02, 0xc4fd794d, 0x8435b35f, 0x2d01bc2e,
1345 0xaa2a14d4, 0xa22b07cb, 0xebda6f4f, 0xddc6514e, 0xf23feab2, 0xea1e5256, 0x6147b45e, 0x47d21e4f,
1346 0x67c41c1f, 0x53ec1a02, 0x352e786d, 0x6bec1a02, 0x78fb4abe, 0xd3014c5d, 0x9fbbeab2, 0x1fc51eb9,
1347 0x720eeab2, 0x2db5eab2, 0xe8baf65c, 0x521b459e, 0x65c4955f, 0x0e7b915f, 0xa8f37e6d, 0x6d0b465f,
1348 0xfab8ff5c, 0xf7c27e6d, 0x7345a846, 0x4fd1a7d5, 0xdfc97e6d, 0x26c27e6d, 0xa9de36b2, 0xc615344d,
1349 0x28ceb95d, 0xa52d895e, 0x18c17e6d, 0x13ec1a02, 0x0ba37125, 0x6c3d344d, 0xb3922c1f, 0x506bbeb0,
1350 0x4d04994e, 0xa1bbe56d, 0xf62c344d, 0x0847d048, 0x4bdc6451, 0xc95b9a05, 0xbcd3a7d5, 0x29b57125,
1351 0x0c4d2cb2, 0xf2b8eab2, 0xc2d5b95d, 0x0185ef59, 0x30adeab2, 0xcaf0e92e, 0x756c344d, 0xfd9e252e,
1352 0xbe5ef3bc, 0x4689344d, 0xb223895e, 0xfcebeaad, 0xb7c0e92e, 0x993c1760, 0xe1e171b0, 0xb857e75b,
1353 0xbf10002e, 0xb55b2cb2, 0xa90e2cb2, 0x13d6f15e, 0xf8be9225, 0x14ddf15e, 0x06e90305, 0x82472cb2,
1355 vector<CAddress> vAdd;
1356 for (unsigned int i = 0; i < vnSeed.size(); i++)
1358 // It'll only connect to one or two seed nodes because once it connects,
1359 // it'll get a pile of addresses with newer timestamps.
1360 // Seed nodes are given a random 'last seen time' of between one and two
1363 memcpy(&ip, &vnSeed[i], sizeof(ip));
1364 CAddress addr(CService(ip, GetDefaultPort()));
1365 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1366 vAdd.push_back(addr);
1368 addrman.Add(vAdd, CNetAddr("127.0.0.1"));
1371 // Add Tor nodes if we have connection with onion router
1372 if (mapArgs.count("-tor"))
1374 const vector<string> vstrTorSeed =
1376 "seedp4knqnoei57u.onion",
1377 "seedr3hhlepyi7fd.onion",
1378 "seed3uuomkclbiz4.onion",
1379 "seedeh7qck3ouff5.onion",
1380 "5rg3vq4jagckeckf.onion",
1381 "seedt3sraf53ajiy.onion",
1382 "seedg4qyccsg42oq.onion",
1383 "novaqrtoywpg7jly.onion",
1384 "seed3d5wolqbgrcb.onion",
1385 "seed24u5dwph3qw4.onion",
1386 "mj26ulzbs2oskgym.onion",
1387 "eqon4usunavt76m7.onion",
1388 "seedd3aldwpslzl3.onion"
1390 vector<CAddress> vAdd;
1391 for (unsigned int i = 0; i < vstrTorSeed.size(); i++)
1393 CAddress addr(CService(vstrTorSeed[i], GetDefaultPort()));
1394 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1395 vAdd.push_back(addr);
1397 addrman.Add(vAdd, CNetAddr("dummyaddress.onion"));
1401 // Choose an address to connect to based on most recently seen
1403 CAddress addrConnect;
1405 // Only connect out to one peer per network group (/16 for IPv4).
1406 // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
1408 set<vector<unsigned char> > setConnected;
1411 for(CNode* pnode : vNodes) {
1412 if (!pnode->fInbound) {
1413 setConnected.insert(pnode->addr.GetGroup());
1419 auto nANow = GetAdjustedTime();
1424 // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
1425 auto addr = addrman.Select(10 + min(nOutbound,8)*10);
1427 // if we selected an invalid address, restart
1428 if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
1431 // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
1432 // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
1433 // already-connected network ranges, ...) before trying new addrman addresses.
1438 if (IsLimited(addr))
1441 // only consider very recently tried nodes after 30 failed attempts
1442 if (nANow - addr.nLastTry < 600 && nTries < 30)
1445 // do not allow non-default ports, unless after 50 invalid addresses selected already
1446 if (addr.GetPort() != GetDefaultPort() && nTries < 50)
1453 if (addrConnect.IsValid())
1454 OpenNetworkConnection(addrConnect, &grant);
1458 void ThreadOpenAddedConnections(void* parg)
1460 // Make this thread recognisable as the connection opening thread
1461 RenameThread("novacoin-opencon");
1465 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1466 ThreadOpenAddedConnections2(parg);
1467 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1469 catch (exception& e) {
1470 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1471 PrintException(&e, "ThreadOpenAddedConnections()");
1473 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1474 PrintException(NULL, "ThreadOpenAddedConnections()");
1476 printf("ThreadOpenAddedConnections exited\n");
1479 void ThreadOpenAddedConnections2(void* parg)
1481 printf("ThreadOpenAddedConnections started\n");
1484 LOCK(cs_vAddedNodes);
1485 vAddedNodes = mapMultiArgs["-addnode"];
1488 if (HaveNameProxy()) {
1490 list<string> lAddresses(0);
1492 LOCK(cs_vAddedNodes);
1493 for(string& strAddNode : vAddedNodes)
1494 lAddresses.push_back(strAddNode);
1496 for(string& strAddNode : lAddresses) {
1498 CSemaphoreGrant grant(*semOutbound);
1499 OpenNetworkConnection(addr, &grant, strAddNode.c_str());
1502 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1503 Sleep(120000); // Retry every 2 minutes
1504 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1509 for (uint32_t i = 0; true; i++)
1511 list<string> lAddresses(0);
1513 LOCK(cs_vAddedNodes);
1514 for(string& strAddNode : vAddedNodes)
1515 lAddresses.push_back(strAddNode);
1518 list<vector<CService> > lservAddressesToAdd(0);
1519 for(string& strAddNode : lAddresses)
1521 vector<CService> vservNode(0);
1522 if (Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
1524 lservAddressesToAdd.push_back(vservNode);
1526 LOCK(cs_setservAddNodeAddresses);
1527 for(CService& serv : vservNode)
1528 setservAddNodeAddresses.insert(serv);
1532 // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
1533 // (keeping in mind that addnode entries can have many IPs if fNameLookup)
1536 for(CNode* pnode : vNodes)
1537 for (auto it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
1539 for(CService& addrNode : *(it))
1540 if (pnode->addr == addrNode)
1542 it = lservAddressesToAdd.erase(it);
1543 if(it != lservAddressesToAdd.begin())
1547 if (it == lservAddressesToAdd.end())
1551 for(vector<CService>& vserv : lservAddressesToAdd)
1553 if (vserv.size() == 0)
1555 CSemaphoreGrant grant(*semOutbound);
1556 OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
1563 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1564 Sleep(120000); // Retry every 2 minutes
1565 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1571 // if successful, this moves the passed grant to the constructed node
1572 bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot)
1575 // Initiate outbound network connection
1580 if (IsLocal(addrConnect) ||
1581 FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
1582 FindNode(addrConnect.ToStringIPPort().c_str()))
1584 if (strDest && FindNode(strDest))
1587 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1588 CNode* pnode = ConnectNode(addrConnect, strDest);
1589 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1595 grantOutbound->MoveTo(pnode->grantOutbound);
1596 pnode->fNetworkNode = true;
1598 pnode->fOneShot = true;
1603 // for now, use a very simple selection metric: the node from which we received
1605 static int64_t NodeSyncScore(const CNode *pnode) {
1606 return pnode->nLastRecv;
1609 void static StartSync(const vector<CNode*> &vNodes) {
1610 CNode *pnodeNewSync = NULL;
1611 int64_t nBestScore = 0;
1613 // Iterate over all nodes
1614 for(CNode* pnode : vNodes) {
1615 // check preconditions for allowing a sync
1616 if (!pnode->fClient && !pnode->fOneShot &&
1617 !pnode->fDisconnect && pnode->fSuccessfullyConnected &&
1618 (pnode->nStartingHeight > (nBestHeight - 144)) &&
1619 (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
1620 // if ok, compare node's score with the best so far
1621 int64_t nScore = NodeSyncScore(pnode);
1622 if (pnodeNewSync == NULL || nScore > nBestScore) {
1623 pnodeNewSync = pnode;
1624 nBestScore = nScore;
1628 // if a new sync candidate was found, start sync!
1630 pnodeNewSync->fStartSync = true;
1631 pnodeSync = pnodeNewSync;
1635 void ThreadMessageHandler(void* parg)
1637 // Make this thread recognisable as the message handling thread
1638 RenameThread("novacoin-msghand");
1642 vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1643 ThreadMessageHandler2(parg);
1644 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1646 catch (exception& e) {
1647 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1648 PrintException(&e, "ThreadMessageHandler()");
1650 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1651 PrintException(NULL, "ThreadMessageHandler()");
1653 printf("ThreadMessageHandler exited\n");
1656 void ThreadMessageHandler2(void* parg)
1658 printf("ThreadMessageHandler started\n");
1659 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1662 bool fHaveSyncNode = false;
1663 vector<CNode*> vNodesCopy;
1666 vNodesCopy = vNodes;
1667 for(CNode* pnode : vNodesCopy) {
1669 if (pnode == pnodeSync)
1670 fHaveSyncNode = true;
1675 StartSync(vNodesCopy);
1677 // Poll the connected nodes for messages
1678 for(CNode* pnode : vNodesCopy)
1682 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1684 ProcessMessages(pnode);
1691 TRY_LOCK(pnode->cs_vSend, lockSend);
1693 SendMessages(pnode);
1701 for(CNode* pnode : vNodesCopy)
1705 // Wait and allow messages to bunch up.
1706 // Reduce vnThreadsRunning so StopNode has permission to exit while
1707 // we're sleeping, but we must always check fShutdown after doing this.
1708 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1710 if (fRequestShutdown)
1712 vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1723 bool BindListenPort(const CService &addrBind, string& strError)
1728 // Create socket for listening for incoming connections
1729 struct sockaddr_storage sockaddr;
1730 socklen_t len = sizeof(sockaddr);
1731 if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
1733 strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
1734 printf("%s\n", strError.c_str());
1738 SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
1739 if (hListenSocket == INVALID_SOCKET)
1741 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1742 printf("%s\n", strError.c_str());
1748 // Different way of disabling SIGPIPE on BSD
1749 if (setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1751 printf("WARNING: setsockopt failed\n");
1752 //TODO: work around problem - may be add CloseSocket and return false?
1755 // Allow binding if the port is still in TIME_WAIT state after
1756 // the program was closed and restarted. Not an issue on windows!
1757 if (setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1759 printf("WARNING: setsockopt failed\n");
1760 //TODO: work around problem - may be add CloseSocket and return false?
1765 // Set to non-blocking, incoming connections will also inherit this
1766 if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
1768 if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
1771 strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1772 printf("%s\n", strError.c_str());
1773 CloseSocket(hListenSocket);
1777 // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
1778 // and enable it by default or not. Try to enable it, if possible.
1779 if (addrBind.IsIPv6()) {
1782 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int)) == SOCKET_ERROR)
1784 printf("WARNING: setsockopt failed\n");
1785 //TODO: work around problem - may be add CloseSocket and return false?
1788 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1790 printf("WARNING: setsockopt failed\n");
1791 //TODO: work around problem - may be add CloseSocket and return false?
1796 int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
1797 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)) == SOCKET_ERROR)
1799 printf("WARNING: setsockopt failed\n");
1800 //TODO: work around problem - may be add CloseSocket and return false?
1805 if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
1807 int nErr = WSAGetLastError();
1808 if (nErr == WSAEADDRINUSE)
1809 strError = strprintf(_("Unable to bind to %s on this computer. NovaCoin is probably already running."), addrBind.ToString().c_str());
1811 strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString().c_str(), NetworkErrorString(nErr).c_str());
1812 printf("%s\n", strError.c_str());
1813 CloseSocket(hListenSocket);
1816 printf("Bound to %s\n", addrBind.ToString().c_str());
1818 // Listen for incoming connections
1819 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1821 strError = strprintf("Error: Listening for incoming connections failed (listen returned error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1822 printf("%s\n", strError.c_str());
1823 CloseSocket(hListenSocket);
1827 vhListenSocket.push_back(hListenSocket);
1829 if (addrBind.IsRoutable() && fDiscover)
1830 AddLocal(addrBind, LOCAL_BIND);
1835 void static Discover()
1841 // Get local host IP
1842 char pszHostName[1000] = "";
1843 if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1845 vector<CNetAddr> vaddr;
1846 if (LookupHost(pszHostName, vaddr))
1848 for(const auto &addr : vaddr)
1850 AddLocal(addr, LOCAL_IF);
1855 // Get local host ip
1856 struct ifaddrs* myaddrs;
1857 if (getifaddrs(&myaddrs) == 0)
1859 for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1861 if (ifa->ifa_addr == NULL) continue;
1862 if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1863 if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1864 if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
1865 if (ifa->ifa_addr->sa_family == AF_INET)
1867 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
1868 CNetAddr addr(s4->sin_addr);
1869 if (AddLocal(addr, LOCAL_IF))
1870 printf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1872 else if (ifa->ifa_addr->sa_family == AF_INET6)
1874 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
1875 CNetAddr addr(s6->sin6_addr);
1876 if (AddLocal(addr, LOCAL_IF))
1877 printf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1880 freeifaddrs(myaddrs);
1884 // Don't use external IPv4 discovery, when -onlynet="IPv6"
1885 if (!IsLimited(NET_IPV4))
1886 NewThread(ThreadGetMyExternalIP, NULL);
1889 void StartNode(void* parg)
1891 // Make this thread recognisable as the startup thread
1892 RenameThread("novacoin-start");
1894 if (semOutbound == NULL) {
1895 // initialize semaphore
1896 int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, GetArgInt("-maxconnections", 125));
1897 semOutbound = new CSemaphore(nMaxOutbound);
1900 if (pnodeLocalHost == NULL)
1901 pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", nPortZero), nLocalServices));
1909 if (!GetBoolArg("-dnsseed", true))
1910 printf("DNS seeding disabled\n");
1912 if (!NewThread(ThreadDNSAddressSeed, NULL))
1913 printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
1915 // Get addresses from IRC and advertise ours
1916 if (!GetBoolArg("-irc", true))
1917 printf("IRC seeding disabled\n");
1919 if (!NewThread(ThreadIRCSeed, NULL))
1920 printf("Error: NewThread(ThreadIRCSeed) failed\n");
1922 // Send and receive from sockets, accept connections
1923 if (!NewThread(ThreadSocketHandler, NULL))
1924 printf("Error: NewThread(ThreadSocketHandler) failed\n");
1926 // Initiate outbound connections from -addnode
1927 if (!NewThread(ThreadOpenAddedConnections, NULL))
1928 printf("Error: NewThread(ThreadOpenAddedConnections) failed\n");
1930 // Initiate outbound connections
1931 if (!NewThread(ThreadOpenConnections, NULL))
1932 printf("Error: NewThread(ThreadOpenConnections) failed\n");
1935 if (!NewThread(ThreadMessageHandler, NULL))
1936 printf("Error: NewThread(ThreadMessageHandler) failed\n");
1938 // Dump network addresses
1939 if (!NewThread(ThreadDumpAddress, NULL))
1940 printf("Error; NewThread(ThreadDumpAddress) failed\n");
1942 // Mine proof-of-stake blocks in the background
1943 if (!NewThread(ThreadStakeMiner, pwalletMain))
1944 printf("Error: NewThread(ThreadStakeMiner) failed\n");
1946 // Trusted NTP server, it's localhost by default.
1947 strTrustedUpstream = GetArg("-ntp", "localhost");
1949 // Start periodical NTP sampling thread
1950 NewThread(ThreadNtpSamples, NULL);
1956 printf("StopNode()\n");
1958 nTransactionsUpdated++;
1959 auto nStart = GetTime();
1962 ThreadScriptCheckQuit();
1965 for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
1966 semOutbound->post();
1969 int nThreadsRunning = 0;
1970 for (int n = 0; n < THREAD_MAX; n++)
1971 nThreadsRunning += vnThreadsRunning[n];
1972 if (nThreadsRunning == 0)
1974 if (GetTime() - nStart > 20)
1978 if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
1979 if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
1980 if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
1981 if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n");
1982 if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n");
1983 if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
1984 if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
1985 if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
1986 if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStakeMinter still running\n");
1987 if (vnThreadsRunning[THREAD_SCRIPTCHECK] > 0) printf("ThreadScriptCheck still running\n");
1988 while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0 || vnThreadsRunning[THREAD_SCRIPTCHECK] > 0)
2005 for(CNode* pnode : vNodes)
2006 if (pnode->hSocket != INVALID_SOCKET)
2007 CloseSocket(pnode->hSocket);
2008 for(SOCKET hListenSocket : vhListenSocket)
2009 if (hListenSocket != INVALID_SOCKET)
2010 if (!CloseSocket(hListenSocket))
2011 printf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()).c_str());
2013 // clean up some globals (to help leak detection)
2014 for(CNode *pnode : vNodes)
2016 for(CNode *pnode : vNodesDisconnected)
2019 vNodesDisconnected.clear();
2022 delete pnodeLocalHost;
2023 pnodeLocalHost = NULL;
2026 // Shutdown Windows Sockets
2031 instance_of_cnetcleanup;
2033 inline void RelayInventory(const CInv& inv)
2035 // Put on lists to offer to the other nodes
2038 for(CNode* pnode : vNodes)
2039 pnode->PushInventory(inv);
2043 void RelayTransaction(const CTransaction& tx, const uint256& hash)
2045 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2048 RelayTransaction(tx, hash, ss);
2051 void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
2053 CInv inv(MSG_TX, hash);
2056 // Expire old relay messages
2057 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
2059 mapRelay.erase(vRelayExpiration.front().second);
2060 vRelayExpiration.pop_front();
2063 // Save original serialized message so newer versions are preserved
2064 mapRelay.insert({inv, ss});
2065 vRelayExpiration.push_back({GetTime() + 15 * 60, inv});
2068 RelayInventory(inv);
2071 void CNode::RecordBytesRecv(uint64_t bytes)
2073 LOCK(cs_totalBytesRecv);
2074 nTotalBytesRecv += bytes;
2077 void CNode::RecordBytesSent(uint64_t bytes)
2079 LOCK(cs_totalBytesSent);
2080 nTotalBytesSent += bytes;
2083 uint64_t CNode::GetTotalBytesRecv()
2085 LOCK(cs_totalBytesRecv);
2086 return nTotalBytesRecv;
2089 uint64_t CNode::GetTotalBytesSent()
2091 LOCK(cs_totalBytesSent);
2092 return nTotalBytesSent;
2095 int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
2096 return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);