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.
12 #include "ui_interface.h"
19 #include <miniupnpc/miniwget.h>
20 #include <miniupnpc/miniupnpc.h>
21 #include <miniupnpc/upnpcommands.h>
22 #include <miniupnpc/upnperrors.h>
26 using namespace boost;
28 static const int MAX_OUTBOUND_CONNECTIONS = 16;
30 void ThreadMessageHandler2(void* parg);
31 void ThreadSocketHandler2(void* parg);
32 void ThreadOpenConnections2(void* parg);
33 void ThreadOpenAddedConnections2(void* parg);
35 void ThreadMapPort2(void* parg);
37 void ThreadDNSAddressSeed2(void* parg);
38 bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
41 struct LocalServiceInfo {
47 // Global state variables
50 bool fDiscover = true;
51 bool fUseUPnP = false;
52 uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
53 static CCriticalSection cs_mapLocalHost;
54 static map<CNetAddr, LocalServiceInfo> mapLocalHost;
55 static bool vfReachable[NET_MAX] = {};
56 static bool vfLimited[NET_MAX] = {};
57 static CNode* pnodeLocalHost = NULL;
58 static CNode* pnodeSync = NULL;
59 CAddress addrSeenByPeer(CService("0.0.0.0", 0), nLocalServices);
60 uint64 nLocalHostNonce = 0;
61 boost::array<int, THREAD_MAX> vnThreadsRunning;
62 static std::vector<SOCKET> vhListenSocket;
65 vector<CNode*> vNodes;
66 CCriticalSection cs_vNodes;
67 map<CInv, CDataStream> mapRelay;
68 deque<pair<int64, CInv> > vRelayExpiration;
69 CCriticalSection cs_mapRelay;
70 map<CInv, int64> mapAlreadyAskedFor;
72 static deque<string> vOneShots;
73 CCriticalSection cs_vOneShots;
75 set<CNetAddr> setservAddNodeAddresses;
76 CCriticalSection cs_setservAddNodeAddresses;
78 static CSemaphore *semOutbound = NULL;
80 void AddOneShot(string strDest)
83 vOneShots.push_back(strDest);
86 unsigned short GetListenPort()
88 return (unsigned short)(GetArg("-port", GetDefaultPort()));
91 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
93 // Filter out duplicate requests
94 if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
96 pindexLastGetBlocksBegin = pindexBegin;
97 hashLastGetBlocksEnd = hashEnd;
99 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
102 // find 'best' local address for a particular peer
103 bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
109 int nBestReachability = -1;
111 LOCK(cs_mapLocalHost);
112 for (map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
114 int nScore = (*it).second.nScore;
115 int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
116 if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))
118 addr = CService((*it).first, (*it).second.nPort);
119 nBestReachability = nReachability;
124 return nBestScore >= 0;
127 // get best local address for a particular peer as a CAddress
128 CAddress GetLocalAddress(const CNetAddr *paddrPeer)
130 CAddress ret(CService("0.0.0.0",0),0);
132 if (GetLocal(addr, paddrPeer))
134 ret = CAddress(addr);
135 ret.nServices = nLocalServices;
136 ret.nTime = GetAdjustedTime();
141 bool RecvLine(SOCKET hSocket, string& strLine)
147 int nBytes = recv(hSocket, &c, 1, 0);
155 if (strLine.size() >= 9000)
158 else if (nBytes <= 0)
164 int nErr = WSAGetLastError();
165 if (nErr == WSAEMSGSIZE)
167 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
173 if (!strLine.empty())
178 printf("socket closed\n");
184 int nErr = WSAGetLastError();
185 printf("recv failed: %d\n", nErr);
192 // used when scores of local addresses may have changed
193 // pushes better local address to peers
194 void static AdvertizeLocal()
197 BOOST_FOREACH(CNode* pnode, vNodes)
199 if (pnode->fSuccessfullyConnected)
201 CAddress addrLocal = GetLocalAddress(&pnode->addr);
202 if (addrLocal.IsRoutable() && (CService)addrLocal != (CService)pnode->addrLocal)
204 pnode->PushAddress(addrLocal);
205 pnode->addrLocal = addrLocal;
211 void SetReachable(enum Network net, bool fFlag)
213 LOCK(cs_mapLocalHost);
214 vfReachable[net] = fFlag;
215 if (net == NET_IPV6 && fFlag)
216 vfReachable[NET_IPV4] = true;
219 // learn a new local address
220 bool AddLocal(const CService& addr, int nScore)
222 if (!addr.IsRoutable())
225 if (!fDiscover && nScore < LOCAL_MANUAL)
231 printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore);
234 LOCK(cs_mapLocalHost);
235 bool fAlready = mapLocalHost.count(addr) > 0;
236 LocalServiceInfo &info = mapLocalHost[addr];
237 if (!fAlready || nScore >= info.nScore) {
238 info.nScore = nScore + (fAlready ? 1 : 0);
239 info.nPort = addr.GetPort();
241 SetReachable(addr.GetNetwork());
249 bool AddLocal(const CNetAddr &addr, int nScore)
251 return AddLocal(CService(addr, GetListenPort()), nScore);
254 /** Make a particular network entirely off-limits (no automatic connects to it) */
255 void SetLimited(enum Network net, bool fLimited)
257 if (net == NET_UNROUTABLE)
259 LOCK(cs_mapLocalHost);
260 vfLimited[net] = fLimited;
263 bool IsLimited(enum Network net)
265 LOCK(cs_mapLocalHost);
266 return vfLimited[net];
269 bool IsLimited(const CNetAddr &addr)
271 return IsLimited(addr.GetNetwork());
274 /** vote for a local address */
275 bool SeenLocal(const CService& addr)
278 LOCK(cs_mapLocalHost);
279 if (mapLocalHost.count(addr) == 0)
281 mapLocalHost[addr].nScore++;
289 /** check whether a given address is potentially local */
290 bool IsLocal(const CService& addr)
292 LOCK(cs_mapLocalHost);
293 return mapLocalHost.count(addr) > 0;
296 /** check whether a given address is in a network we can probably connect to */
297 bool IsReachable(const CNetAddr& addr)
299 LOCK(cs_mapLocalHost);
300 enum Network net = addr.GetNetwork();
301 return vfReachable[net] && !vfLimited[net];
304 extern int GetExternalIPbySTUN(uint64_t rnd, struct sockaddr_in *mapped, const char **srv);
306 // We now get our external IP from the IRC server first and only use this as a backup
307 bool GetMyExternalIP(CNetAddr& ipRet)
309 struct sockaddr_in mapped;
310 uint64 rnd = GetRand(~0LL);
312 int rc = GetExternalIPbySTUN(rnd, &mapped, &srv);
314 ipRet = CNetAddr(mapped.sin_addr);
315 printf("GetExternalIPbySTUN(%"PRI64u") returned %s in attempt %d; Server=%s\n", rnd, ipRet.ToStringIP().c_str(), rc, srv);
321 void ThreadGetMyExternalIP(void* parg)
323 // Make this thread recognisable as the external IP detection thread
324 RenameThread("novacoin-ext-ip");
326 CNetAddr addrLocalHost;
327 if (GetMyExternalIP(addrLocalHost))
329 printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
330 AddLocal(addrLocalHost, LOCAL_HTTP);
338 void AddressCurrentlyConnected(const CService& addr)
340 addrman.Connected(addr);
346 uint64_t CNode::nTotalBytesRecv = 0;
347 uint64_t CNode::nTotalBytesSent = 0;
348 CCriticalSection CNode::cs_totalBytesRecv;
349 CCriticalSection CNode::cs_totalBytesSent;
351 CNode* FindNode(const CNetAddr& ip)
354 BOOST_FOREACH(CNode* pnode, vNodes)
355 if ((CNetAddr)pnode->addr == ip)
360 CNode* FindNode(std::string addrName)
363 BOOST_FOREACH(CNode* pnode, vNodes)
364 if (pnode->addrName == addrName)
369 CNode* FindNode(const CService& addr)
372 BOOST_FOREACH(CNode* pnode, vNodes)
373 if ((CService)pnode->addr == addr)
378 CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout)
380 if (pszDest == NULL) {
381 if (IsLocal(addrConnect))
384 // Look for an existing connection
385 CNode* pnode = FindNode((CService)addrConnect);
389 pnode->AddRef(nTimeout);
398 printf("trying connection %s lastseen=%.1fhrs\n",
399 pszDest ? pszDest : addrConnect.ToString().c_str(),
400 pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
404 if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, GetDefaultPort()) : ConnectSocket(addrConnect, hSocket))
406 addrman.Attempt(addrConnect);
409 printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str());
411 // Set to non-blocking
414 if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
415 printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
417 if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
418 printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
422 CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
424 pnode->AddRef(nTimeout);
430 vNodes.push_back(pnode);
433 pnode->nTimeConnected = GetTime();
442 void CNode::CloseSocketDisconnect()
445 if (hSocket != INVALID_SOCKET)
447 printf("disconnecting node %s\n", addrName.c_str());
448 closesocket(hSocket);
449 hSocket = INVALID_SOCKET;
453 // in case this fails, we'll empty the recv buffer when the CNode is deleted
454 TRY_LOCK(cs_vRecv, lockRecv);
458 // if this was the sync node, we'll need a new one
459 if (this == pnodeSync)
463 void CNode::Cleanup()
468 void CNode::PushVersion()
470 /// when NTP implemented, change to just nTime = GetAdjustedTime()
471 int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
472 CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
473 CAddress addrMe = GetLocalAddress(&addr);
474 RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
475 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());
476 PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
477 nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
484 std::map<CNetAddr, int64> CNode::setBanned;
485 CCriticalSection CNode::cs_setBanned;
487 void CNode::ClearBanned()
492 bool CNode::IsBanned(CNetAddr ip)
494 bool fResult = false;
497 std::map<CNetAddr, int64>::iterator i = setBanned.find(ip);
498 if (i != setBanned.end())
500 int64 t = (*i).second;
508 bool CNode::Misbehaving(int howmuch)
512 printf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch);
516 nMisbehavior += howmuch;
517 if (nMisbehavior >= GetArg("-banscore", 100))
519 int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
520 printf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
523 if (setBanned[addr] < banTime)
524 setBanned[addr] = banTime;
526 CloseSocketDisconnect();
529 printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
534 #define X(name) stats.name = name
535 void CNode::copyStats(CNodeStats &stats)
550 stats.fSyncNode = (this == pnodeSync);
563 void ThreadSocketHandler(void* parg)
565 // Make this thread recognisable as the networking thread
566 RenameThread("novacoin-net");
570 vnThreadsRunning[THREAD_SOCKETHANDLER]++;
571 ThreadSocketHandler2(parg);
572 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
574 catch (std::exception& e) {
575 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
576 PrintException(&e, "ThreadSocketHandler()");
578 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
579 throw; // support pthread_cancel()
581 printf("ThreadSocketHandler exited\n");
584 void ThreadSocketHandler2(void* parg)
586 printf("ThreadSocketHandler started\n");
587 list<CNode*> vNodesDisconnected;
588 unsigned int nPrevNodeCount = 0;
597 // Disconnect unused nodes
598 vector<CNode*> vNodesCopy = vNodes;
599 BOOST_FOREACH(CNode* pnode, vNodesCopy)
601 if (pnode->fDisconnect ||
602 (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
604 // remove from vNodes
605 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
607 // release outbound grant (if any)
608 pnode->grantOutbound.Release();
610 // close socket and cleanup
611 pnode->CloseSocketDisconnect();
614 // hold in disconnected pool until all refs are released
615 pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
616 if (pnode->fNetworkNode || pnode->fInbound)
618 vNodesDisconnected.push_back(pnode);
622 // Delete disconnected nodes
623 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
624 BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
626 // wait until threads are done using it
627 if (pnode->GetRefCount() <= 0)
629 bool fDelete = false;
631 TRY_LOCK(pnode->cs_vSend, lockSend);
634 TRY_LOCK(pnode->cs_vRecv, lockRecv);
637 TRY_LOCK(pnode->cs_mapRequests, lockReq);
640 TRY_LOCK(pnode->cs_inventory, lockInv);
649 vNodesDisconnected.remove(pnode);
655 if (vNodes.size() != nPrevNodeCount)
657 nPrevNodeCount = vNodes.size();
658 uiInterface.NotifyNumConnectionsChanged(vNodes.size());
663 // Find which sockets have data to receive
665 struct timeval timeout;
667 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
674 FD_ZERO(&fdsetError);
675 SOCKET hSocketMax = 0;
676 bool have_fds = false;
678 BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
679 FD_SET(hListenSocket, &fdsetRecv);
680 hSocketMax = max(hSocketMax, hListenSocket);
685 BOOST_FOREACH(CNode* pnode, vNodes)
687 if (pnode->hSocket == INVALID_SOCKET)
689 FD_SET(pnode->hSocket, &fdsetRecv);
690 FD_SET(pnode->hSocket, &fdsetError);
691 hSocketMax = max(hSocketMax, pnode->hSocket);
694 TRY_LOCK(pnode->cs_vSend, lockSend);
695 if (lockSend && !pnode->vSend.empty())
696 FD_SET(pnode->hSocket, &fdsetSend);
701 vnThreadsRunning[THREAD_SOCKETHANDLER]--;
702 int nSelect = select(have_fds ? hSocketMax + 1 : 0,
703 &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
704 vnThreadsRunning[THREAD_SOCKETHANDLER]++;
707 if (nSelect == SOCKET_ERROR)
711 int nErr = WSAGetLastError();
712 printf("socket select error %d\n", nErr);
713 for (unsigned int i = 0; i <= hSocketMax; i++)
714 FD_SET(i, &fdsetRecv);
717 FD_ZERO(&fdsetError);
718 Sleep(timeout.tv_usec/1000);
723 // Accept new connections
725 BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
726 if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
729 struct sockaddr_storage sockaddr;
731 struct sockaddr sockaddr;
733 socklen_t len = sizeof(sockaddr);
734 SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
738 if (hSocket != INVALID_SOCKET)
739 if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
740 printf("Warning: Unknown socket family\n");
744 BOOST_FOREACH(CNode* pnode, vNodes)
749 if (hSocket == INVALID_SOCKET)
751 int nErr = WSAGetLastError();
752 if (nErr != WSAEWOULDBLOCK)
753 printf("socket error accept failed: %d\n", nErr);
755 else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
758 LOCK(cs_setservAddNodeAddresses);
759 if (!setservAddNodeAddresses.count(addr))
760 closesocket(hSocket);
763 else if (CNode::IsBanned(addr))
765 printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
766 closesocket(hSocket);
770 printf("accepted connection %s\n", addr.ToString().c_str());
771 CNode* pnode = new CNode(hSocket, addr, "", true);
775 vNodes.push_back(pnode);
782 // Service each socket
784 vector<CNode*> vNodesCopy;
788 BOOST_FOREACH(CNode* pnode, vNodesCopy)
791 BOOST_FOREACH(CNode* pnode, vNodesCopy)
799 if (pnode->hSocket == INVALID_SOCKET)
801 if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
803 TRY_LOCK(pnode->cs_vRecv, lockRecv);
806 CDataStream& vRecv = pnode->vRecv;
807 unsigned int nPos = vRecv.size();
809 if (nPos > ReceiveBufferSize()) {
810 if (!pnode->fDisconnect)
811 printf("socket recv flood control disconnect (%"PRIszu" bytes)\n", vRecv.size());
812 pnode->CloseSocketDisconnect();
815 // typical socket buffer is 8K-64K
816 char pchBuf[0x10000];
817 int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
820 vRecv.resize(nPos + nBytes);
821 memcpy(&vRecv[nPos], pchBuf, nBytes);
822 pnode->nLastRecv = GetTime();
823 pnode->nRecvBytes += nBytes;
824 pnode->RecordBytesRecv(nBytes);
826 else if (nBytes == 0)
828 // socket closed gracefully
829 if (!pnode->fDisconnect)
830 printf("socket closed\n");
831 pnode->CloseSocketDisconnect();
836 int nErr = WSAGetLastError();
837 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
839 if (!pnode->fDisconnect)
840 printf("socket recv error %d\n", nErr);
841 pnode->CloseSocketDisconnect();
851 if (pnode->hSocket == INVALID_SOCKET)
853 if (FD_ISSET(pnode->hSocket, &fdsetSend))
855 TRY_LOCK(pnode->cs_vSend, lockSend);
858 CDataStream& vSend = pnode->vSend;
861 int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
864 vSend.erase(vSend.begin(), vSend.begin() + nBytes);
865 pnode->nLastSend = GetTime();
866 pnode->nSendBytes += nBytes;
867 pnode->RecordBytesSent(nBytes);
872 int nErr = WSAGetLastError();
873 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
875 printf("socket send error %d\n", nErr);
876 pnode->CloseSocketDisconnect();
884 // Inactivity checking
886 if (pnode->vSend.empty())
887 pnode->nLastSendEmpty = GetTime();
888 if (GetTime() - pnode->nTimeConnected > 60)
890 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
892 printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
893 pnode->fDisconnect = true;
895 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
897 printf("socket not sending\n");
898 pnode->fDisconnect = true;
900 else if (GetTime() - pnode->nLastRecv > 90*60)
902 printf("socket inactivity timeout\n");
903 pnode->fDisconnect = true;
909 BOOST_FOREACH(CNode* pnode, vNodesCopy)
926 void ThreadMapPort(void* parg)
928 // Make this thread recognisable as the UPnP thread
929 RenameThread("novacoin-UPnP");
933 vnThreadsRunning[THREAD_UPNP]++;
934 ThreadMapPort2(parg);
935 vnThreadsRunning[THREAD_UPNP]--;
937 catch (std::exception& e) {
938 vnThreadsRunning[THREAD_UPNP]--;
939 PrintException(&e, "ThreadMapPort()");
941 vnThreadsRunning[THREAD_UPNP]--;
942 PrintException(NULL, "ThreadMapPort()");
944 printf("ThreadMapPort exited\n");
947 void ThreadMapPort2(void* parg)
949 printf("ThreadMapPort started\n");
951 std::string port = strprintf("%u", GetListenPort());
952 const char * multicastif = 0;
953 const char * minissdpdpath = 0;
954 struct UPNPDev * devlist = 0;
957 #ifndef UPNPDISCOVER_SUCCESS
959 devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
963 devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
966 struct UPNPUrls urls;
967 struct IGDdatas data;
970 r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
974 char externalIPAddress[40];
975 r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
976 if(r != UPNPCOMMAND_SUCCESS)
977 printf("UPnP: GetExternalIPAddress() returned %d\n", r);
980 if(externalIPAddress[0])
982 printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
983 AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP);
986 printf("UPnP: GetExternalIPAddress failed.\n");
990 string strDesc = "NovaCoin " + FormatFullVersion();
991 #ifndef UPNPDISCOVER_SUCCESS
993 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
994 port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0);
997 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
998 port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
1001 if(r!=UPNPCOMMAND_SUCCESS)
1002 printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
1003 port.c_str(), port.c_str(), lanaddr, r, strupnperror(r));
1005 printf("UPnP Port Mapping successful.\n");
1009 if (fShutdown || !fUseUPnP)
1011 r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
1012 printf("UPNP_DeletePortMapping() returned : %d\n", r);
1013 freeUPNPDevlist(devlist); devlist = 0;
1014 FreeUPNPUrls(&urls);
1017 if (i % 600 == 0) // Refresh every 20 minutes
1019 #ifndef UPNPDISCOVER_SUCCESS
1021 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
1022 port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0);
1025 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
1026 port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
1029 if(r!=UPNPCOMMAND_SUCCESS)
1030 printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
1031 port.c_str(), port.c_str(), lanaddr, r, strupnperror(r));
1033 printf("UPnP Port Mapping successful.\n");;
1039 printf("No valid UPnP IGDs found\n");
1040 freeUPNPDevlist(devlist); devlist = 0;
1042 FreeUPNPUrls(&urls);
1045 if (fShutdown || !fUseUPnP)
1054 if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1)
1056 if (!NewThread(ThreadMapPort, NULL))
1057 printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
1063 // Intentionally left blank.
1076 // Each pair gives a source name and a seed name.
1077 // The first name is used as information source for addrman.
1078 // The second name should resolve to a list of seed addresses.
1079 static const char *strDNSSeed[][2] = {
1080 {"novacoin.karelia.pro", "dnsseed.novacoin.karelia.pro"},
1081 {"novacoin.su", "dnsseed.novacoin.su"},
1082 {"novacoin.ru", "dnsseed.novacoin.ru"},
1083 {"novaco.in", "dnsseed.novaco.in"},
1086 void ThreadDNSAddressSeed(void* parg)
1088 // Make this thread recognisable as the DNS seeding thread
1089 RenameThread("novacoin-dnsseed");
1093 vnThreadsRunning[THREAD_DNSSEED]++;
1094 ThreadDNSAddressSeed2(parg);
1095 vnThreadsRunning[THREAD_DNSSEED]--;
1097 catch (std::exception& e) {
1098 vnThreadsRunning[THREAD_DNSSEED]--;
1099 PrintException(&e, "ThreadDNSAddressSeed()");
1101 vnThreadsRunning[THREAD_DNSSEED]--;
1102 throw; // support pthread_cancel()
1104 printf("ThreadDNSAddressSeed exited\n");
1107 void ThreadDNSAddressSeed2(void* parg)
1109 printf("ThreadDNSAddressSeed started\n");
1114 printf("Loading addresses from DNS seeds (could take a while)\n");
1116 for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
1117 if (HaveNameProxy()) {
1118 AddOneShot(strDNSSeed[seed_idx][1]);
1120 vector<CNetAddr> vaddr;
1121 vector<CAddress> vAdd;
1122 if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
1124 BOOST_FOREACH(CNetAddr& ip, vaddr)
1126 int nOneDay = 24*3600;
1127 CAddress addr = CAddress(CService(ip, GetDefaultPort()));
1128 addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
1129 vAdd.push_back(addr);
1133 addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
1138 printf("%d addresses found from DNS seeds\n", found);
1152 unsigned int pnSeed[] =
1154 0x5360a653, 0x6c47bb25, 0x52568c5f, 0xc6f5c851, 0x6f17f3a2, 0x1d52a9d5, 0x2c1544c1, 0xb8748368,
1155 0x055d6ac1, 0x2490bb25, 0x614488d5, 0xa463f8a2, 0xc54c1256, 0xf72d9252, 0x548432c6, 0xade08368,
1156 0x02bf8f55, 0x79f81c48, 0xeb44a26d, 0x802c0856, 0xe3a8d772, 0xc661c852, 0xde30d4b0, 0x1044d079,
1157 0xa1e1485d, 0x269d5e02, 0x65ec8b5b, 0x4b78a605, 0xac9a1f5f, 0x307c7db0, 0xb75d4880, 0x31aaef53,
1158 0xe9433eb0, 0x8ce0861f, 0x1874695f, 0x6baef986, 0x06cfbf2e, 0x6c2e0082, 0x15e024b0, 0x0d0986bc,
1159 0xe7002d48, 0x064b2d05, 0xba568c5f, 0x3c93fa18, 0xfae6234d, 0xb06f5d02, 0x34e25d02, 0x559425b0,
1160 0x308eae6e, 0x48e15d02, 0x87fee36d, 0x647f5e02, 0xcbfe61bc, 0x3bf377d4, 0x1543075b, 0x3ee84980,
1161 0xde26482e, 0x66a65e02, 0x60cf0fb0, 0xf74c8e4f, 0x88d39a5e, 0x1c385e02, 0x62c4f460, 0x5b26df48,
1162 0x5249515d, 0x2b353f7d, 0xb6e34980, 0x5e7cd23e, 0x5ecc5e02, 0x9349515d, 0x31abbf2e, 0xa8675cb6,
1163 0xa8ce4762, 0x09e5d4b0, 0x6db26805, 0xb4f45d02, 0xfe07e555, 0xb6ab40bc, 0x8be25d02, 0x92bd345f,
1164 0x7122306c, 0x9254c248, 0x8dcc5e02, 0x0d1d5d02, 0x35a2805f, 0x404ef986, 0x5dab696d, 0xf153ad2e,
1165 0xc5c7a988, 0xfafd6d4a, 0xf172a7be, 0x09627bd9, 0x747d695f, 0xaa4a5d02, 0x4d226805, 0x6bb40ab9,
1169 void DumpAddresses()
1171 int64 nStart = GetTimeMillis();
1176 printf("Flushed %d addresses to peers.dat %"PRI64d"ms\n",
1177 addrman.size(), GetTimeMillis() - nStart);
1180 void ThreadDumpAddress2(void* parg)
1182 vnThreadsRunning[THREAD_DUMPADDRESS]++;
1186 vnThreadsRunning[THREAD_DUMPADDRESS]--;
1188 vnThreadsRunning[THREAD_DUMPADDRESS]++;
1190 vnThreadsRunning[THREAD_DUMPADDRESS]--;
1193 void ThreadDumpAddress(void* parg)
1195 // Make this thread recognisable as the address dumping thread
1196 RenameThread("novacoin-adrdump");
1200 ThreadDumpAddress2(parg);
1202 catch (std::exception& e) {
1203 PrintException(&e, "ThreadDumpAddress()");
1205 printf("ThreadDumpAddress exited\n");
1208 void ThreadOpenConnections(void* parg)
1210 // Make this thread recognisable as the connection opening thread
1211 RenameThread("novacoin-opencon");
1215 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1216 ThreadOpenConnections2(parg);
1217 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1219 catch (std::exception& e) {
1220 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1221 PrintException(&e, "ThreadOpenConnections()");
1223 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1224 PrintException(NULL, "ThreadOpenConnections()");
1226 printf("ThreadOpenConnections exited\n");
1229 void static ProcessOneShot()
1234 if (vOneShots.empty())
1236 strDest = vOneShots.front();
1237 vOneShots.pop_front();
1240 CSemaphoreGrant grant(*semOutbound, true);
1242 if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true))
1243 AddOneShot(strDest);
1247 // ppcoin: stake minter thread
1248 void static ThreadStakeMinter(void* parg)
1250 printf("ThreadStakeMinter started\n");
1251 CWallet* pwallet = (CWallet*)parg;
1254 vnThreadsRunning[THREAD_MINTER]++;
1255 StakeMiner(pwallet);
1256 vnThreadsRunning[THREAD_MINTER]--;
1258 catch (std::exception& e) {
1259 vnThreadsRunning[THREAD_MINTER]--;
1260 PrintException(&e, "ThreadStakeMinter()");
1262 vnThreadsRunning[THREAD_MINTER]--;
1263 PrintException(NULL, "ThreadStakeMinter()");
1265 printf("ThreadStakeMinter exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINTER]);
1268 void ThreadOpenConnections2(void* parg)
1270 printf("ThreadOpenConnections started\n");
1272 // Connect to specific addresses
1273 if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
1275 for (int64 nLoop = 0;; nLoop++)
1278 BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
1281 OpenNetworkConnection(addr, NULL, strAddr.c_str());
1282 for (int i = 0; i < 10 && i < nLoop; i++)
1293 // Initiate network connections
1294 int64 nStart = GetTime();
1299 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1301 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1306 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1307 CSemaphoreGrant grant(*semOutbound);
1308 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1312 // Add seed nodes if IRC isn't working
1313 if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
1315 std::vector<CAddress> vAdd;
1316 for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
1318 // It'll only connect to one or two seed nodes because once it connects,
1319 // it'll get a pile of addresses with newer timestamps.
1320 // Seed nodes are given a random 'last seen time' of between one and two
1322 const int64 nOneWeek = 7*24*60*60;
1324 memcpy(&ip, &pnSeed[i], sizeof(ip));
1325 CAddress addr(CService(ip, GetDefaultPort()));
1326 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
1327 vAdd.push_back(addr);
1329 addrman.Add(vAdd, CNetAddr("127.0.0.1"));
1333 // Choose an address to connect to based on most recently seen
1335 CAddress addrConnect;
1337 // Only connect out to one peer per network group (/16 for IPv4).
1338 // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
1340 set<vector<unsigned char> > setConnected;
1343 BOOST_FOREACH(CNode* pnode, vNodes) {
1344 if (!pnode->fInbound) {
1345 setConnected.insert(pnode->addr.GetGroup());
1351 int64 nANow = GetAdjustedTime();
1356 // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
1357 CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
1359 // if we selected an invalid address, restart
1360 if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
1363 // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
1364 // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
1365 // already-connected network ranges, ...) before trying new addrman addresses.
1370 if (IsLimited(addr))
1373 // only consider very recently tried nodes after 30 failed attempts
1374 if (nANow - addr.nLastTry < 600 && nTries < 30)
1377 // do not allow non-default ports, unless after 50 invalid addresses selected already
1378 if (addr.GetPort() != GetDefaultPort() && nTries < 50)
1385 if (addrConnect.IsValid())
1386 OpenNetworkConnection(addrConnect, &grant);
1390 void ThreadOpenAddedConnections(void* parg)
1392 // Make this thread recognisable as the connection opening thread
1393 RenameThread("novacoin-opencon");
1397 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1398 ThreadOpenAddedConnections2(parg);
1399 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1401 catch (std::exception& e) {
1402 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1403 PrintException(&e, "ThreadOpenAddedConnections()");
1405 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1406 PrintException(NULL, "ThreadOpenAddedConnections()");
1408 printf("ThreadOpenAddedConnections exited\n");
1411 void ThreadOpenAddedConnections2(void* parg)
1413 printf("ThreadOpenAddedConnections started\n");
1415 if (mapArgs.count("-addnode") == 0)
1418 if (HaveNameProxy()) {
1420 BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) {
1422 CSemaphoreGrant grant(*semOutbound);
1423 OpenNetworkConnection(addr, &grant, strAddNode.c_str());
1426 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1427 Sleep(120000); // Retry every 2 minutes
1428 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1433 vector<vector<CService> > vservAddressesToAdd(0);
1434 BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"])
1436 vector<CService> vservNode(0);
1437 if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
1439 vservAddressesToAdd.push_back(vservNode);
1441 LOCK(cs_setservAddNodeAddresses);
1442 BOOST_FOREACH(CService& serv, vservNode)
1443 setservAddNodeAddresses.insert(serv);
1449 vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd;
1450 // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
1451 // (keeping in mind that addnode entries can have many IPs if fNameLookup)
1454 BOOST_FOREACH(CNode* pnode, vNodes)
1455 for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
1456 BOOST_FOREACH(CService& addrNode, *(it))
1457 if (pnode->addr == addrNode)
1459 it = vservConnectAddresses.erase(it);
1464 BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
1466 CSemaphoreGrant grant(*semOutbound);
1467 OpenNetworkConnection(CAddress(*(vserv.begin())), &grant);
1474 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
1475 Sleep(120000); // Retry every 2 minutes
1476 vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
1482 // if successful, this moves the passed grant to the constructed node
1483 bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot)
1486 // Initiate outbound network connection
1491 if (IsLocal(addrConnect) ||
1492 FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
1493 FindNode(addrConnect.ToStringIPPort().c_str()))
1495 if (strDest && FindNode(strDest))
1498 vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
1499 CNode* pnode = ConnectNode(addrConnect, strDest);
1500 vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
1506 grantOutbound->MoveTo(pnode->grantOutbound);
1507 pnode->fNetworkNode = true;
1509 pnode->fOneShot = true;
1514 // for now, use a very simple selection metric: the node from which we received
1516 double static NodeSyncScore(const CNode *pnode) {
1517 return -pnode->nLastRecv;
1520 void static StartSync(const vector<CNode*> &vNodes) {
1521 CNode *pnodeNewSync = NULL;
1522 double dBestScore = 0;
1524 // Iterate over all nodes
1525 BOOST_FOREACH(CNode* pnode, vNodes) {
1526 // check preconditions for allowing a sync
1527 if (!pnode->fClient && !pnode->fOneShot &&
1528 !pnode->fDisconnect && pnode->fSuccessfullyConnected &&
1529 (pnode->nStartingHeight > (nBestHeight - 144)) &&
1530 (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
1531 // if ok, compare node's score with the best so far
1532 double dScore = NodeSyncScore(pnode);
1533 if (pnodeNewSync == NULL || dScore > dBestScore) {
1534 pnodeNewSync = pnode;
1535 dBestScore = dScore;
1539 // if a new sync candidate was found, start sync!
1541 pnodeNewSync->fStartSync = true;
1542 pnodeSync = pnodeNewSync;
1546 void ThreadMessageHandler(void* parg)
1548 // Make this thread recognisable as the message handling thread
1549 RenameThread("novacoin-msghand");
1553 vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1554 ThreadMessageHandler2(parg);
1555 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1557 catch (std::exception& e) {
1558 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1559 PrintException(&e, "ThreadMessageHandler()");
1561 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1562 PrintException(NULL, "ThreadMessageHandler()");
1564 printf("ThreadMessageHandler exited\n");
1567 void ThreadMessageHandler2(void* parg)
1569 printf("ThreadMessageHandler started\n");
1570 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1573 bool fHaveSyncNode = false;
1574 vector<CNode*> vNodesCopy;
1577 vNodesCopy = vNodes;
1578 BOOST_FOREACH(CNode* pnode, vNodesCopy) {
1580 if (pnode == pnodeSync)
1581 fHaveSyncNode = true;
1586 StartSync(vNodesCopy);
1588 // Poll the connected nodes for messages
1589 CNode* pnodeTrickle = NULL;
1590 if (!vNodesCopy.empty())
1591 pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
1592 BOOST_FOREACH(CNode* pnode, vNodesCopy)
1596 TRY_LOCK(pnode->cs_vRecv, lockRecv);
1598 ProcessMessages(pnode);
1605 TRY_LOCK(pnode->cs_vSend, lockSend);
1607 SendMessages(pnode, pnode == pnodeTrickle);
1615 BOOST_FOREACH(CNode* pnode, vNodesCopy)
1619 // Wait and allow messages to bunch up.
1620 // Reduce vnThreadsRunning so StopNode has permission to exit while
1621 // we're sleeping, but we must always check fShutdown after doing this.
1622 vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
1624 if (fRequestShutdown)
1626 vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
1637 bool BindListenPort(const CService &addrBind, string& strError)
1643 // Initialize Windows Sockets
1645 int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
1646 if (ret != NO_ERROR)
1648 strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
1649 printf("%s\n", strError.c_str());
1654 // Create socket for listening for incoming connections
1656 struct sockaddr_storage sockaddr;
1658 struct sockaddr sockaddr;
1660 socklen_t len = sizeof(sockaddr);
1661 if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
1663 strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str());
1664 printf("%s\n", strError.c_str());
1668 SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
1669 if (hListenSocket == INVALID_SOCKET)
1671 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
1672 printf("%s\n", strError.c_str());
1677 // Different way of disabling SIGPIPE on BSD
1678 setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
1682 // Allow binding if the port is still in TIME_WAIT state after
1683 // the program was closed and restarted. Not an issue on windows.
1684 setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
1689 // Set to non-blocking, incoming connections will also inherit this
1690 if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
1692 if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
1695 strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
1696 printf("%s\n", strError.c_str());
1701 // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
1702 // and enable it by default or not. Try to enable it, if possible.
1703 if (addrBind.IsIPv6()) {
1706 setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int));
1708 setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
1712 int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
1713 int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
1714 // this call is allowed to fail
1715 setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
1720 if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
1722 int nErr = WSAGetLastError();
1723 if (nErr == WSAEADDRINUSE)
1724 strError = strprintf(_("Unable to bind to %s on this computer. NovaCoin is probably already running."), addrBind.ToString().c_str());
1726 strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr));
1727 printf("%s\n", strError.c_str());
1730 printf("Bound to %s\n", addrBind.ToString().c_str());
1732 // Listen for incoming connections
1733 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1735 strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
1736 printf("%s\n", strError.c_str());
1740 vhListenSocket.push_back(hListenSocket);
1742 if (addrBind.IsRoutable() && fDiscover)
1743 AddLocal(addrBind, LOCAL_BIND);
1748 void static Discover()
1754 // Get local host IP
1755 char pszHostName[1000] = "";
1756 if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
1758 vector<CNetAddr> vaddr;
1759 if (LookupHost(pszHostName, vaddr))
1761 BOOST_FOREACH (const CNetAddr &addr, vaddr)
1763 AddLocal(addr, LOCAL_IF);
1768 // Get local host ip
1769 struct ifaddrs* myaddrs;
1770 if (getifaddrs(&myaddrs) == 0)
1772 for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
1774 if (ifa->ifa_addr == NULL) continue;
1775 if ((ifa->ifa_flags & IFF_UP) == 0) continue;
1776 if (strcmp(ifa->ifa_name, "lo") == 0) continue;
1777 if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
1778 if (ifa->ifa_addr->sa_family == AF_INET)
1780 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
1781 CNetAddr addr(s4->sin_addr);
1782 if (AddLocal(addr, LOCAL_IF))
1783 printf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1786 else if (ifa->ifa_addr->sa_family == AF_INET6)
1788 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
1789 CNetAddr addr(s6->sin6_addr);
1790 if (AddLocal(addr, LOCAL_IF))
1791 printf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str());
1795 freeifaddrs(myaddrs);
1799 // Don't use external IPv4 discovery, when -onlynet="IPv6"
1800 if (!IsLimited(NET_IPV4))
1801 NewThread(ThreadGetMyExternalIP, NULL);
1804 void StartNode(void* parg)
1806 // Make this thread recognisable as the startup thread
1807 RenameThread("novacoin-start");
1809 if (semOutbound == NULL) {
1810 // initialize semaphore
1811 int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
1812 semOutbound = new CSemaphore(nMaxOutbound);
1815 if (pnodeLocalHost == NULL)
1816 pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
1824 if (!GetBoolArg("-dnsseed", true))
1825 printf("DNS seeding disabled\n");
1827 if (!NewThread(ThreadDNSAddressSeed, NULL))
1828 printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
1830 // Map ports with UPnP
1834 // Get addresses from IRC and advertise ours
1835 if (!NewThread(ThreadIRCSeed, NULL))
1836 printf("Error: NewThread(ThreadIRCSeed) failed\n");
1838 // Send and receive from sockets, accept connections
1839 if (!NewThread(ThreadSocketHandler, NULL))
1840 printf("Error: NewThread(ThreadSocketHandler) failed\n");
1842 // Initiate outbound connections from -addnode
1843 if (!NewThread(ThreadOpenAddedConnections, NULL))
1844 printf("Error: NewThread(ThreadOpenAddedConnections) failed\n");
1846 // Initiate outbound connections
1847 if (!NewThread(ThreadOpenConnections, NULL))
1848 printf("Error: NewThread(ThreadOpenConnections) failed\n");
1851 if (!NewThread(ThreadMessageHandler, NULL))
1852 printf("Error: NewThread(ThreadMessageHandler) failed\n");
1854 // Dump network addresses
1855 if (!NewThread(ThreadDumpAddress, NULL))
1856 printf("Error; NewThread(ThreadDumpAddress) failed\n");
1858 // ppcoin: mint proof-of-stake blocks in the background
1859 if (!NewThread(ThreadStakeMinter, pwalletMain))
1860 printf("Error: NewThread(ThreadStakeMinter) failed\n");
1865 printf("StopNode()\n");
1867 nTransactionsUpdated++;
1868 int64 nStart = GetTime();
1871 ThreadScriptCheckQuit();
1874 for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
1875 semOutbound->post();
1878 int nThreadsRunning = 0;
1879 for (int n = 0; n < THREAD_MAX; n++)
1880 nThreadsRunning += vnThreadsRunning[n];
1881 if (nThreadsRunning == 0)
1883 if (GetTime() - nStart > 20)
1887 if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
1888 if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
1889 if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
1890 if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n");
1891 if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n");
1893 if (vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
1895 if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
1896 if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
1897 if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
1898 if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStakeMinter still running\n");
1899 if (vnThreadsRunning[THREAD_SCRIPTCHECK] > 0) printf("ThreadScriptCheck still running\n");
1900 while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0 || vnThreadsRunning[THREAD_SCRIPTCHECK] > 0)
1916 BOOST_FOREACH(CNode* pnode, vNodes)
1917 if (pnode->hSocket != INVALID_SOCKET)
1918 closesocket(pnode->hSocket);
1919 BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
1920 if (hListenSocket != INVALID_SOCKET)
1921 if (closesocket(hListenSocket) == SOCKET_ERROR)
1922 printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
1925 // Shutdown Windows Sockets
1930 instance_of_cnetcleanup;
1932 void RelayTransaction(const CTransaction& tx, const uint256& hash)
1934 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
1937 RelayTransaction(tx, hash, ss);
1940 void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
1942 CInv inv(MSG_TX, hash);
1945 // Expire old relay messages
1946 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
1948 mapRelay.erase(vRelayExpiration.front().second);
1949 vRelayExpiration.pop_front();
1952 // Save original serialized message so newer versions are preserved
1953 mapRelay.insert(std::make_pair(inv, ss));
1954 vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
1957 RelayInventory(inv);
1960 void CNode::RecordBytesRecv(uint64_t bytes)
1962 LOCK(cs_totalBytesRecv);
1963 nTotalBytesRecv += bytes;
1966 void CNode::RecordBytesSent(uint64_t bytes)
1968 LOCK(cs_totalBytesSent);
1969 nTotalBytesSent += bytes;
1972 uint64_t CNode::GetTotalBytesRecv()
1974 LOCK(cs_totalBytesRecv);
1975 return nTotalBytesRecv;
1978 uint64_t CNode::GetTotalBytesSent()
1980 LOCK(cs_totalBytesSent);
1981 return nTotalBytesSent;