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;
42 uint64_t nLocalServices = (fClient ? 0 : NODE_NETWORK);
43 CCriticalSection cs_mapLocalHost;
44 map<CNetAddr, LocalServiceInfo> mapLocalHost;
45 static bool vfReachable[NET_MAX] = {};
46 static bool vfLimited[NET_MAX] = {};
47 static CNode* pnodeLocalHost = NULL;
48 static CNode* pnodeSync = NULL;
49 CAddress addrSeenByPeer(CService("0.0.0.0", nPortZero), nLocalServices);
50 uint64_t nLocalHostNonce = 0;
51 array<int, THREAD_MAX> vnThreadsRunning;
52 static vector<SOCKET> vhListenSocket;
55 vector<CNode*> vNodes;
56 CCriticalSection cs_vNodes;
57 map<CInv, CDataStream> mapRelay;
58 deque<pair<int64_t, CInv> > vRelayExpiration;
59 CCriticalSection cs_mapRelay;
60 map<CInv, int64_t> mapAlreadyAskedFor;
62 static deque<string> vOneShots;
63 CCriticalSection cs_vOneShots;
65 set<CNetAddr> setservAddNodeAddresses;
66 CCriticalSection cs_setservAddNodeAddresses;
68 vector<string> vAddedNodes;
69 CCriticalSection cs_vAddedNodes;
71 static CSemaphore *semOutbound = NULL;
73 void AddOneShot(string strDest)
76 vOneShots.push_back(strDest);
79 uint16_t GetListenPort()
81 return static_cast<uint16_t>(GetArg("-port", GetDefaultPort()));
84 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
86 // Filter out duplicate requests
87 if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
89 pindexLastGetBlocksBegin = pindexBegin;
90 hashLastGetBlocksEnd = hashEnd;
92 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
95 // find 'best' local address for a particular peer
96 bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
102 int nBestReachability = -1;
104 LOCK(cs_mapLocalHost);
105 for (auto it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
107 int nScore = (*it).second.nScore;
108 int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
109 if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
111 addr = CService((*it).first, (*it).second.nPort);
112 nBestReachability = nReachability;
117 return nBestScore >= 0;
120 // get best local address for a particular peer as a CAddress
121 CAddress GetLocalAddress(const CNetAddr *paddrPeer)
123 CAddress ret(CService("0.0.0.0", nPortZero), 0);
125 if (GetLocal(addr, paddrPeer))
127 ret = CAddress(addr);
128 ret.nServices = nLocalServices;
129 ret.nTime = GetAdjustedTime();
134 bool RecvLine(SOCKET hSocket, string& strLine)
140 int nBytes = recv(hSocket, &c, 1, 0);
148 if (strLine.size() >= 9000)
151 else if (nBytes <= 0)
157 int nErr = WSAGetLastError();
158 if (nErr == WSAEMSGSIZE)
160 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
166 if (!strLine.empty())
171 printf("socket closed\n");
177 int nErr = WSAGetLastError();
178 printf("recv failed: %s\n", NetworkErrorString(nErr).c_str());
185 // used when scores of local addresses may have changed
186 // pushes better local address to peers
187 void static AdvertizeLocal()
190 for(CNode* pnode : vNodes)
192 if (pnode->fSuccessfullyConnected)
194 auto addrLocal = GetLocalAddress(&pnode->addr);
195 if (addrLocal.IsRoutable() && (CService)addrLocal != pnode->addrLocal)
197 pnode->PushAddress(addrLocal);
198 pnode->addrLocal = addrLocal;
204 void SetReachable(enum Network net, bool fFlag)
206 LOCK(cs_mapLocalHost);
207 vfReachable[net] = fFlag;
208 if (net == NET_IPV6 && fFlag)
209 vfReachable[NET_IPV4] = true;
212 int GetnScore(const CService& addr)
214 LOCK(cs_mapLocalHost);
215 if (mapLocalHost.count(addr) == LOCAL_NONE)
217 return mapLocalHost[addr].nScore;
221 // Is our peer's addrLocal potentially useful as an external IP source?
222 bool IsPeerAddrLocalGood(CNode *pnode)
224 return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() &&
225 !IsLimited(pnode->addrLocal.GetNetwork());
228 // pushes our own address to a peer
229 void AdvertiseLocal(CNode *pnode)
231 if (fListen && pnode->fSuccessfullyConnected)
233 auto addrLocal = GetLocalAddress(&pnode->addr);
234 // If discovery is enabled, sometimes give our peer the address it
235 // tells us that it sees us as in case it has a better idea of our
236 // address than we do.
237 if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
238 GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
240 addrLocal.SetIP(pnode->addrLocal);
242 if (addrLocal.IsRoutable())
244 printf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString().c_str());
245 pnode->PushAddress(addrLocal);
250 // learn a new local address
251 bool AddLocal(const CService& addr, int nScore)
253 if (!addr.IsRoutable())
256 if (!fDiscover && nScore < LOCAL_MANUAL)
262 printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore);
265 LOCK(cs_mapLocalHost);
266 bool fAlready = mapLocalHost.count(addr) > 0;
267 LocalServiceInfo &info = mapLocalHost[addr];
268 if (!fAlready || nScore >= info.nScore) {
269 info.nScore = nScore + (fAlready ? 1 : 0);
270 info.nPort = addr.GetPort();
272 SetReachable(addr.GetNetwork());
280 bool AddLocal(const CNetAddr &addr, int nScore)
282 return AddLocal(CService(addr, GetListenPort()), nScore);
285 /** Make a particular network entirely off-limits (no automatic connects to it) */
286 void SetLimited(enum Network net, bool fLimited)
288 if (net == NET_UNROUTABLE)
290 LOCK(cs_mapLocalHost);
291 vfLimited[net] = fLimited;
294 bool IsLimited(enum Network net)
296 LOCK(cs_mapLocalHost);
297 return vfLimited[net];
300 bool IsLimited(const CNetAddr &addr)
302 return IsLimited(addr.GetNetwork());
305 /** vote for a local address */
306 bool SeenLocal(const CService& addr)
309 LOCK(cs_mapLocalHost);
310 if (mapLocalHost.count(addr) == 0)
312 mapLocalHost[addr].nScore++;
320 /** check whether a given address is potentially local */
321 bool IsLocal(const CService& addr)
323 LOCK(cs_mapLocalHost);
324 return mapLocalHost.count(addr) > 0;
327 /** check whether a given address is in a network we can probably connect to */
328 bool IsReachable(const CNetAddr& addr)
330 LOCK(cs_mapLocalHost);
331 enum Network net = addr.GetNetwork();
332 return vfReachable[net] && !vfLimited[net];
335 extern int GetExternalIPbySTUN(uint64_t rnd, struct sockaddr_in *mapped, const char **srv);
337 // We now get our external IP from the IRC server first and only use this as a backup
338 bool GetMyExternalIP(CNetAddr& ipRet)
340 struct sockaddr_in mapped = {};
341 auto rnd = GetRand(numeric_limits<uint64_t>::max());
343 int rc = GetExternalIPbySTUN(rnd, &mapped, &srv);
345 ipRet = CNetAddr(mapped.sin_addr);
347 printf("GetExternalIPbySTUN(%" PRIu64 ") returned %s in attempt %d; Server=%s\n", rnd, ipRet.ToStringIP().c_str(), rc, srv);
354 void ThreadGetMyExternalIP(void* parg)
356 // Make this thread recognisable as the external IP detection thread
357 RenameThread("novacoin-ext-ip");
359 CNetAddr addrLocalHost;
360 if (GetMyExternalIP(addrLocalHost))
362 printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
363 AddLocal(addrLocalHost, LOCAL_HTTP);
367 void AddressCurrentlyConnected(const CService& addr)
369 addrman.Connected(addr);
375 uint64_t CNode::nTotalBytesRecv = 0;
376 uint64_t CNode::nTotalBytesSent = 0;
377 CCriticalSection CNode::cs_totalBytesRecv;
378 CCriticalSection CNode::cs_totalBytesSent;
380 CNode* FindNode(const CNetAddr& ip)
383 for(CNode* pnode : vNodes)
384 if ((CNetAddr)pnode->addr == ip)
389 CNode* FindNode(string addrName)
392 for(CNode* pnode : vNodes)
393 if (pnode->addrName == addrName)
398 CNode* FindNode(const CService& addr)
401 for(CNode* pnode : vNodes)
402 if ((CService)pnode->addr == addr)
407 CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64_t nTimeout)
409 if (pszDest == NULL) {
410 if (IsLocal(addrConnect))
413 // Look for an existing connection
414 CNode* pnode = FindNode((CService)addrConnect);
418 pnode->AddRef(nTimeout);
427 printf("trying connection %s lastseen=%.1fhrs\n",
428 pszDest ? pszDest : addrConnect.ToString().c_str(),
429 pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
433 if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, GetDefaultPort()) : ConnectSocket(addrConnect, hSocket))
435 addrman.Attempt(addrConnect);
438 printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str());
440 // Set to non-blocking
443 if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
444 printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %s\n", NetworkErrorString(WSAGetLastError()).c_str());
446 if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
447 printf("ConnectSocket() : fcntl non-blocking setting failed, error %s\n", NetworkErrorString(errno).c_str());
451 CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
453 pnode->AddRef(nTimeout);
459 vNodes.push_back(pnode);
462 pnode->nTimeConnected = GetTime();
471 CNode::CNode(SOCKET hSocketIn, CAddress addrIn, string addrNameIn, bool fInboundIn) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION)
479 nLastSendEmpty = GetTime();
480 nTimeConnected = GetTime();
482 nMessageStart = numeric_limits<uint32_t>::max();
484 addrName = addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn;
488 fClient = false; // set by version message
489 fInbound = fInboundIn;
490 fNetworkNode = false;
491 fSuccessfullyConnected = false;
496 pindexLastGetBlocksBegin = 0;
497 hashLastGetBlocksEnd = 0;
498 nStartingHeight = -1;
499 nNextLocalAddrSend = 0;
505 hashCheckpointKnown = 0;
506 setInventoryKnown.max_size((size_t)SendBufferSize() / 1000);
508 // Be shy and don't send version until we hear
509 if (hSocket != INVALID_SOCKET && !fInbound)
515 if (hSocket != INVALID_SOCKET)
517 CloseSocket(hSocket);
521 int CNode::GetRefCount()
523 return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
526 CNode* CNode::AddRef(int64_t nTimeout)
529 nReleaseTime = max(nReleaseTime, GetTime() + nTimeout);
535 void CNode::Release()
540 void CNode::AddAddressKnown(const CAddress& addr)
542 setAddrKnown.insert(addr);
545 void CNode::PushAddress(const CAddress& addr)
547 // Known checking here is only to save space from duplicates.
548 // SendMessages will filter it again for knowns that were added
549 // after addresses were pushed.
550 if (addr.IsValid() && !setAddrKnown.count(addr))
551 vAddrToSend.push_back(addr);
554 void CNode::AddInventoryKnown(const CInv& inv)
558 setInventoryKnown.insert(inv);
562 void CNode::PushInventory(const CInv& inv)
566 if (!setInventoryKnown.count(inv))
567 vInventoryToSend.push_back(inv);
571 void CNode::AskFor(const CInv& inv)
573 // We're using mapAskFor as a priority queue,
574 // the key is the earliest time the request can be sent
575 int64_t& nRequestTime = mapAlreadyAskedFor[inv];
577 printf("askfor %s %" PRId64 " (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str());
579 // Make sure not to reuse time indexes to keep things in the same order
580 int64_t nNow = (GetTime() - 1) * 1000000;
581 static int64_t nLastTime;
583 nNow = max(nNow, nLastTime);
586 // Each retry is 2 minutes after the last
587 nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow);
588 mapAskFor.insert({ nRequestTime, inv });
591 void CNode::BeginMessage(const char* pszCommand)
593 ENTER_CRITICAL_SECTION(cs_vSend);
594 if (nHeaderStart != -1)
596 nHeaderStart = (int32_t)vSend.size();
597 vSend << CMessageHeader(pszCommand, 0);
598 nMessageStart = (uint32_t)vSend.size();
600 printf("sending: %s ", pszCommand);
603 void CNode::AbortMessage()
605 if (nHeaderStart < 0)
607 vSend.resize(nHeaderStart);
609 nMessageStart = numeric_limits<uint32_t>::max();
610 LEAVE_CRITICAL_SECTION(cs_vSend);
613 printf("(aborted)\n");
616 void CNode::EndMessage()
618 if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
620 printf("dropmessages DROPPING SEND MESSAGE\n");
625 if (nHeaderStart < 0)
629 uint32_t nSize = (uint32_t) vSend.size() - nMessageStart;
630 memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::MESSAGE_SIZE_OFFSET, &nSize, sizeof(nSize));
633 auto hash = Hash(vSend.begin() + nMessageStart, vSend.end());
634 uint32_t nChecksum = 0;
635 memcpy(&nChecksum, &hash, sizeof(nChecksum));
636 assert(nMessageStart - nHeaderStart >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
637 memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::CHECKSUM_OFFSET, &nChecksum, sizeof(nChecksum));
640 printf("(%d bytes)\n", nSize);
644 nMessageStart = numeric_limits<uint32_t>::max();
645 LEAVE_CRITICAL_SECTION(cs_vSend);
648 void CNode::EndMessageAbortIfEmpty()
650 if (nHeaderStart < 0)
652 int nSize = (int) vSend.size() - nMessageStart;
659 void CNode::CloseSocketDisconnect()
662 if (hSocket != INVALID_SOCKET)
664 printf("disconnecting node %s\n", addrName.c_str());
665 CloseSocket(hSocket);
669 // in case this fails, we'll empty the recv buffer when the CNode is deleted
670 TRY_LOCK(cs_vRecv, lockRecv);
674 // if this was the sync node, we'll need a new one
675 if (this == pnodeSync)
679 void CNode::Cleanup()
684 void CNode::PushVersion()
686 auto nTime = GetAdjustedTime();
687 CAddress addrYou, addrMe;
689 bool fHidden = false;
691 if (mapArgs.count("-torname")) {
692 // Our hidden service address
693 CService addrTorName(mapArgs["-torname"], GetListenPort());
695 if (addrTorName.IsValid()) {
697 addrMe = CAddress(addrTorName);
704 addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", nPortZero)));
705 addrMe = GetLocalAddress(&addr);
708 RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
709 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());
710 PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
711 nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, vector<string>()), nBestHeight);
718 map<CNetAddr, int64_t> CNode::setBanned;
719 CCriticalSection CNode::cs_setBanned;
721 void CNode::ClearBanned()
727 bool CNode::IsBanned(const CNetAddr& ip)
729 bool fResult = false;
732 auto i = setBanned.find(ip);
733 if (i != setBanned.end())
735 auto t = (*i).second;
743 bool CNode::Misbehaving(int howmuch)
747 printf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch);
751 nMisbehavior += howmuch;
752 if (nMisbehavior >= GetArgInt("-banscore", 100))
754 auto banTime = GetTime()+GetArg("-bantime", nOneDay); // Default 24-hour ban
755 printf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
758 if (setBanned[addr] < banTime)
759 setBanned[addr] = banTime;
761 CloseSocketDisconnect();
764 printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
769 #define X(name) stats.name = name
770 void CNode::copyStats(CNodeStats &stats)
785 stats.fSyncNode = (this == pnodeSync);
790 void ThreadSocketHandler(void* parg)
792 // Make this thread recognisable as the networking thread
793 RenameThread("novacoin-net");
797 vnThreadsRunning[THREAD_SOCKETHANDLER]++;
798 ThreadSocketHandler2(parg);
799 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
801 catch (exception& e) {
802 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
803 PrintException(&e, "ThreadSocketHandler()");
805 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
806 throw; // support pthread_cancel()
808 printf("ThreadSocketHandler exited\n");
811 static list<CNode*> vNodesDisconnected;
813 void ThreadSocketHandler2(void* parg)
815 printf("ThreadSocketHandler started\n");
816 size_t nPrevNodeCount = 0;
824 // Disconnect unused nodes
825 vector<CNode*> vNodesCopy = vNodes;
826 for(CNode* pnode : vNodesCopy)
828 if (pnode->fDisconnect ||
829 (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
831 // remove from vNodes
832 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
834 // release outbound grant (if any)
835 pnode->grantOutbound.Release();
837 // close socket and cleanup
838 pnode->CloseSocketDisconnect();
841 // hold in disconnected pool until all refs are released
842 pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
843 if (pnode->fNetworkNode || pnode->fInbound)
845 vNodesDisconnected.push_back(pnode);
849 // Delete disconnected nodes
850 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
851 for(CNode* pnode : vNodesDisconnectedCopy)
853 // wait until threads are done using it
854 if (pnode->GetRefCount() <= 0)
856 bool fDelete = false;
858 TRY_LOCK(pnode->cs_vSend, lockSend);
861 TRY_LOCK(pnode->cs_vRecv, lockRecv);
864 TRY_LOCK(pnode->cs_mapRequests, lockReq);
867 TRY_LOCK(pnode->cs_inventory, lockInv);
876 vNodesDisconnected.remove(pnode);
882 if (vNodes.size() != nPrevNodeCount)
884 nPrevNodeCount = vNodes.size();
885 uiInterface.NotifyNumConnectionsChanged(vNodes.size());
890 // Find which sockets have data to receive
892 struct timeval timeout;
894 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
901 FD_ZERO(&fdsetError);
902 SOCKET hSocketMax = 0;
903 bool have_fds = false;
905 for(SOCKET hListenSocket : vhListenSocket) {
906 FD_SET(hListenSocket, &fdsetRecv);
907 hSocketMax = max(hSocketMax, hListenSocket);
912 for(CNode* pnode : vNodes)
914 if (pnode->hSocket == INVALID_SOCKET)
916 FD_SET(pnode->hSocket, &fdsetRecv);
917 FD_SET(pnode->hSocket, &fdsetError);
918 hSocketMax = max(hSocketMax, pnode->hSocket);
921 TRY_LOCK(pnode->cs_vSend, lockSend);
922 if (lockSend && !pnode->vSend.empty())
923 FD_SET(pnode->hSocket, &fdsetSend);
928 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
929 int nSelect = select(have_fds ? hSocketMax + 1 : 0,
930 &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
931 vnThreadsRunning[THREAD_SOCKETHANDLER]++;
934 if (nSelect == SOCKET_ERROR)
938 int nErr = WSAGetLastError();
939 printf("socket select error %s\n", NetworkErrorString(nErr).c_str());
940 for (unsigned int i = 0; i <= hSocketMax; i++)
941 FD_SET(i, &fdsetRecv);
944 FD_ZERO(&fdsetError);
945 Sleep(timeout.tv_usec/1000);
950 // Accept new connections
952 for(SOCKET hListenSocket : vhListenSocket)
953 if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
955 struct sockaddr_storage sockaddr;
956 socklen_t len = sizeof(sockaddr);
957 SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
961 if (hSocket != INVALID_SOCKET)
962 if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
963 printf("Warning: Unknown socket family\n");
967 for(CNode* pnode : vNodes)
972 if (hSocket == INVALID_SOCKET)
974 int nErr = WSAGetLastError();
975 if (nErr != WSAEWOULDBLOCK)
976 printf("socket error accept failed: %s\n", NetworkErrorString(nErr).c_str());
978 else if (nInbound >= GetArgInt("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
980 printf("connection from %s dropped (overall limit)\n", addr.ToString().c_str());
981 CloseSocket(hSocket);
983 else if (CNode::IsBanned(addr))
985 printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
986 CloseSocket(hSocket);
990 printf("accepted connection %s\n", addr.ToString().c_str());
991 CNode* pnode = new CNode(hSocket, addr, "", true);
995 vNodes.push_back(pnode);
1002 // Service each socket
1004 vector<CNode*> vNodesCopy;
1007 vNodesCopy = vNodes;
1008 for(CNode* pnode : vNodesCopy)
1011 for(CNode* pnode : vNodesCopy)
1019 if (pnode->hSocket == INVALID_SOCKET)
1021 if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
1023 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1026 CDataStream& vRecv = pnode->vRecv;
1027 uint64_t nPos = vRecv.size();
1029 if (nPos > ReceiveBufferSize()) {
1030 if (!pnode->fDisconnect)
1031 printf("socket recv flood control disconnect (%" PRIszu " bytes)\n", vRecv.size());
1032 pnode->CloseSocketDisconnect();
1035 // typical socket buffer is 8K-64K
1036 char pchBuf[0x10000];
1037 int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
1040 vRecv.resize(nPos + nBytes);
1041 memcpy(&vRecv[nPos], pchBuf, nBytes);
1042 pnode->nLastRecv = GetTime();
1043 pnode->nRecvBytes += nBytes;
1044 pnode->RecordBytesRecv(nBytes);
1046 else if (nBytes == 0)
1048 // socket closed gracefully
1049 if (!pnode->fDisconnect)
1050 printf("socket closed\n");
1051 pnode->CloseSocketDisconnect();
1053 else if (nBytes < 0)
1056 int nErr = WSAGetLastError();
1057 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
1059 if (!pnode->fDisconnect)
1060 printf("socket recv error %s\n", NetworkErrorString(nErr).c_str());
1061 pnode->CloseSocketDisconnect();
1071 if (pnode->hSocket == INVALID_SOCKET)
1073 if (FD_ISSET(pnode->hSocket, &fdsetSend))
1075 TRY_LOCK(pnode->cs_vSend, lockSend);
1078 CDataStream& vSend = pnode->vSend;
1081 int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
1084 vSend.erase(vSend.begin(), vSend.begin() + nBytes);
1085 pnode->nLastSend = GetTime();
1086 pnode->nSendBytes += nBytes;
1087 pnode->RecordBytesSent(nBytes);
1089 else if (nBytes < 0)
1092 int nErr = WSAGetLastError();
1093 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
1095 printf("socket send error %s\n", NetworkErrorString(nErr).c_str());
1096 pnode->CloseSocketDisconnect();
1104 // Inactivity checking
1106 if (pnode->vSend.empty())
1107 pnode->nLastSendEmpty = GetTime();
1108 if (GetTime() - pnode->nTimeConnected > 60)
1110 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
1112 printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
1113 pnode->fDisconnect = true;
1115 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
1117 printf("socket not sending\n");
1118 pnode->fDisconnect = true;
1120 else if (GetTime() - pnode->nLastRecv > 90*60)
1122 printf("socket inactivity timeout\n");
1123 pnode->fDisconnect = true;
1129 for(CNode* pnode : vNodesCopy)
1137 void ThreadDNSAddressSeed(void* parg)
1139 // Make this thread recognisable as the DNS seeding thread
1140 RenameThread("novacoin-dnsseed");
1144 vnThreadsRunning[THREAD_DNSSEED]++;
1145 ThreadDNSAddressSeed2(parg);
1146 vnThreadsRunning[THREAD_DNSSEED]--;
1148 catch (exception& e) {
1149 vnThreadsRunning[THREAD_DNSSEED]--;
1150 PrintException(&e, "ThreadDNSAddressSeed()");
1152 vnThreadsRunning[THREAD_DNSSEED]--;
1153 throw; // support pthread_cancel()
1155 printf("ThreadDNSAddressSeed exited\n");
1158 void ThreadDNSAddressSeed2(void* parg)
1160 printf("ThreadDNSAddressSeed started\n");
1166 // Each pair gives a source name and a seed name.
1167 // The first name is used as information source for addrman.
1168 // The second name should resolve to a list of seed addresses.
1169 static const vector<pair <string, string> > vstrDNSSeed = {
1170 { "node.novacoin.karelia.pro", "dnsseed.novacoin.karelia.pro" },
1171 { "novacoin.ru", "dnsseed.novacoin.ru" },
1172 { "novacoin.ru", "testseed.novacoin.ru" },
1173 { "novaco.in", "dnsseed.novaco.in" },
1175 printf("Loading addresses from DNS seeds (could take a while)\n");
1177 for (unsigned int seed_idx = 0; seed_idx < vstrDNSSeed.size(); seed_idx++) {
1178 if (HaveNameProxy()) {
1179 AddOneShot(vstrDNSSeed[seed_idx].second);
1181 vector<CNetAddr> vaddr;
1182 vector<CAddress> vAdd;
1183 if (LookupHost(vstrDNSSeed[seed_idx].second, vaddr))
1185 for(CNetAddr& ip : vaddr)
1187 auto addr = CAddress(CService(ip, GetDefaultPort()));
1188 addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
1189 vAdd.push_back(addr);
1193 addrman.Add(vAdd, CNetAddr(vstrDNSSeed[seed_idx].first, true));
1198 printf("%d addresses found from DNS seeds\n", found);
1201 void DumpAddresses()
1203 auto nStart = GetTimeMillis();
1208 printf("Flushed %d addresses to peers.dat %" PRId64 "ms\n",
1209 addrman.size(), GetTimeMillis() - nStart);
1212 void ThreadDumpAddress2(void* parg)
1214 printf("ThreadDumpAddress started\n");
1216 vnThreadsRunning[THREAD_DUMPADDRESS]++;
1220 vnThreadsRunning[THREAD_DUMPADDRESS]--;
1222 vnThreadsRunning[THREAD_DUMPADDRESS]++;
1224 vnThreadsRunning[THREAD_DUMPADDRESS]--;
1227 void ThreadDumpAddress(void* parg)
1229 // Make this thread recognisable as the address dumping thread
1230 RenameThread("novacoin-adrdump");
1234 ThreadDumpAddress2(parg);
1236 catch (exception& e) {
1237 PrintException(&e, "ThreadDumpAddress()");
1239 printf("ThreadDumpAddress exited\n");
1242 void ThreadOpenConnections(void* parg)
1244 // Make this thread recognisable as the connection opening thread
1245 RenameThread("novacoin-opencon");
1249 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1250 ThreadOpenConnections2(parg);
1251 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1253 catch (exception& e) {
1254 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1255 PrintException(&e, "ThreadOpenConnections()");
1257 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1258 PrintException(NULL, "ThreadOpenConnections()");
1260 printf("ThreadOpenConnections exited\n");
1263 void static ProcessOneShot()
1268 if (vOneShots.empty())
1270 strDest = vOneShots.front();
1271 vOneShots.pop_front();
1274 CSemaphoreGrant grant(*semOutbound, true);
1276 if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true))
1277 AddOneShot(strDest);
1281 void ThreadOpenConnections2(void* parg)
1283 printf("ThreadOpenConnections started\n");
1285 // Connect to specific addresses
1286 if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
1288 for (int64_t nLoop = 0;; nLoop++)
1291 for(string strAddr : mapMultiArgs["-connect"])
1294 OpenNetworkConnection(addr, NULL, strAddr.c_str());
1295 for (int i = 0; i < 10 && i < nLoop; i++)
1306 // Initiate network connections
1307 auto nStart = GetTime();
1312 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1314 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1319 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1320 CSemaphoreGrant grant(*semOutbound);
1321 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1325 // Add seed nodes if IRC isn't working
1326 if (!IsLimited(NET_IPV4) && addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
1328 vector<uint32_t> vnSeed =
1330 0x1c542868, 0x3859dd6f, 0x203c2e68, 0xf145a6bc, 0x638a545f, 0x325da346, 0x385da346, 0xfb2b8d5f,
1331 0x52568c5f, 0xa979e65b, 0x8de6485d, 0x9f79e65b, 0x048a861f, 0x3388b55f, 0x6ff0b45e, 0x17e81f5f,
1332 0x6c47bb25, 0x1ecdc852, 0x28263db9, 0x47824e5d, 0x36f1c851, 0x2bf913b2, 0x95923cb3, 0x84e63eb2,
1333 0xefdeedbf, 0x65200092, 0xf36f6805, 0x42692d05, 0x772c1955, 0xb6bf1b4e, 0x7abb5f5d, 0xdb2fa6bc,
1334 0x90e911bf, 0x82de565f, 0x694416b2, 0x0ab600bc, 0xfcecbe6d, 0x24ed9fb2, 0x1bb618c2, 0xc64765bb,
1335 0x4e3d62c3, 0xdba24baa, 0x4b7109b0, 0x12a12cc2, 0xfc01864f, 0x0b69e85b, 0x33922c1f, 0xac611bc6,
1336 0x2a257155, 0x991d5fc0, 0xbfdabcb1, 0x9b73ee55, 0x5bc2b95d, 0xdef0762e, 0x6ab7c936, 0x9c4416b2,
1337 0xd60d864f, 0x03671f1f, 0x3b5da346, 0xc6f5c851, 0x5411b2d4, 0xe7c25702, 0x63474fb0, 0x7e11c854,
1338 0x52381d5f, 0x72fdfe59, 0x51599a05, 0xfb12b2d4, 0xaee4f15e, 0xd0e3f15e, 0x2aa2805f, 0xa1caf15e,
1339 0x34fe425e, 0x46e1f15e, 0xd7c71955, 0xaeeff15e, 0x47c2af55, 0x563d89b2, 0x67980fd9, 0xc9def15e,
1340 0x9cc51eb9, 0xdaa7aa6b, 0x78e6871f, 0x0d5d2cb2, 0x7aedf15e, 0x9bcaf15e, 0xe5f7f15e, 0x501c1759,
1341 0xdfbc4980, 0xa7397f2e, 0x31ea1a02, 0x3a27655e, 0xaa86f05c, 0xdcddf15e, 0x64689cb2, 0xd4bf62d4,
1342 0xf093eab2, 0x98def15e, 0xb6c5f15e, 0x81e8f15e, 0xe5d2fe59, 0xa312786d, 0x4cf9fe59, 0x8a922c1f,
1343 0x00c7fe59, 0x1ade565f, 0x9e4116b2, 0x2c36983e, 0x68f8f15e, 0x51b7eab2, 0x76c51eb9, 0x9edd4980,
1344 0x90ef565f, 0x0dd80857, 0xd513fb94, 0xf5bdeab2, 0xa95277b0, 0x2cf2f15e, 0x1897eab2, 0x924416b2,
1345 0x985c9b59, 0x30aa43d8, 0xf9c6745f, 0xaf862e5f, 0xe0ceeab2, 0xb9b3eab2, 0x6da4eab2, 0xa4fdeab2,
1346 0x0fa6c125, 0xe38bbd05, 0x5d922c1f, 0x9bd0eab2, 0x73025e02, 0xc4fd794d, 0x8435b35f, 0x2d01bc2e,
1347 0xaa2a14d4, 0xa22b07cb, 0xebda6f4f, 0xddc6514e, 0xf23feab2, 0xea1e5256, 0x6147b45e, 0x47d21e4f,
1348 0x67c41c1f, 0x53ec1a02, 0x352e786d, 0x6bec1a02, 0x78fb4abe, 0xd3014c5d, 0x9fbbeab2, 0x1fc51eb9,
1349 0x720eeab2, 0x2db5eab2, 0xe8baf65c, 0x521b459e, 0x65c4955f, 0x0e7b915f, 0xa8f37e6d, 0x6d0b465f,
1350 0xfab8ff5c, 0xf7c27e6d, 0x7345a846, 0x4fd1a7d5, 0xdfc97e6d, 0x26c27e6d, 0xa9de36b2, 0xc615344d,
1351 0x28ceb95d, 0xa52d895e, 0x18c17e6d, 0x13ec1a02, 0x0ba37125, 0x6c3d344d, 0xb3922c1f, 0x506bbeb0,
1352 0x4d04994e, 0xa1bbe56d, 0xf62c344d, 0x0847d048, 0x4bdc6451, 0xc95b9a05, 0xbcd3a7d5, 0x29b57125,
1353 0x0c4d2cb2, 0xf2b8eab2, 0xc2d5b95d, 0x0185ef59, 0x30adeab2, 0xcaf0e92e, 0x756c344d, 0xfd9e252e,
1354 0xbe5ef3bc, 0x4689344d, 0xb223895e, 0xfcebeaad, 0xb7c0e92e, 0x993c1760, 0xe1e171b0, 0xb857e75b,
1355 0xbf10002e, 0xb55b2cb2, 0xa90e2cb2, 0x13d6f15e, 0xf8be9225, 0x14ddf15e, 0x06e90305, 0x82472cb2,
1357 vector<CAddress> vAdd;
1358 for (unsigned int i = 0; i < vnSeed.size(); i++)
1360 // It'll only connect to one or two seed nodes because once it connects,
1361 // it'll get a pile of addresses with newer timestamps.
1362 // Seed nodes are given a random 'last seen time' of between one and two
1365 memcpy(&ip, &vnSeed[i], sizeof(ip));
1366 CAddress addr(CService(ip, GetDefaultPort()));
1367 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1368 vAdd.push_back(addr);
1370 addrman.Add(vAdd, CNetAddr("127.0.0.1"));
1373 // Add Tor nodes if we have connection with onion router
1374 if (mapArgs.count("-tor"))
1376 const vector<string> vstrTorSeed =
1378 "seedp4knqnoei57u.onion",
1379 "seedr3hhlepyi7fd.onion",
1380 "seed3uuomkclbiz4.onion",
1381 "seedeh7qck3ouff5.onion",
1382 "5rg3vq4jagckeckf.onion",
1383 "seedt3sraf53ajiy.onion",
1384 "seedg4qyccsg42oq.onion",
1385 "novaqrtoywpg7jly.onion",
1386 "seed3d5wolqbgrcb.onion",
1387 "seed24u5dwph3qw4.onion",
1388 "mj26ulzbs2oskgym.onion",
1389 "eqon4usunavt76m7.onion",
1390 "seedd3aldwpslzl3.onion"
1392 vector<CAddress> vAdd;
1393 for (unsigned int i = 0; i < vstrTorSeed.size(); i++)
1395 CAddress addr(CService(vstrTorSeed[i], GetDefaultPort()));
1396 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1397 vAdd.push_back(addr);
1399 addrman.Add(vAdd, CNetAddr("dummyaddress.onion"));
1403 // Choose an address to connect to based on most recently seen
1405 CAddress addrConnect;
1407 // Only connect out to one peer per network group (/16 for IPv4).
1408 // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
1410 set<vector<unsigned char> > setConnected;
1413 for(CNode* pnode : vNodes) {
1414 if (!pnode->fInbound) {
1415 setConnected.insert(pnode->addr.GetGroup());
1421 auto nANow = GetAdjustedTime();
1426 // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
1427 auto addr = addrman.Select(10 + min(nOutbound,8)*10);
1429 // if we selected an invalid address, restart
1430 if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
1433 // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
1434 // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
1435 // already-connected network ranges, ...) before trying new addrman addresses.
1440 if (IsLimited(addr))
1443 // only consider very recently tried nodes after 30 failed attempts
1444 if (nANow - addr.nLastTry < 600 && nTries < 30)
1447 // do not allow non-default ports, unless after 50 invalid addresses selected already
1448 if (addr.GetPort() != GetDefaultPort() && nTries < 50)
1455 if (addrConnect.IsValid())
1456 OpenNetworkConnection(addrConnect, &grant);
1460 void ThreadOpenAddedConnections(void* parg)
1462 // Make this thread recognisable as the connection opening thread
1463 RenameThread("novacoin-opencon");
1467 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1468 ThreadOpenAddedConnections2(parg);
1469 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1471 catch (exception& e) {
1472 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1473 PrintException(&e, "ThreadOpenAddedConnections()");
1475 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1476 PrintException(NULL, "ThreadOpenAddedConnections()");
1478 printf("ThreadOpenAddedConnections exited\n");
1481 void ThreadOpenAddedConnections2(void* parg)
1483 printf("ThreadOpenAddedConnections started\n");
1486 LOCK(cs_vAddedNodes);
1487 vAddedNodes = mapMultiArgs["-addnode"];
1490 if (HaveNameProxy()) {
1492 list<string> lAddresses(0);
1494 LOCK(cs_vAddedNodes);
1495 for(string& strAddNode : vAddedNodes)
1496 lAddresses.push_back(strAddNode);
1498 for(string& strAddNode : lAddresses) {
1500 CSemaphoreGrant grant(*semOutbound);
1501 OpenNetworkConnection(addr, &grant, strAddNode.c_str());
1504 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1505 Sleep(120000); // Retry every 2 minutes
1506 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1511 for (uint32_t i = 0; true; i++)
1513 list<string> lAddresses(0);
1515 LOCK(cs_vAddedNodes);
1516 for(string& strAddNode : vAddedNodes)
1517 lAddresses.push_back(strAddNode);
1520 list<vector<CService> > lservAddressesToAdd(0);
1521 for(string& strAddNode : lAddresses)
1523 vector<CService> vservNode(0);
1524 if (Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
1526 lservAddressesToAdd.push_back(vservNode);
1528 LOCK(cs_setservAddNodeAddresses);
1529 for(CService& serv : vservNode)
1530 setservAddNodeAddresses.insert(serv);
1534 // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
1535 // (keeping in mind that addnode entries can have many IPs if fNameLookup)
1538 for(CNode* pnode : vNodes)
1539 for (auto it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
1541 for(CService& addrNode : *(it))
1542 if (pnode->addr == addrNode)
1544 it = lservAddressesToAdd.erase(it);
1545 if(it != lservAddressesToAdd.begin())
1549 if (it == lservAddressesToAdd.end())
1553 for(vector<CService>& vserv : lservAddressesToAdd)
1555 if (vserv.size() == 0)
1557 CSemaphoreGrant grant(*semOutbound);
1558 OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
1565 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1566 Sleep(120000); // Retry every 2 minutes
1567 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1573 // if successful, this moves the passed grant to the constructed node
1574 bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot)
1577 // Initiate outbound network connection
1582 if (IsLocal(addrConnect) ||
1583 FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
1584 FindNode(addrConnect.ToStringIPPort().c_str()))
1586 if (strDest && FindNode(strDest))
1589 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1590 CNode* pnode = ConnectNode(addrConnect, strDest);
1591 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1597 grantOutbound->MoveTo(pnode->grantOutbound);
1598 pnode->fNetworkNode = true;
1600 pnode->fOneShot = true;
1605 // for now, use a very simple selection metric: the node from which we received
1607 static int64_t NodeSyncScore(const CNode *pnode) {
1608 return pnode->nLastRecv;
1611 void static StartSync(const vector<CNode*> &vNodes) {
1612 CNode *pnodeNewSync = NULL;
1613 int64_t nBestScore = 0;
1615 // Iterate over all nodes
1616 for(CNode* pnode : vNodes) {
1617 // check preconditions for allowing a sync
1618 if (!pnode->fClient && !pnode->fOneShot &&
1619 !pnode->fDisconnect && pnode->fSuccessfullyConnected &&
1620 (pnode->nStartingHeight > (nBestHeight - 144)) &&
1621 (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
1622 // if ok, compare node's score with the best so far
1623 int64_t nScore = NodeSyncScore(pnode);
1624 if (pnodeNewSync == NULL || nScore > nBestScore) {
1625 pnodeNewSync = pnode;
1626 nBestScore = nScore;
1630 // if a new sync candidate was found, start sync!
1632 pnodeNewSync->fStartSync = true;
1633 pnodeSync = pnodeNewSync;
1637 void ThreadMessageHandler(void* parg)
1639 // Make this thread recognisable as the message handling thread
1640 RenameThread("novacoin-msghand");
1644 vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1645 ThreadMessageHandler2(parg);
1646 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1648 catch (exception& e) {
1649 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1650 PrintException(&e, "ThreadMessageHandler()");
1652 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1653 PrintException(NULL, "ThreadMessageHandler()");
1655 printf("ThreadMessageHandler exited\n");
1658 void ThreadMessageHandler2(void* parg)
1660 printf("ThreadMessageHandler started\n");
1661 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1664 bool fHaveSyncNode = false;
1665 vector<CNode*> vNodesCopy;
1668 vNodesCopy = vNodes;
1669 for(CNode* pnode : vNodesCopy) {
1671 if (pnode == pnodeSync)
1672 fHaveSyncNode = true;
1677 StartSync(vNodesCopy);
1679 // Poll the connected nodes for messages
1680 for(CNode* pnode : vNodesCopy)
1684 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1686 ProcessMessages(pnode);
1693 TRY_LOCK(pnode->cs_vSend, lockSend);
1695 SendMessages(pnode);
1703 for(CNode* pnode : vNodesCopy)
1707 // Wait and allow messages to bunch up.
1708 // Reduce vnThreadsRunning so StopNode has permission to exit while
1709 // we're sleeping, but we must always check fShutdown after doing this.
1710 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1712 if (fRequestShutdown)
1714 vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1725 bool BindListenPort(const CService &addrBind, string& strError)
1730 // Create socket for listening for incoming connections
1731 struct sockaddr_storage sockaddr;
1732 socklen_t len = sizeof(sockaddr);
1733 if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
1735 strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
1736 printf("%s\n", strError.c_str());
1740 SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
1741 if (hListenSocket == INVALID_SOCKET)
1743 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1744 printf("%s\n", strError.c_str());
1750 // Different way of disabling SIGPIPE on BSD
1751 if (setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1753 printf("WARNING: setsockopt failed\n");
1754 //TODO: work around problem - may be add CloseSocket and return false?
1757 // Allow binding if the port is still in TIME_WAIT state after
1758 // the program was closed and restarted. Not an issue on windows!
1759 if (setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1761 printf("WARNING: setsockopt failed\n");
1762 //TODO: work around problem - may be add CloseSocket and return false?
1767 // Set to non-blocking, incoming connections will also inherit this
1768 if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
1770 if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
1773 strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1774 printf("%s\n", strError.c_str());
1775 CloseSocket(hListenSocket);
1779 // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
1780 // and enable it by default or not. Try to enable it, if possible.
1781 if (addrBind.IsIPv6()) {
1784 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int)) == SOCKET_ERROR)
1786 printf("WARNING: setsockopt failed\n");
1787 //TODO: work around problem - may be add CloseSocket and return false?
1790 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1792 printf("WARNING: setsockopt failed\n");
1793 //TODO: work around problem - may be add CloseSocket and return false?
1798 int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
1799 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)) == SOCKET_ERROR)
1801 printf("WARNING: setsockopt failed\n");
1802 //TODO: work around problem - may be add CloseSocket and return false?
1807 if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
1809 int nErr = WSAGetLastError();
1810 if (nErr == WSAEADDRINUSE)
1811 strError = strprintf(_("Unable to bind to %s on this computer. NovaCoin is probably already running."), addrBind.ToString().c_str());
1813 strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString().c_str(), NetworkErrorString(nErr).c_str());
1814 printf("%s\n", strError.c_str());
1815 CloseSocket(hListenSocket);
1818 printf("Bound to %s\n", addrBind.ToString().c_str());
1820 // Listen for incoming connections
1821 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1823 strError = strprintf("Error: Listening for incoming connections failed (listen returned error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1824 printf("%s\n", strError.c_str());
1825 CloseSocket(hListenSocket);
1829 vhListenSocket.push_back(hListenSocket);
1831 if (addrBind.IsRoutable() && fDiscover)
1832 AddLocal(addrBind, LOCAL_BIND);
1837 void static Discover()
1843 // Get local host IP
1844 char pszHostName[1000] = "";
1845 if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1847 vector<CNetAddr> vaddr;
1848 if (LookupHost(pszHostName, vaddr))
1850 for(const auto &addr : vaddr)
1852 AddLocal(addr, LOCAL_IF);
1857 // Get local host ip
1858 struct ifaddrs* myaddrs;
1859 if (getifaddrs(&myaddrs) == 0)
1861 for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1863 if (ifa->ifa_addr == NULL) continue;
1864 if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1865 if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1866 if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
1867 if (ifa->ifa_addr->sa_family == AF_INET)
1869 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
1870 CNetAddr addr(s4->sin_addr);
1871 if (AddLocal(addr, LOCAL_IF))
1872 printf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1874 else if (ifa->ifa_addr->sa_family == AF_INET6)
1876 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
1877 CNetAddr addr(s6->sin6_addr);
1878 if (AddLocal(addr, LOCAL_IF))
1879 printf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1882 freeifaddrs(myaddrs);
1886 // Don't use external IPv4 discovery, when -onlynet="IPv6"
1887 if (!IsLimited(NET_IPV4))
1888 NewThread(ThreadGetMyExternalIP, NULL);
1891 void StartNode(void* parg)
1893 // Make this thread recognisable as the startup thread
1894 RenameThread("novacoin-start");
1896 if (semOutbound == NULL) {
1897 // initialize semaphore
1898 int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, GetArgInt("-maxconnections", 125));
1899 semOutbound = new CSemaphore(nMaxOutbound);
1902 if (pnodeLocalHost == NULL)
1903 pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", nPortZero), nLocalServices));
1911 if (!GetBoolArg("-dnsseed", true))
1912 printf("DNS seeding disabled\n");
1914 if (!NewThread(ThreadDNSAddressSeed, NULL))
1915 printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
1917 // Get addresses from IRC and advertise ours
1918 if (!GetBoolArg("-irc", true))
1919 printf("IRC seeding disabled\n");
1921 if (!NewThread(ThreadIRCSeed, NULL))
1922 printf("Error: NewThread(ThreadIRCSeed) failed\n");
1924 // Send and receive from sockets, accept connections
1925 if (!NewThread(ThreadSocketHandler, NULL))
1926 printf("Error: NewThread(ThreadSocketHandler) failed\n");
1928 // Initiate outbound connections from -addnode
1929 if (!NewThread(ThreadOpenAddedConnections, NULL))
1930 printf("Error: NewThread(ThreadOpenAddedConnections) failed\n");
1932 // Initiate outbound connections
1933 if (!NewThread(ThreadOpenConnections, NULL))
1934 printf("Error: NewThread(ThreadOpenConnections) failed\n");
1937 if (!NewThread(ThreadMessageHandler, NULL))
1938 printf("Error: NewThread(ThreadMessageHandler) failed\n");
1940 // Dump network addresses
1941 if (!NewThread(ThreadDumpAddress, NULL))
1942 printf("Error; NewThread(ThreadDumpAddress) failed\n");
1944 // Mine proof-of-stake blocks in the background
1945 if (!NewThread(ThreadStakeMiner, pwalletMain))
1946 printf("Error: NewThread(ThreadStakeMiner) failed\n");
1948 // Trusted NTP server, it's localhost by default.
1949 strTrustedUpstream = GetArg("-ntp", "localhost");
1951 // Start periodical NTP sampling thread
1952 NewThread(ThreadNtpSamples, NULL);
1958 printf("StopNode()\n");
1960 nTransactionsUpdated++;
1961 auto nStart = GetTime();
1964 ThreadScriptCheckQuit();
1967 for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
1968 semOutbound->post();
1971 int nThreadsRunning = 0;
1972 for (int n = 0; n < THREAD_MAX; n++)
1973 nThreadsRunning += vnThreadsRunning[n];
1974 if (nThreadsRunning == 0)
1976 if (GetTime() - nStart > 20)
1980 if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
1981 if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
1982 if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
1983 if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n");
1984 if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n");
1985 if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
1986 if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
1987 if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
1988 if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStakeMinter still running\n");
1989 if (vnThreadsRunning[THREAD_SCRIPTCHECK] > 0) printf("ThreadScriptCheck still running\n");
1990 while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0 || vnThreadsRunning[THREAD_SCRIPTCHECK] > 0)
2007 for(CNode* pnode : vNodes)
2008 if (pnode->hSocket != INVALID_SOCKET)
2009 CloseSocket(pnode->hSocket);
2010 for(SOCKET hListenSocket : vhListenSocket)
2011 if (hListenSocket != INVALID_SOCKET)
2012 if (!CloseSocket(hListenSocket))
2013 printf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()).c_str());
2015 // clean up some globals (to help leak detection)
2016 for(CNode *pnode : vNodes)
2018 for(CNode *pnode : vNodesDisconnected)
2021 vNodesDisconnected.clear();
2024 delete pnodeLocalHost;
2025 pnodeLocalHost = NULL;
2028 // Shutdown Windows Sockets
2033 instance_of_cnetcleanup;
2035 inline void RelayInventory(const CInv& inv)
2037 // Put on lists to offer to the other nodes
2040 for(CNode* pnode : vNodes)
2041 pnode->PushInventory(inv);
2045 void RelayTransaction(const CTransaction& tx, const uint256& hash)
2047 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2050 RelayTransaction(tx, hash, ss);
2053 void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
2055 CInv inv(MSG_TX, hash);
2058 // Expire old relay messages
2059 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
2061 mapRelay.erase(vRelayExpiration.front().second);
2062 vRelayExpiration.pop_front();
2065 // Save original serialized message so newer versions are preserved
2066 mapRelay.insert({inv, ss});
2067 vRelayExpiration.push_back({GetTime() + 15 * 60, inv});
2070 RelayInventory(inv);
2073 void CNode::RecordBytesRecv(uint64_t bytes)
2075 LOCK(cs_totalBytesRecv);
2076 nTotalBytesRecv += bytes;
2079 void CNode::RecordBytesSent(uint64_t bytes)
2081 LOCK(cs_totalBytesSent);
2082 nTotalBytesSent += bytes;
2085 uint64_t CNode::GetTotalBytesRecv()
2087 LOCK(cs_totalBytesRecv);
2088 return nTotalBytesRecv;
2091 uint64_t CNode::GetTotalBytesSent()
2093 LOCK(cs_totalBytesSent);
2094 return nTotalBytesSent;
2097 int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
2098 return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);