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()
726 bool CNode::IsBanned(const CNetAddr& ip)
728 bool fResult = false;
731 auto i = setBanned.find(ip);
732 if (i != setBanned.end())
734 auto t = (*i).second;
742 bool CNode::Misbehaving(int howmuch)
746 printf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch);
750 nMisbehavior += howmuch;
751 if (nMisbehavior >= GetArgInt("-banscore", 100))
753 auto banTime = GetTime()+GetArg("-bantime", nOneDay); // Default 24-hour ban
754 printf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
757 if (setBanned[addr] < banTime)
758 setBanned[addr] = banTime;
760 CloseSocketDisconnect();
763 printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
768 #define X(name) stats.name = name
769 void CNode::copyStats(CNodeStats &stats)
784 stats.fSyncNode = (this == pnodeSync);
789 void ThreadSocketHandler(void* parg)
791 // Make this thread recognisable as the networking thread
792 RenameThread("novacoin-net");
796 vnThreadsRunning[THREAD_SOCKETHANDLER]++;
797 ThreadSocketHandler2(parg);
798 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
800 catch (exception& e) {
801 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
802 PrintException(&e, "ThreadSocketHandler()");
804 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
805 throw; // support pthread_cancel()
807 printf("ThreadSocketHandler exited\n");
810 static list<CNode*> vNodesDisconnected;
812 void ThreadSocketHandler2(void* parg)
814 printf("ThreadSocketHandler started\n");
815 size_t nPrevNodeCount = 0;
823 // Disconnect unused nodes
824 vector<CNode*> vNodesCopy = vNodes;
825 for(CNode* pnode : vNodesCopy)
827 if (pnode->fDisconnect ||
828 (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
830 // remove from vNodes
831 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
833 // release outbound grant (if any)
834 pnode->grantOutbound.Release();
836 // close socket and cleanup
837 pnode->CloseSocketDisconnect();
840 // hold in disconnected pool until all refs are released
841 pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
842 if (pnode->fNetworkNode || pnode->fInbound)
844 vNodesDisconnected.push_back(pnode);
848 // Delete disconnected nodes
849 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
850 for(CNode* pnode : vNodesDisconnectedCopy)
852 // wait until threads are done using it
853 if (pnode->GetRefCount() <= 0)
855 bool fDelete = false;
857 TRY_LOCK(pnode->cs_vSend, lockSend);
860 TRY_LOCK(pnode->cs_vRecv, lockRecv);
863 TRY_LOCK(pnode->cs_mapRequests, lockReq);
866 TRY_LOCK(pnode->cs_inventory, lockInv);
875 vNodesDisconnected.remove(pnode);
881 if (vNodes.size() != nPrevNodeCount)
883 nPrevNodeCount = vNodes.size();
884 uiInterface.NotifyNumConnectionsChanged(vNodes.size());
889 // Find which sockets have data to receive
891 struct timeval timeout;
893 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
900 FD_ZERO(&fdsetError);
901 SOCKET hSocketMax = 0;
902 bool have_fds = false;
904 for(SOCKET hListenSocket : vhListenSocket) {
905 FD_SET(hListenSocket, &fdsetRecv);
906 hSocketMax = max(hSocketMax, hListenSocket);
911 for(CNode* pnode : vNodes)
913 if (pnode->hSocket == INVALID_SOCKET)
915 FD_SET(pnode->hSocket, &fdsetRecv);
916 FD_SET(pnode->hSocket, &fdsetError);
917 hSocketMax = max(hSocketMax, pnode->hSocket);
920 TRY_LOCK(pnode->cs_vSend, lockSend);
921 if (lockSend && !pnode->vSend.empty())
922 FD_SET(pnode->hSocket, &fdsetSend);
927 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
928 int nSelect = select(have_fds ? hSocketMax + 1 : 0,
929 &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
930 vnThreadsRunning[THREAD_SOCKETHANDLER]++;
933 if (nSelect == SOCKET_ERROR)
937 int nErr = WSAGetLastError();
938 printf("socket select error %s\n", NetworkErrorString(nErr).c_str());
939 for (unsigned int i = 0; i <= hSocketMax; i++)
940 FD_SET(i, &fdsetRecv);
943 FD_ZERO(&fdsetError);
944 Sleep(timeout.tv_usec/1000);
949 // Accept new connections
951 for(SOCKET hListenSocket : vhListenSocket)
952 if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
954 struct sockaddr_storage sockaddr;
955 socklen_t len = sizeof(sockaddr);
956 SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
960 if (hSocket != INVALID_SOCKET)
961 if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
962 printf("Warning: Unknown socket family\n");
966 for(CNode* pnode : vNodes)
971 if (hSocket == INVALID_SOCKET)
973 int nErr = WSAGetLastError();
974 if (nErr != WSAEWOULDBLOCK)
975 printf("socket error accept failed: %s\n", NetworkErrorString(nErr).c_str());
977 else if (nInbound >= GetArgInt("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
979 printf("connection from %s dropped (overall limit)\n", addr.ToString().c_str());
980 CloseSocket(hSocket);
982 else if (CNode::IsBanned(addr))
984 printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
985 CloseSocket(hSocket);
989 printf("accepted connection %s\n", addr.ToString().c_str());
990 CNode* pnode = new CNode(hSocket, addr, "", true);
994 vNodes.push_back(pnode);
1001 // Service each socket
1003 vector<CNode*> vNodesCopy;
1006 vNodesCopy = vNodes;
1007 for(CNode* pnode : vNodesCopy)
1010 for(CNode* pnode : vNodesCopy)
1018 if (pnode->hSocket == INVALID_SOCKET)
1020 if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
1022 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1025 CDataStream& vRecv = pnode->vRecv;
1026 uint64_t nPos = vRecv.size();
1028 if (nPos > ReceiveBufferSize()) {
1029 if (!pnode->fDisconnect)
1030 printf("socket recv flood control disconnect (%" PRIszu " bytes)\n", vRecv.size());
1031 pnode->CloseSocketDisconnect();
1034 // typical socket buffer is 8K-64K
1035 char pchBuf[0x10000];
1036 int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
1039 vRecv.resize(nPos + nBytes);
1040 memcpy(&vRecv[nPos], pchBuf, nBytes);
1041 pnode->nLastRecv = GetTime();
1042 pnode->nRecvBytes += nBytes;
1043 pnode->RecordBytesRecv(nBytes);
1045 else if (nBytes == 0)
1047 // socket closed gracefully
1048 if (!pnode->fDisconnect)
1049 printf("socket closed\n");
1050 pnode->CloseSocketDisconnect();
1052 else if (nBytes < 0)
1055 int nErr = WSAGetLastError();
1056 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
1058 if (!pnode->fDisconnect)
1059 printf("socket recv error %s\n", NetworkErrorString(nErr).c_str());
1060 pnode->CloseSocketDisconnect();
1070 if (pnode->hSocket == INVALID_SOCKET)
1072 if (FD_ISSET(pnode->hSocket, &fdsetSend))
1074 TRY_LOCK(pnode->cs_vSend, lockSend);
1077 CDataStream& vSend = pnode->vSend;
1080 int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
1083 vSend.erase(vSend.begin(), vSend.begin() + nBytes);
1084 pnode->nLastSend = GetTime();
1085 pnode->nSendBytes += nBytes;
1086 pnode->RecordBytesSent(nBytes);
1088 else if (nBytes < 0)
1091 int nErr = WSAGetLastError();
1092 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
1094 printf("socket send error %s\n", NetworkErrorString(nErr).c_str());
1095 pnode->CloseSocketDisconnect();
1103 // Inactivity checking
1105 if (pnode->vSend.empty())
1106 pnode->nLastSendEmpty = GetTime();
1107 if (GetTime() - pnode->nTimeConnected > 60)
1109 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
1111 printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
1112 pnode->fDisconnect = true;
1114 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
1116 printf("socket not sending\n");
1117 pnode->fDisconnect = true;
1119 else if (GetTime() - pnode->nLastRecv > 90*60)
1121 printf("socket inactivity timeout\n");
1122 pnode->fDisconnect = true;
1128 for(CNode* pnode : vNodesCopy)
1136 void ThreadDNSAddressSeed(void* parg)
1138 // Make this thread recognisable as the DNS seeding thread
1139 RenameThread("novacoin-dnsseed");
1143 vnThreadsRunning[THREAD_DNSSEED]++;
1144 ThreadDNSAddressSeed2(parg);
1145 vnThreadsRunning[THREAD_DNSSEED]--;
1147 catch (exception& e) {
1148 vnThreadsRunning[THREAD_DNSSEED]--;
1149 PrintException(&e, "ThreadDNSAddressSeed()");
1151 vnThreadsRunning[THREAD_DNSSEED]--;
1152 throw; // support pthread_cancel()
1154 printf("ThreadDNSAddressSeed exited\n");
1157 void ThreadDNSAddressSeed2(void* parg)
1159 printf("ThreadDNSAddressSeed started\n");
1165 // Each pair gives a source name and a seed name.
1166 // The first name is used as information source for addrman.
1167 // The second name should resolve to a list of seed addresses.
1168 static const vector<pair <string, string> > vstrDNSSeed = {
1169 { "node.novacoin.karelia.pro", "dnsseed.novacoin.karelia.pro" },
1170 { "novacoin.ru", "dnsseed.novacoin.ru" },
1171 { "novacoin.ru", "testseed.novacoin.ru" },
1172 { "novaco.in", "dnsseed.novaco.in" },
1174 printf("Loading addresses from DNS seeds (could take a while)\n");
1176 for (unsigned int seed_idx = 0; seed_idx < vstrDNSSeed.size(); seed_idx++) {
1177 if (HaveNameProxy()) {
1178 AddOneShot(vstrDNSSeed[seed_idx].second);
1180 vector<CNetAddr> vaddr;
1181 vector<CAddress> vAdd;
1182 if (LookupHost(vstrDNSSeed[seed_idx].second, vaddr))
1184 for(CNetAddr& ip : vaddr)
1186 auto addr = CAddress(CService(ip, GetDefaultPort()));
1187 addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
1188 vAdd.push_back(addr);
1192 addrman.Add(vAdd, CNetAddr(vstrDNSSeed[seed_idx].first, true));
1197 printf("%d addresses found from DNS seeds\n", found);
1200 void DumpAddresses()
1202 auto nStart = GetTimeMillis();
1207 printf("Flushed %d addresses to peers.dat %" PRId64 "ms\n",
1208 addrman.size(), GetTimeMillis() - nStart);
1211 void ThreadDumpAddress2(void* parg)
1213 printf("ThreadDumpAddress started\n");
1215 vnThreadsRunning[THREAD_DUMPADDRESS]++;
1219 vnThreadsRunning[THREAD_DUMPADDRESS]--;
1221 vnThreadsRunning[THREAD_DUMPADDRESS]++;
1223 vnThreadsRunning[THREAD_DUMPADDRESS]--;
1226 void ThreadDumpAddress(void* parg)
1228 // Make this thread recognisable as the address dumping thread
1229 RenameThread("novacoin-adrdump");
1233 ThreadDumpAddress2(parg);
1235 catch (exception& e) {
1236 PrintException(&e, "ThreadDumpAddress()");
1238 printf("ThreadDumpAddress exited\n");
1241 void ThreadOpenConnections(void* parg)
1243 // Make this thread recognisable as the connection opening thread
1244 RenameThread("novacoin-opencon");
1248 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1249 ThreadOpenConnections2(parg);
1250 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1252 catch (exception& e) {
1253 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1254 PrintException(&e, "ThreadOpenConnections()");
1256 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1257 PrintException(NULL, "ThreadOpenConnections()");
1259 printf("ThreadOpenConnections exited\n");
1262 void static ProcessOneShot()
1267 if (vOneShots.empty())
1269 strDest = vOneShots.front();
1270 vOneShots.pop_front();
1273 CSemaphoreGrant grant(*semOutbound, true);
1275 if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true))
1276 AddOneShot(strDest);
1280 void ThreadOpenConnections2(void* parg)
1282 printf("ThreadOpenConnections started\n");
1284 // Connect to specific addresses
1285 if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
1287 for (int64_t nLoop = 0;; nLoop++)
1290 for(string strAddr : mapMultiArgs["-connect"])
1293 OpenNetworkConnection(addr, NULL, strAddr.c_str());
1294 for (int i = 0; i < 10 && i < nLoop; i++)
1305 // Initiate network connections
1306 auto nStart = GetTime();
1311 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1313 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1318 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1319 CSemaphoreGrant grant(*semOutbound);
1320 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1324 // Add seed nodes if IRC isn't working
1325 if (!IsLimited(NET_IPV4) && addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
1327 vector<uint32_t> vnSeed =
1329 0x1c542868, 0x3859dd6f, 0x203c2e68, 0xf145a6bc, 0x638a545f, 0x325da346, 0x385da346, 0xfb2b8d5f,
1330 0x52568c5f, 0xa979e65b, 0x8de6485d, 0x9f79e65b, 0x048a861f, 0x3388b55f, 0x6ff0b45e, 0x17e81f5f,
1331 0x6c47bb25, 0x1ecdc852, 0x28263db9, 0x47824e5d, 0x36f1c851, 0x2bf913b2, 0x95923cb3, 0x84e63eb2,
1332 0xefdeedbf, 0x65200092, 0xf36f6805, 0x42692d05, 0x772c1955, 0xb6bf1b4e, 0x7abb5f5d, 0xdb2fa6bc,
1333 0x90e911bf, 0x82de565f, 0x694416b2, 0x0ab600bc, 0xfcecbe6d, 0x24ed9fb2, 0x1bb618c2, 0xc64765bb,
1334 0x4e3d62c3, 0xdba24baa, 0x4b7109b0, 0x12a12cc2, 0xfc01864f, 0x0b69e85b, 0x33922c1f, 0xac611bc6,
1335 0x2a257155, 0x991d5fc0, 0xbfdabcb1, 0x9b73ee55, 0x5bc2b95d, 0xdef0762e, 0x6ab7c936, 0x9c4416b2,
1336 0xd60d864f, 0x03671f1f, 0x3b5da346, 0xc6f5c851, 0x5411b2d4, 0xe7c25702, 0x63474fb0, 0x7e11c854,
1337 0x52381d5f, 0x72fdfe59, 0x51599a05, 0xfb12b2d4, 0xaee4f15e, 0xd0e3f15e, 0x2aa2805f, 0xa1caf15e,
1338 0x34fe425e, 0x46e1f15e, 0xd7c71955, 0xaeeff15e, 0x47c2af55, 0x563d89b2, 0x67980fd9, 0xc9def15e,
1339 0x9cc51eb9, 0xdaa7aa6b, 0x78e6871f, 0x0d5d2cb2, 0x7aedf15e, 0x9bcaf15e, 0xe5f7f15e, 0x501c1759,
1340 0xdfbc4980, 0xa7397f2e, 0x31ea1a02, 0x3a27655e, 0xaa86f05c, 0xdcddf15e, 0x64689cb2, 0xd4bf62d4,
1341 0xf093eab2, 0x98def15e, 0xb6c5f15e, 0x81e8f15e, 0xe5d2fe59, 0xa312786d, 0x4cf9fe59, 0x8a922c1f,
1342 0x00c7fe59, 0x1ade565f, 0x9e4116b2, 0x2c36983e, 0x68f8f15e, 0x51b7eab2, 0x76c51eb9, 0x9edd4980,
1343 0x90ef565f, 0x0dd80857, 0xd513fb94, 0xf5bdeab2, 0xa95277b0, 0x2cf2f15e, 0x1897eab2, 0x924416b2,
1344 0x985c9b59, 0x30aa43d8, 0xf9c6745f, 0xaf862e5f, 0xe0ceeab2, 0xb9b3eab2, 0x6da4eab2, 0xa4fdeab2,
1345 0x0fa6c125, 0xe38bbd05, 0x5d922c1f, 0x9bd0eab2, 0x73025e02, 0xc4fd794d, 0x8435b35f, 0x2d01bc2e,
1346 0xaa2a14d4, 0xa22b07cb, 0xebda6f4f, 0xddc6514e, 0xf23feab2, 0xea1e5256, 0x6147b45e, 0x47d21e4f,
1347 0x67c41c1f, 0x53ec1a02, 0x352e786d, 0x6bec1a02, 0x78fb4abe, 0xd3014c5d, 0x9fbbeab2, 0x1fc51eb9,
1348 0x720eeab2, 0x2db5eab2, 0xe8baf65c, 0x521b459e, 0x65c4955f, 0x0e7b915f, 0xa8f37e6d, 0x6d0b465f,
1349 0xfab8ff5c, 0xf7c27e6d, 0x7345a846, 0x4fd1a7d5, 0xdfc97e6d, 0x26c27e6d, 0xa9de36b2, 0xc615344d,
1350 0x28ceb95d, 0xa52d895e, 0x18c17e6d, 0x13ec1a02, 0x0ba37125, 0x6c3d344d, 0xb3922c1f, 0x506bbeb0,
1351 0x4d04994e, 0xa1bbe56d, 0xf62c344d, 0x0847d048, 0x4bdc6451, 0xc95b9a05, 0xbcd3a7d5, 0x29b57125,
1352 0x0c4d2cb2, 0xf2b8eab2, 0xc2d5b95d, 0x0185ef59, 0x30adeab2, 0xcaf0e92e, 0x756c344d, 0xfd9e252e,
1353 0xbe5ef3bc, 0x4689344d, 0xb223895e, 0xfcebeaad, 0xb7c0e92e, 0x993c1760, 0xe1e171b0, 0xb857e75b,
1354 0xbf10002e, 0xb55b2cb2, 0xa90e2cb2, 0x13d6f15e, 0xf8be9225, 0x14ddf15e, 0x06e90305, 0x82472cb2,
1356 vector<CAddress> vAdd;
1357 for (unsigned int i = 0; i < vnSeed.size(); i++)
1359 // It'll only connect to one or two seed nodes because once it connects,
1360 // it'll get a pile of addresses with newer timestamps.
1361 // Seed nodes are given a random 'last seen time' of between one and two
1364 memcpy(&ip, &vnSeed[i], sizeof(ip));
1365 CAddress addr(CService(ip, GetDefaultPort()));
1366 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1367 vAdd.push_back(addr);
1369 addrman.Add(vAdd, CNetAddr("127.0.0.1"));
1372 // Add Tor nodes if we have connection with onion router
1373 if (mapArgs.count("-tor"))
1375 const vector<string> vstrTorSeed =
1377 "seedp4knqnoei57u.onion",
1378 "seedr3hhlepyi7fd.onion",
1379 "seed3uuomkclbiz4.onion",
1380 "seedeh7qck3ouff5.onion",
1381 "5rg3vq4jagckeckf.onion",
1382 "seedt3sraf53ajiy.onion",
1383 "seedg4qyccsg42oq.onion",
1384 "novaqrtoywpg7jly.onion",
1385 "seed3d5wolqbgrcb.onion",
1386 "seed24u5dwph3qw4.onion",
1387 "mj26ulzbs2oskgym.onion",
1388 "eqon4usunavt76m7.onion",
1389 "seedd3aldwpslzl3.onion"
1391 vector<CAddress> vAdd;
1392 for (unsigned int i = 0; i < vstrTorSeed.size(); i++)
1394 CAddress addr(CService(vstrTorSeed[i], GetDefaultPort()));
1395 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1396 vAdd.push_back(addr);
1398 addrman.Add(vAdd, CNetAddr("dummyaddress.onion"));
1402 // Choose an address to connect to based on most recently seen
1404 CAddress addrConnect;
1406 // Only connect out to one peer per network group (/16 for IPv4).
1407 // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
1409 set<vector<unsigned char> > setConnected;
1412 for(CNode* pnode : vNodes) {
1413 if (!pnode->fInbound) {
1414 setConnected.insert(pnode->addr.GetGroup());
1420 auto nANow = GetAdjustedTime();
1425 // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
1426 auto addr = addrman.Select(10 + min(nOutbound,8)*10);
1428 // if we selected an invalid address, restart
1429 if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
1432 // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
1433 // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
1434 // already-connected network ranges, ...) before trying new addrman addresses.
1439 if (IsLimited(addr))
1442 // only consider very recently tried nodes after 30 failed attempts
1443 if (nANow - addr.nLastTry < 600 && nTries < 30)
1446 // do not allow non-default ports, unless after 50 invalid addresses selected already
1447 if (addr.GetPort() != GetDefaultPort() && nTries < 50)
1454 if (addrConnect.IsValid())
1455 OpenNetworkConnection(addrConnect, &grant);
1459 void ThreadOpenAddedConnections(void* parg)
1461 // Make this thread recognisable as the connection opening thread
1462 RenameThread("novacoin-opencon");
1466 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1467 ThreadOpenAddedConnections2(parg);
1468 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1470 catch (exception& e) {
1471 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1472 PrintException(&e, "ThreadOpenAddedConnections()");
1474 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1475 PrintException(NULL, "ThreadOpenAddedConnections()");
1477 printf("ThreadOpenAddedConnections exited\n");
1480 void ThreadOpenAddedConnections2(void* parg)
1482 printf("ThreadOpenAddedConnections started\n");
1485 LOCK(cs_vAddedNodes);
1486 vAddedNodes = mapMultiArgs["-addnode"];
1489 if (HaveNameProxy()) {
1491 list<string> lAddresses(0);
1493 LOCK(cs_vAddedNodes);
1494 for(string& strAddNode : vAddedNodes)
1495 lAddresses.push_back(strAddNode);
1497 for(string& strAddNode : lAddresses) {
1499 CSemaphoreGrant grant(*semOutbound);
1500 OpenNetworkConnection(addr, &grant, strAddNode.c_str());
1503 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1504 Sleep(120000); // Retry every 2 minutes
1505 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1510 for (uint32_t i = 0; true; i++)
1512 list<string> lAddresses(0);
1514 LOCK(cs_vAddedNodes);
1515 for(string& strAddNode : vAddedNodes)
1516 lAddresses.push_back(strAddNode);
1519 list<vector<CService> > lservAddressesToAdd(0);
1520 for(string& strAddNode : lAddresses)
1522 vector<CService> vservNode(0);
1523 if (Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
1525 lservAddressesToAdd.push_back(vservNode);
1527 LOCK(cs_setservAddNodeAddresses);
1528 for(CService& serv : vservNode)
1529 setservAddNodeAddresses.insert(serv);
1533 // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
1534 // (keeping in mind that addnode entries can have many IPs if fNameLookup)
1537 for(CNode* pnode : vNodes)
1538 for (auto it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
1540 for(CService& addrNode : *(it))
1541 if (pnode->addr == addrNode)
1543 it = lservAddressesToAdd.erase(it);
1544 if(it != lservAddressesToAdd.begin())
1548 if (it == lservAddressesToAdd.end())
1552 for(vector<CService>& vserv : lservAddressesToAdd)
1554 if (vserv.size() == 0)
1556 CSemaphoreGrant grant(*semOutbound);
1557 OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
1564 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1565 Sleep(120000); // Retry every 2 minutes
1566 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1572 // if successful, this moves the passed grant to the constructed node
1573 bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot)
1576 // Initiate outbound network connection
1581 if (IsLocal(addrConnect) ||
1582 FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
1583 FindNode(addrConnect.ToStringIPPort().c_str()))
1585 if (strDest && FindNode(strDest))
1588 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1589 CNode* pnode = ConnectNode(addrConnect, strDest);
1590 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1596 grantOutbound->MoveTo(pnode->grantOutbound);
1597 pnode->fNetworkNode = true;
1599 pnode->fOneShot = true;
1604 // for now, use a very simple selection metric: the node from which we received
1606 static int64_t NodeSyncScore(const CNode *pnode) {
1607 return pnode->nLastRecv;
1610 void static StartSync(const vector<CNode*> &vNodes) {
1611 CNode *pnodeNewSync = NULL;
1612 int64_t nBestScore = 0;
1614 // Iterate over all nodes
1615 for(CNode* pnode : vNodes) {
1616 // check preconditions for allowing a sync
1617 if (!pnode->fClient && !pnode->fOneShot &&
1618 !pnode->fDisconnect && pnode->fSuccessfullyConnected &&
1619 (pnode->nStartingHeight > (nBestHeight - 144)) &&
1620 (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
1621 // if ok, compare node's score with the best so far
1622 int64_t nScore = NodeSyncScore(pnode);
1623 if (pnodeNewSync == NULL || nScore > nBestScore) {
1624 pnodeNewSync = pnode;
1625 nBestScore = nScore;
1629 // if a new sync candidate was found, start sync!
1631 pnodeNewSync->fStartSync = true;
1632 pnodeSync = pnodeNewSync;
1636 void ThreadMessageHandler(void* parg)
1638 // Make this thread recognisable as the message handling thread
1639 RenameThread("novacoin-msghand");
1643 vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1644 ThreadMessageHandler2(parg);
1645 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1647 catch (exception& e) {
1648 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1649 PrintException(&e, "ThreadMessageHandler()");
1651 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1652 PrintException(NULL, "ThreadMessageHandler()");
1654 printf("ThreadMessageHandler exited\n");
1657 void ThreadMessageHandler2(void* parg)
1659 printf("ThreadMessageHandler started\n");
1660 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1663 bool fHaveSyncNode = false;
1664 vector<CNode*> vNodesCopy;
1667 vNodesCopy = vNodes;
1668 for(CNode* pnode : vNodesCopy) {
1670 if (pnode == pnodeSync)
1671 fHaveSyncNode = true;
1676 StartSync(vNodesCopy);
1678 // Poll the connected nodes for messages
1679 for(CNode* pnode : vNodesCopy)
1683 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1685 ProcessMessages(pnode);
1692 TRY_LOCK(pnode->cs_vSend, lockSend);
1694 SendMessages(pnode);
1702 for(CNode* pnode : vNodesCopy)
1706 // Wait and allow messages to bunch up.
1707 // Reduce vnThreadsRunning so StopNode has permission to exit while
1708 // we're sleeping, but we must always check fShutdown after doing this.
1709 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1711 if (fRequestShutdown)
1713 vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1724 bool BindListenPort(const CService &addrBind, string& strError)
1729 // Create socket for listening for incoming connections
1730 struct sockaddr_storage sockaddr;
1731 socklen_t len = sizeof(sockaddr);
1732 if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
1734 strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
1735 printf("%s\n", strError.c_str());
1739 SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
1740 if (hListenSocket == INVALID_SOCKET)
1742 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1743 printf("%s\n", strError.c_str());
1749 // Different way of disabling SIGPIPE on BSD
1750 if (setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1752 printf("WARNING: setsockopt failed\n");
1753 //TODO: work around problem - may be add CloseSocket and return false?
1756 // Allow binding if the port is still in TIME_WAIT state after
1757 // the program was closed and restarted. Not an issue on windows!
1758 if (setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1760 printf("WARNING: setsockopt failed\n");
1761 //TODO: work around problem - may be add CloseSocket and return false?
1766 // Set to non-blocking, incoming connections will also inherit this
1767 if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
1769 if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
1772 strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1773 printf("%s\n", strError.c_str());
1774 CloseSocket(hListenSocket);
1778 // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
1779 // and enable it by default or not. Try to enable it, if possible.
1780 if (addrBind.IsIPv6()) {
1783 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int)) == SOCKET_ERROR)
1785 printf("WARNING: setsockopt failed\n");
1786 //TODO: work around problem - may be add CloseSocket and return false?
1789 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)) == SOCKET_ERROR)
1791 printf("WARNING: setsockopt failed\n");
1792 //TODO: work around problem - may be add CloseSocket and return false?
1797 int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
1798 if (setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)) == SOCKET_ERROR)
1800 printf("WARNING: setsockopt failed\n");
1801 //TODO: work around problem - may be add CloseSocket and return false?
1806 if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
1808 int nErr = WSAGetLastError();
1809 if (nErr == WSAEADDRINUSE)
1810 strError = strprintf(_("Unable to bind to %s on this computer. NovaCoin is probably already running."), addrBind.ToString().c_str());
1812 strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString().c_str(), NetworkErrorString(nErr).c_str());
1813 printf("%s\n", strError.c_str());
1814 CloseSocket(hListenSocket);
1817 printf("Bound to %s\n", addrBind.ToString().c_str());
1819 // Listen for incoming connections
1820 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1822 strError = strprintf("Error: Listening for incoming connections failed (listen returned error %s)", NetworkErrorString(WSAGetLastError()).c_str());
1823 printf("%s\n", strError.c_str());
1824 CloseSocket(hListenSocket);
1828 vhListenSocket.push_back(hListenSocket);
1830 if (addrBind.IsRoutable() && fDiscover)
1831 AddLocal(addrBind, LOCAL_BIND);
1836 void static Discover()
1842 // Get local host IP
1843 char pszHostName[1000] = "";
1844 if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1846 vector<CNetAddr> vaddr;
1847 if (LookupHost(pszHostName, vaddr))
1849 for(const auto &addr : vaddr)
1851 AddLocal(addr, LOCAL_IF);
1856 // Get local host ip
1857 struct ifaddrs* myaddrs;
1858 if (getifaddrs(&myaddrs) == 0)
1860 for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1862 if (ifa->ifa_addr == NULL) continue;
1863 if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1864 if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1865 if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
1866 if (ifa->ifa_addr->sa_family == AF_INET)
1868 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
1869 CNetAddr addr(s4->sin_addr);
1870 if (AddLocal(addr, LOCAL_IF))
1871 printf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1873 else if (ifa->ifa_addr->sa_family == AF_INET6)
1875 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
1876 CNetAddr addr(s6->sin6_addr);
1877 if (AddLocal(addr, LOCAL_IF))
1878 printf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1881 freeifaddrs(myaddrs);
1885 // Don't use external IPv4 discovery, when -onlynet="IPv6"
1886 if (!IsLimited(NET_IPV4))
1887 NewThread(ThreadGetMyExternalIP, NULL);
1890 void StartNode(void* parg)
1892 // Make this thread recognisable as the startup thread
1893 RenameThread("novacoin-start");
1895 if (semOutbound == NULL) {
1896 // initialize semaphore
1897 int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, GetArgInt("-maxconnections", 125));
1898 semOutbound = new CSemaphore(nMaxOutbound);
1901 if (pnodeLocalHost == NULL)
1902 pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", nPortZero), nLocalServices));
1910 if (!GetBoolArg("-dnsseed", true))
1911 printf("DNS seeding disabled\n");
1913 if (!NewThread(ThreadDNSAddressSeed, NULL))
1914 printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
1916 // Get addresses from IRC and advertise ours
1917 if (!GetBoolArg("-irc", true))
1918 printf("IRC seeding disabled\n");
1920 if (!NewThread(ThreadIRCSeed, NULL))
1921 printf("Error: NewThread(ThreadIRCSeed) failed\n");
1923 // Send and receive from sockets, accept connections
1924 if (!NewThread(ThreadSocketHandler, NULL))
1925 printf("Error: NewThread(ThreadSocketHandler) failed\n");
1927 // Initiate outbound connections from -addnode
1928 if (!NewThread(ThreadOpenAddedConnections, NULL))
1929 printf("Error: NewThread(ThreadOpenAddedConnections) failed\n");
1931 // Initiate outbound connections
1932 if (!NewThread(ThreadOpenConnections, NULL))
1933 printf("Error: NewThread(ThreadOpenConnections) failed\n");
1936 if (!NewThread(ThreadMessageHandler, NULL))
1937 printf("Error: NewThread(ThreadMessageHandler) failed\n");
1939 // Dump network addresses
1940 if (!NewThread(ThreadDumpAddress, NULL))
1941 printf("Error; NewThread(ThreadDumpAddress) failed\n");
1943 // Mine proof-of-stake blocks in the background
1944 if (!NewThread(ThreadStakeMiner, pwalletMain))
1945 printf("Error: NewThread(ThreadStakeMiner) failed\n");
1947 // Trusted NTP server, it's localhost by default.
1948 strTrustedUpstream = GetArg("-ntp", "localhost");
1950 // Start periodical NTP sampling thread
1951 NewThread(ThreadNtpSamples, NULL);
1957 printf("StopNode()\n");
1959 nTransactionsUpdated++;
1960 auto nStart = GetTime();
1963 ThreadScriptCheckQuit();
1966 for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
1967 semOutbound->post();
1970 int nThreadsRunning = 0;
1971 for (int n = 0; n < THREAD_MAX; n++)
1972 nThreadsRunning += vnThreadsRunning[n];
1973 if (nThreadsRunning == 0)
1975 if (GetTime() - nStart > 20)
1979 if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
1980 if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
1981 if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
1982 if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n");
1983 if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n");
1984 if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
1985 if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
1986 if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
1987 if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStakeMinter still running\n");
1988 if (vnThreadsRunning[THREAD_SCRIPTCHECK] > 0) printf("ThreadScriptCheck still running\n");
1989 while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0 || vnThreadsRunning[THREAD_SCRIPTCHECK] > 0)
2006 for(CNode* pnode : vNodes)
2007 if (pnode->hSocket != INVALID_SOCKET)
2008 CloseSocket(pnode->hSocket);
2009 for(SOCKET hListenSocket : vhListenSocket)
2010 if (hListenSocket != INVALID_SOCKET)
2011 if (!CloseSocket(hListenSocket))
2012 printf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()).c_str());
2014 // clean up some globals (to help leak detection)
2015 for(CNode *pnode : vNodes)
2017 for(CNode *pnode : vNodesDisconnected)
2020 vNodesDisconnected.clear();
2023 delete pnodeLocalHost;
2024 pnodeLocalHost = NULL;
2027 // Shutdown Windows Sockets
2032 instance_of_cnetcleanup;
2034 inline void RelayInventory(const CInv& inv)
2036 // Put on lists to offer to the other nodes
2039 for(CNode* pnode : vNodes)
2040 pnode->PushInventory(inv);
2044 void RelayTransaction(const CTransaction& tx, const uint256& hash)
2046 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2049 RelayTransaction(tx, hash, ss);
2052 void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
2054 CInv inv(MSG_TX, hash);
2057 // Expire old relay messages
2058 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
2060 mapRelay.erase(vRelayExpiration.front().second);
2061 vRelayExpiration.pop_front();
2064 // Save original serialized message so newer versions are preserved
2065 mapRelay.insert({inv, ss});
2066 vRelayExpiration.push_back({GetTime() + 15 * 60, inv});
2069 RelayInventory(inv);
2072 void CNode::RecordBytesRecv(uint64_t bytes)
2074 LOCK(cs_totalBytesRecv);
2075 nTotalBytesRecv += bytes;
2078 void CNode::RecordBytesSent(uint64_t bytes)
2080 LOCK(cs_totalBytesSent);
2081 nTotalBytesSent += bytes;
2084 uint64_t CNode::GetTotalBytesRecv()
2086 LOCK(cs_totalBytesRecv);
2087 return nTotalBytesRecv;
2090 uint64_t CNode::GetTotalBytesSent()
2092 LOCK(cs_totalBytesSent);
2093 return nTotalBytesSent;
2096 int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
2097 return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);