X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fnet.cpp;h=c69e83c0abc5e8403c215a125a0bf2f00f94f475;hp=0cc235003ada54282b484ab3caae6884bad579b3;hb=86ca35296e3e65c9a769a946f90a59b273063d9c;hpb=06de9fe18ebe40ae746e1b16332f2618ccc25f0e diff --git a/src/net.cpp b/src/net.cpp index 0cc2350..c69e83c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 The PPCoin developers -// Copyright (c) 2012-2013 The NovaCoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,66 +7,84 @@ #include "db.h" #include "net.h" #include "init.h" -#include "strlcpy.h" #include "addrman.h" #include "ui_interface.h" +#include "miner.h" +#include "ntp.h" #ifdef WIN32 #include #endif -#ifdef USE_UPNP -#include -#include -#include -#include -#endif - using namespace std; using namespace boost; -static const int MAX_OUTBOUND_CONNECTIONS = 8; +static const int MAX_OUTBOUND_CONNECTIONS = 16; void ThreadMessageHandler2(void* parg); void ThreadSocketHandler2(void* parg); void ThreadOpenConnections2(void* parg); void ThreadOpenAddedConnections2(void* parg); -#ifdef USE_UPNP -void ThreadMapPort2(void* parg); -#endif void ThreadDNSAddressSeed2(void* parg); -bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant = true); +// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h. +// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version. +#ifdef WIN32 +#ifndef PROTECTION_LEVEL_UNRESTRICTED +#define PROTECTION_LEVEL_UNRESTRICTED 10 +#endif +#ifndef IPV6_PROTECTION_LEVEL +#define IPV6_PROTECTION_LEVEL 23 +#endif +#endif +struct LocalServiceInfo { + int nScore; + uint16_t nPort; +}; // // Global state variables // bool fClient = false; -bool fAllowDNS = false; -static bool fUseUPnP = false; -uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); -CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices); -CAddress addrSeenByPeer(CService("0.0.0.0", 0), nLocalServices); +bool fDiscover = true; +uint64_t nLocalServices = (fClient ? 0 : NODE_NETWORK); +static CCriticalSection cs_mapLocalHost; +static map mapLocalHost; +static bool vfReachable[NET_MAX] = {}; +static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; -uint64 nLocalHostNonce = 0; -array vnThreadsRunning; -static SOCKET hListenSocket = INVALID_SOCKET; +static CNode* pnodeSync = NULL; +CAddress addrSeenByPeer(CService("0.0.0.0", nPortZero), nLocalServices); +uint64_t nLocalHostNonce = 0; +boost::array vnThreadsRunning; +static std::vector vhListenSocket; CAddrMan addrman; vector vNodes; CCriticalSection cs_vNodes; map mapRelay; -deque > vRelayExpiration; +deque > vRelayExpiration; CCriticalSection cs_mapRelay; -map mapAlreadyAskedFor; +map mapAlreadyAskedFor; +static deque vOneShots; +CCriticalSection cs_vOneShots; set setservAddNodeAddresses; CCriticalSection cs_setservAddNodeAddresses; +vector vAddedNodes; +CCriticalSection cs_vAddedNodes; + static CSemaphore *semOutbound = NULL; +void AddOneShot(string strDest) +{ + LOCK(cs_vOneShots); + vOneShots.push_back(strDest); +} + unsigned short GetListenPort() { return (unsigned short)(GetArg("-port", GetDefaultPort())); @@ -85,12 +101,49 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); } +// find 'best' local address for a particular peer +bool GetLocal(CService& addr, const CNetAddr *paddrPeer) +{ + if (fNoListen) + return false; + + int nBestScore = -1; + int nBestReachability = -1; + { + LOCK(cs_mapLocalHost); + for (map::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) + { + int nScore = (*it).second.nScore; + int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); + if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) + { + addr = CService((*it).first, (*it).second.nPort); + nBestReachability = nReachability; + nBestScore = nScore; + } + } + } + return nBestScore >= 0; +} +// get best local address for a particular peer as a CAddress +CAddress GetLocalAddress(const CNetAddr *paddrPeer) +{ + CAddress ret(CService("0.0.0.0", nPortZero), 0); + CService addr; + if (GetLocal(addr, paddrPeer)) + { + ret = CAddress(addr); + ret.nServices = nLocalServices; + ret.nTime = GetAdjustedTime(); + } + return ret; +} bool RecvLine(SOCKET hSocket, string& strLine) { strLine = ""; - loop + for ( ; ; ) { char c; int nBytes = recv(hSocket, &c, 1, 0); @@ -138,146 +191,145 @@ bool RecvLine(SOCKET hSocket, string& strLine) } } - - -bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) +// used when scores of local addresses may have changed +// pushes better local address to peers +void static AdvertizeLocal() { - SOCKET hSocket; - if (!ConnectSocket(addrConnect, hSocket)) - return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str()); - - send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL); - - string strLine; - while (RecvLine(hSocket, strLine)) + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { - if (strLine.empty()) // HTTP response is separated from headers by blank line + if (pnode->fSuccessfullyConnected) { - loop + CAddress addrLocal = GetLocalAddress(&pnode->addr); + if (addrLocal.IsRoutable() && (CService)addrLocal != pnode->addrLocal) { - if (!RecvLine(hSocket, strLine)) - { - closesocket(hSocket); - return false; - } - if (pszKeyword == NULL) - break; - if (strLine.find(pszKeyword) != string::npos) - { - strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword)); - break; - } + pnode->PushAddress(addrLocal); + pnode->addrLocal = addrLocal; } - closesocket(hSocket); - if (strLine.find("<") != string::npos) - strLine = strLine.substr(0, strLine.find("<")); - strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r")); - while (strLine.size() > 0 && isspace(strLine[strLine.size()-1])) - strLine.resize(strLine.size()-1); - CService addr(strLine,0,true); - printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); - if (!addr.IsValid() || !addr.IsRoutable()) - return false; - ipRet.SetIP(addr); - return true; } } - closesocket(hSocket); - return error("GetMyExternalIP() : connection closed"); } -// We now get our external IP from the IRC server first and only use this as a backup -bool GetMyExternalIP(CNetAddr& ipRet) +void SetReachable(enum Network net, bool fFlag) { - CService addrConnect; - const char* pszGet; - const char* pszKeyword; + LOCK(cs_mapLocalHost); + vfReachable[net] = fFlag; + if (net == NET_IPV6 && fFlag) + vfReachable[NET_IPV4] = true; +} - if (fNoListen||fUseProxy) +// learn a new local address +bool AddLocal(const CService& addr, int nScore) +{ + if (!addr.IsRoutable()) return false; - for (int nLookup = 0; nLookup <= 1; nLookup++) - for (int nHost = 1; nHost <= 2; nHost++) - { - // We should be phasing out our use of sites like these. If we need - // replacements, we should ask for volunteers to put this simple - // php file on their webserver that prints the client IP: - // - if (nHost == 1) - { - addrConnect = CService("91.198.22.70",80); // checkip.dyndns.org + if (!fDiscover && nScore < LOCAL_MANUAL) + return false; - if (nLookup == 1) - { - CService addrIP("checkip.dyndns.org", 80, true); - if (addrIP.IsValid()) - addrConnect = addrIP; - } + if (IsLimited(addr)) + return false; - pszGet = "GET / HTTP/1.1\r\n" - "Host: checkip.dyndns.org\r\n" - "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" - "Connection: close\r\n" - "\r\n"; + printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore); - pszKeyword = "Address:"; + { + LOCK(cs_mapLocalHost); + bool fAlready = mapLocalHost.count(addr) > 0; + LocalServiceInfo &info = mapLocalHost[addr]; + if (!fAlready || nScore >= info.nScore) { + info.nScore = nScore + (fAlready ? 1 : 0); + info.nPort = addr.GetPort(); } - else if (nHost == 2) - { - addrConnect = CService("74.208.43.192", 80); // www.showmyip.com + SetReachable(addr.GetNetwork()); + } - if (nLookup == 1) - { - CService addrIP("www.showmyip.com", 80, true); - if (addrIP.IsValid()) - addrConnect = addrIP; - } + AdvertizeLocal(); - pszGet = "GET /simple/ HTTP/1.1\r\n" - "Host: www.showmyip.com\r\n" - "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" - "Connection: close\r\n" - "\r\n"; + return true; +} - pszKeyword = NULL; // Returns just IP address - } +bool AddLocal(const CNetAddr &addr, int nScore) +{ + return AddLocal(CService(addr, GetListenPort()), nScore); +} + +/** Make a particular network entirely off-limits (no automatic connects to it) */ +void SetLimited(enum Network net, bool fLimited) +{ + if (net == NET_UNROUTABLE) + return; + LOCK(cs_mapLocalHost); + vfLimited[net] = fLimited; +} + +bool IsLimited(enum Network net) +{ + LOCK(cs_mapLocalHost); + return vfLimited[net]; +} - if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet)) - return true; +bool IsLimited(const CNetAddr &addr) +{ + return IsLimited(addr.GetNetwork()); +} + +/** vote for a local address */ +bool SeenLocal(const CService& addr) +{ + { + LOCK(cs_mapLocalHost); + if (mapLocalHost.count(addr) == 0) + return false; + mapLocalHost[addr].nScore++; } + AdvertizeLocal(); + + return true; +} + +/** check whether a given address is potentially local */ +bool IsLocal(const CService& addr) +{ + LOCK(cs_mapLocalHost); + return mapLocalHost.count(addr) > 0; +} + +/** check whether a given address is in a network we can probably connect to */ +bool IsReachable(const CNetAddr& addr) +{ + LOCK(cs_mapLocalHost); + enum Network net = addr.GetNetwork(); + return vfReachable[net] && !vfLimited[net]; +} + +extern int GetExternalIPbySTUN(uint64_t rnd, struct sockaddr_in *mapped, const char **srv); + +// We now get our external IP from the IRC server first and only use this as a backup +bool GetMyExternalIP(CNetAddr& ipRet) +{ + struct sockaddr_in mapped; + uint64_t rnd = std::numeric_limits::max(); + const char *srv; + int rc = GetExternalIPbySTUN(rnd, &mapped, &srv); + if(rc >= 0) { + ipRet = CNetAddr(mapped.sin_addr); + printf("GetExternalIPbySTUN(%" PRIu64 ") returned %s in attempt %d; Server=%s\n", rnd, ipRet.ToStringIP().c_str(), rc, srv); + return true; + } return false; } void ThreadGetMyExternalIP(void* parg) { - // Wait for IRC to get it first - if (GetBoolArg("-irc", true)) - { - for (int i = 0; i < 2 * 60; i++) - { - Sleep(1000); - if (fGotExternalIP || fShutdown) - return; - } - } + // Make this thread recognisable as the external IP detection thread + RenameThread("novacoin-ext-ip"); - // Fallback in case IRC fails to get it + CNetAddr addrLocalHost; if (GetMyExternalIP(addrLocalHost)) { printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str()); - if (addrLocalHost.IsRoutable()) - { - // If we already connected to a few before we had our IP, go back and addr them. - // setAddrKnown automatically filters any duplicate sends. - CAddress addr(addrLocalHost); - addr.nTime = GetAdjustedTime(); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - pnode->PushAddress(addr); - } - } + AddLocal(addrLocalHost, LOCAL_HTTP); } } @@ -293,77 +345,88 @@ void AddressCurrentlyConnected(const CService& addr) - - +uint64_t CNode::nTotalBytesRecv = 0; +uint64_t CNode::nTotalBytesSent = 0; +CCriticalSection CNode::cs_totalBytesRecv; +CCriticalSection CNode::cs_totalBytesSent; CNode* FindNode(const CNetAddr& ip) { - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if ((CNetAddr)pnode->addr == ip) - return (pnode); - } + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if ((CNetAddr)pnode->addr == ip) + return (pnode); + return NULL; +} + +CNode* FindNode(std::string addrName) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->addrName == addrName) + return (pnode); return NULL; } CNode* FindNode(const CService& addr) { - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if ((CService)pnode->addr == addr) - return (pnode); - } + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if ((CService)pnode->addr == addr) + return (pnode); return NULL; } -CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) +CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64_t nTimeout) { - if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost) - return NULL; + if (pszDest == NULL) { + if (IsLocal(addrConnect)) + return NULL; - // Look for an existing connection - CNode* pnode = FindNode((CService)addrConnect); - if (pnode) - { - if (nTimeout != 0) - pnode->AddRef(nTimeout); - else - pnode->AddRef(); - return pnode; + // Look for an existing connection + CNode* pnode = FindNode((CService)addrConnect); + if (pnode) + { + if (nTimeout != 0) + pnode->AddRef(nTimeout); + else + pnode->AddRef(); + return pnode; + } } + /// debug print printf("trying connection %s lastseen=%.1fhrs\n", - addrConnect.ToString().c_str(), - (double)(addrConnect.nTime - GetAdjustedTime())/3600.0); - - addrman.Attempt(addrConnect); + pszDest ? pszDest : addrConnect.ToString().c_str(), + pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0); // Connect SOCKET hSocket; - if (ConnectSocket(addrConnect, hSocket)) + if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, GetDefaultPort()) : ConnectSocket(addrConnect, hSocket)) { + addrman.Attempt(addrConnect); + /// debug print - printf("connected %s\n", addrConnect.ToString().c_str()); + printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str()); - // Set to nonblocking + // Set to non-blocking #ifdef WIN32 u_long nOne = 1; if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) - printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError()); + printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError()); #else if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) - printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno); + printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno); #endif // Add node - CNode* pnode = new CNode(hSocket, addrConnect, false); + CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); if (nTimeout != 0) pnode->AddRef(nTimeout); else pnode->AddRef(); + { LOCK(cs_vNodes); vNodes.push_back(pnode); @@ -383,13 +446,19 @@ void CNode::CloseSocketDisconnect() fDisconnect = true; if (hSocket != INVALID_SOCKET) { - if (fDebug) - printf("%s ", DateTimeStrFormat(GetTime()).c_str()); - printf("disconnecting node %s\n", addr.ToString().c_str()); - closesocket(hSocket); - hSocket = INVALID_SOCKET; + printf("disconnecting node %s\n", addrName.c_str()); + CloseSocket(hSocket); vRecv.clear(); } + + // in case this fails, we'll empty the recv buffer when the CNode is deleted + TRY_LOCK(cs_vRecv, lockRecv); + if (lockRecv) + vRecv.clear(); + + // if this was the sync node, we'll need a new one + if (this == pnodeSync) + pnodeSync = NULL; } void CNode::Cleanup() @@ -399,11 +468,30 @@ void CNode::Cleanup() void CNode::PushVersion() { - /// when NTP implemented, change to just nTime = GetAdjustedTime() - int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); - CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr); - CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress(CService("0.0.0.0",0)) : addrLocalHost); + int64_t nTime = GetAdjustedTime(); + CAddress addrYou, addrMe; + + bool fHidden = false; + if (addr.IsTor()) { + if (mapArgs.count("-torname")) { + // Our hidden service address + CService addrTorName(mapArgs["-torname"], GetListenPort()); + + if (addrTorName.IsValid()) { + addrYou = addr; + addrMe = CAddress(addrTorName); + fHidden = true; + } + } + } + + if (!fHidden) { + addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", nPortZero))); + addrMe = GetLocalAddress(&addr); + } + RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); + 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()); PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), nBestHeight); } @@ -412,7 +500,7 @@ void CNode::PushVersion() -std::map CNode::setBanned; +std::map CNode::setBanned; CCriticalSection CNode::cs_setBanned; void CNode::ClearBanned() @@ -425,10 +513,10 @@ bool CNode::IsBanned(CNetAddr ip) bool fResult = false; { LOCK(cs_setBanned); - std::map::iterator i = setBanned.find(ip); + std::map::iterator i = setBanned.find(ip); if (i != setBanned.end()) { - int64 t = (*i).second; + int64_t t = (*i).second; if (GetTime() < t) fResult = true; } @@ -440,32 +528,51 @@ bool CNode::Misbehaving(int howmuch) { if (addr.IsLocal()) { - printf("Warning: local node %s misbehaving\n", addr.ToString().c_str()); + printf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch); return false; } nMisbehavior += howmuch; - if (nMisbehavior >= GetArg("-banscore", 100)) + if (nMisbehavior >= GetArgInt("-banscore", 100)) { - int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban + int64_t banTime = GetTime()+GetArg("-bantime", nOneDay); // Default 24-hour ban + printf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior); { LOCK(cs_setBanned); if (setBanned[addr] < banTime) setBanned[addr] = banTime; } CloseSocketDisconnect(); - printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior); return true; - } + } else + printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior); return false; } +#undef X +#define X(name) stats.name = name +void CNode::copyStats(CNodeStats &stats) +{ + X(nServices); + X(nLastSend); + X(nLastRecv); + X(nTimeConnected); + X(addrName); + X(nVersion); + X(strSubVer); + X(fInbound); + X(nReleaseTime); + X(nStartingHeight); + X(nMisbehavior); + X(nSendBytes); + X(nRecvBytes); + stats.fSyncNode = (this == pnodeSync); +} +#undef X - - - - - +void Release(CNode* node) { + node->Release(); +} @@ -473,7 +580,9 @@ bool CNode::Misbehaving(int howmuch) void ThreadSocketHandler(void* parg) { - IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg)); + // Make this thread recognisable as the networking thread + RenameThread("novacoin-net"); + try { vnThreadsRunning[THREAD_SOCKETHANDLER]++; @@ -487,16 +596,16 @@ void ThreadSocketHandler(void* parg) vnThreadsRunning[THREAD_SOCKETHANDLER]--; throw; // support pthread_cancel() } - printf("ThreadSocketHandler exiting\n"); + printf("ThreadSocketHandler exited\n"); } +static list vNodesDisconnected; + void ThreadSocketHandler2(void* parg) { printf("ThreadSocketHandler started\n"); - list vNodesDisconnected; - unsigned int nPrevNodeCount = 0; - - loop + size_t nPrevNodeCount = 0; + for ( ; ; ) { // // Disconnect nodes @@ -513,9 +622,8 @@ void ThreadSocketHandler2(void* parg) // remove from vNodes vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); - if (pnode->fHasGrant) - semOutbound->post(); - pnode->fHasGrant = false; + // release outbound grant (if any) + pnode->grantOutbound.Release(); // close socket and cleanup pnode->CloseSocketDisconnect(); @@ -565,7 +673,7 @@ void ThreadSocketHandler2(void* parg) if (vNodes.size() != nPrevNodeCount) { nPrevNodeCount = vNodes.size(); - MainFrameRepaint(); + uiInterface.NotifyNumConnectionsChanged(vNodes.size()); } @@ -583,10 +691,13 @@ void ThreadSocketHandler2(void* parg) FD_ZERO(&fdsetSend); FD_ZERO(&fdsetError); SOCKET hSocketMax = 0; + bool have_fds = false; - if(hListenSocket != INVALID_SOCKET) + BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) { FD_SET(hListenSocket, &fdsetRecv); - hSocketMax = max(hSocketMax, hListenSocket); + hSocketMax = max(hSocketMax, hListenSocket); + have_fds = true; + } { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) @@ -596,6 +707,7 @@ void ThreadSocketHandler2(void* parg) FD_SET(pnode->hSocket, &fdsetRecv); FD_SET(pnode->hSocket, &fdsetError); hSocketMax = max(hSocketMax, pnode->hSocket); + have_fds = true; { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend && !pnode->vSend.empty()) @@ -605,15 +717,16 @@ void ThreadSocketHandler2(void* parg) } vnThreadsRunning[THREAD_SOCKETHANDLER]--; - int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout); + int nSelect = select(have_fds ? hSocketMax + 1 : 0, + &fdsetRecv, &fdsetSend, &fdsetError, &timeout); vnThreadsRunning[THREAD_SOCKETHANDLER]++; if (fShutdown) return; if (nSelect == SOCKET_ERROR) { - int nErr = WSAGetLastError(); - if (hSocketMax != INVALID_SOCKET) + if (have_fds) { + int nErr = WSAGetLastError(); printf("socket select error %d\n", nErr); for (unsigned int i = 0; i <= hSocketMax; i++) FD_SET(i, &fdsetRecv); @@ -627,16 +740,22 @@ void ThreadSocketHandler2(void* parg) // // Accept new connections // + BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv)) { - struct sockaddr_in sockaddr; +#ifdef USE_IPV6 + struct sockaddr_storage sockaddr; +#else + struct sockaddr sockaddr; +#endif socklen_t len = sizeof(sockaddr); SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; if (hSocket != INVALID_SOCKET) - addr = CAddress(sockaddr); + if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) + printf("Warning: Unknown socket family\n"); { LOCK(cs_vNodes); @@ -647,26 +766,27 @@ void ThreadSocketHandler2(void* parg) if (hSocket == INVALID_SOCKET) { - if (WSAGetLastError() != WSAEWOULDBLOCK) - printf("socket error accept failed: %d\n", WSAGetLastError()); + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK) + printf("socket error accept failed: %d\n", nErr); } - else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS) + else if (nInbound >= GetArgInt("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS) { { LOCK(cs_setservAddNodeAddresses); if (!setservAddNodeAddresses.count(addr)) - closesocket(hSocket); + CloseSocket(hSocket); } } else if (CNode::IsBanned(addr)) { printf("connection from %s dropped (banned)\n", addr.ToString().c_str()); - closesocket(hSocket); + CloseSocket(hSocket); } else { printf("accepted connection %s\n", addr.ToString().c_str()); - CNode* pnode = new CNode(hSocket, addr, true); + CNode* pnode = new CNode(hSocket, addr, "", true); pnode->AddRef(); { LOCK(cs_vNodes); @@ -702,11 +822,11 @@ void ThreadSocketHandler2(void* parg) if (lockRecv) { CDataStream& vRecv = pnode->vRecv; - unsigned int nPos = vRecv.size(); + uint64_t nPos = vRecv.size(); if (nPos > ReceiveBufferSize()) { if (!pnode->fDisconnect) - printf("socket recv flood control disconnect (%d bytes)\n", vRecv.size()); + printf("socket recv flood control disconnect (%" PRIszu " bytes)\n", vRecv.size()); pnode->CloseSocketDisconnect(); } else { @@ -718,6 +838,8 @@ void ThreadSocketHandler2(void* parg) vRecv.resize(nPos + nBytes); memcpy(&vRecv[nPos], pchBuf, nBytes); pnode->nLastRecv = GetTime(); + pnode->nRecvBytes += nBytes; + pnode->RecordBytesRecv(nBytes); } else if (nBytes == 0) { @@ -759,6 +881,8 @@ void ThreadSocketHandler2(void* parg) { vSend.erase(vSend.begin(), vSend.begin() + nBytes); pnode->nLastSend = GetTime(); + pnode->nSendBytes += nBytes; + pnode->RecordBytesSent(nBytes); } else if (nBytes < 0) { @@ -770,11 +894,6 @@ void ThreadSocketHandler2(void* parg) pnode->CloseSocketDisconnect(); } } - if (vSend.size() > SendBufferSize()) { - if (!pnode->fDisconnect) - printf("socket send flood control disconnect (%d bytes)\n", vSend.size()); - pnode->CloseSocketDisconnect(); - } } } } @@ -805,189 +924,29 @@ void ThreadSocketHandler2(void* parg) } { LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodesCopy) - pnode->Release(); + for_each(vNodesCopy.begin(), vNodesCopy.end(), Release); } Sleep(10); } } - - - - - - - - -#ifdef USE_UPNP -void ThreadMapPort(void* parg) -{ - IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg)); - try - { - vnThreadsRunning[THREAD_UPNP]++; - ThreadMapPort2(parg); - vnThreadsRunning[THREAD_UPNP]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_UPNP]--; - PrintException(&e, "ThreadMapPort()"); - } catch (...) { - vnThreadsRunning[THREAD_UPNP]--; - PrintException(NULL, "ThreadMapPort()"); - } - printf("ThreadMapPort exiting\n"); -} - -void ThreadMapPort2(void* parg) -{ - printf("ThreadMapPort started\n"); - - char port[6]; - sprintf(port, "%d", GetListenPort()); - - const char * multicastif = 0; - const char * minissdpdpath = 0; - struct UPNPDev * devlist = 0; - char lanaddr[64]; - -#ifndef UPNPDISCOVER_SUCCESS - /* miniupnpc 1.5 */ - devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0); -#else - /* miniupnpc 1.6 */ - int error = 0; - devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); -#endif - - struct UPNPUrls urls; - struct IGDdatas data; - int r; - - r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); - if (r == 1) - { - if (!addrLocalHost.IsRoutable()) - { - char externalIPAddress[40]; - r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); - if(r != UPNPCOMMAND_SUCCESS) - printf("UPnP: GetExternalIPAddress() returned %d\n", r); - else - { - if(externalIPAddress[0]) - { - printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress); - CAddress addrExternalFromUPnP(CService(externalIPAddress, 0), nLocalServices); - if (addrExternalFromUPnP.IsRoutable()) - addrLocalHost = addrExternalFromUPnP; - } - else - printf("UPnP: GetExternalIPAddress failed.\n"); - } - } - - string strDesc = "NovaCoin " + FormatFullVersion(); -#ifndef UPNPDISCOVER_SUCCESS - /* miniupnpc 1.5 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port, port, lanaddr, strDesc.c_str(), "TCP", 0); -#else - /* miniupnpc 1.6 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0"); -#endif - - if(r!=UPNPCOMMAND_SUCCESS) - printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - port, port, lanaddr, r, strupnperror(r)); - else - printf("UPnP Port Mapping successful.\n"); - int i = 1; - loop { - if (fShutdown || !fUseUPnP) - { - r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port, "TCP", 0); - printf("UPNP_DeletePortMapping() returned : %d\n", r); - freeUPNPDevlist(devlist); devlist = 0; - FreeUPNPUrls(&urls); - return; - } - if (i % 600 == 0) // Refresh every 20 minutes - { -#ifndef UPNPDISCOVER_SUCCESS - /* miniupnpc 1.5 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port, port, lanaddr, strDesc.c_str(), "TCP", 0); -#else - /* miniupnpc 1.6 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0"); -#endif - - if(r!=UPNPCOMMAND_SUCCESS) - printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - port, port, lanaddr, r, strupnperror(r)); - else - printf("UPnP Port Mapping successful.\n");; - } - Sleep(2000); - i++; - } - } else { - printf("No valid UPnP IGDs found\n"); - freeUPNPDevlist(devlist); devlist = 0; - if (r != 0) - FreeUPNPUrls(&urls); - loop { - if (fShutdown || !fUseUPnP) - return; - Sleep(2000); - } - } -} - -void MapPort(bool fMapPort) -{ - if (fUseUPnP != fMapPort) - { - fUseUPnP = fMapPort; - } - if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1) - { - if (!CreateThread(ThreadMapPort, NULL)) - printf("Error: ThreadMapPort(ThreadMapPort) failed\n"); - } -} -#else -void MapPort(bool /* unused fMapPort */) -{ - // Intentionally left blank. -} -#endif - - - - - - - - - // DNS seeds // Each pair gives a source name and a seed name. // The first name is used as information source for addrman. // The second name should resolve to a list of seed addresses. -// testnet dns seed begins with 't', all else are ppcoin dns seeds. static const char *strDNSSeed[][2] = { - {"seed", "xxx"} + {"novacoin.karelia.pro", "dnsseed.novacoin.karelia.pro"}, + {"novacoin.ru", "dnsseed.novacoin.ru"}, + {"novacoin.ru", "testseed.novacoin.ru"}, + {"novaco.in", "dnsseed.novaco.in"}, }; void ThreadDNSAddressSeed(void* parg) { - IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg)); + // Make this thread recognisable as the DNS seeding thread + RenameThread("novacoin-dnsseed"); + try { vnThreadsRunning[THREAD_DNSSEED]++; @@ -1001,7 +960,7 @@ void ThreadDNSAddressSeed(void* parg) vnThreadsRunning[THREAD_DNSSEED]--; throw; // support pthread_cancel() } - printf("ThreadDNSAddressSeed exiting\n"); + printf("ThreadDNSAddressSeed exited\n"); } void ThreadDNSAddressSeed2(void* parg) @@ -1009,28 +968,28 @@ void ThreadDNSAddressSeed2(void* parg) printf("ThreadDNSAddressSeed started\n"); int found = 0; - if (true && !fTestNet) + if (!fTestNet) { printf("Loading addresses from DNS seeds (could take a while)\n"); for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { - if (fTestNet && strDNSSeed[seed_idx][1][0] != 't') continue; - if ((!fTestNet) && strDNSSeed[seed_idx][1][0] == 't') continue; - - vector vaddr; - vector vAdd; - if (LookupHost(strDNSSeed[seed_idx][1], vaddr)) - { - BOOST_FOREACH(CNetAddr& ip, vaddr) + if (HaveNameProxy()) { + AddOneShot(strDNSSeed[seed_idx][1]); + } else { + vector vaddr; + vector vAdd; + if (LookupHost(strDNSSeed[seed_idx][1], vaddr)) { - int nOneDay = 24*3600; - CAddress addr = CAddress(CService(ip, GetDefaultPort())); - addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old - vAdd.push_back(addr); - found++; + BOOST_FOREACH(CNetAddr& ip, vaddr) + { + CAddress addr = CAddress(CService(ip, GetDefaultPort())); + addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old + vAdd.push_back(addr); + found++; + } } + addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true)); } - addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true)); } } @@ -1048,25 +1007,65 @@ void ThreadDNSAddressSeed2(void* parg) -unsigned int pnSeed[] = +uint32_t pnSeed[] = { - 0x90EF78BC, + 0xa52bf0da, 0x30aa43d8, 0x614488d5, 0x517b6fd5, 0xd4bf62d4, 0xb7d638d4, 0xbc12bcd1, 0xa2501bc6, + 0xfde617c6, 0x3337b1c6, 0x1dcd71c3, 0x2c1544c1, 0xe05f6ac1, 0x852f63c0, 0x3e2363c0, 0x15f563c0, + 0x430d63c0, 0x50d6a9c0, 0xf0a679c0, 0xefdeedbf, 0x7aaee8bc, 0x3a3dbbbc, 0xef218abc, 0x0bef78bc, + 0x8baa3eb2, 0x2bf913b2, 0x24ed9fb2, 0xb42289b2, 0x718a09b0, 0xe9433eb0, 0x559425b0, 0xc97e1fb0, + 0x18e1d4b0, 0x8f6cc1b0, 0xac3838ae, 0x86c0ffad, 0x6b0272a7, 0xa463f8a2, 0x6f17f3a2, 0xb3d6f3a2, + 0x9cd8f997, 0xd513fb94, 0x39e64880, 0x3859dd6f, 0x0b08fe6d, 0xe601fe6d, 0xeb44a26d, 0xfe53186c, + 0x203c2e68, 0x1c542868, 0x0caa8368, 0xb8748368, 0xccca4762, 0xc637555f, 0x638a545f, 0x59b2205f, + 0x52568c5f, 0xba568c5f, 0x8a568c5f, 0x31b0f45e, 0x54a0f45e, 0x37d6f15e, 0xc520175e, 0x7620175e, + 0xc310175e, 0x8e33b45e, 0x7abb5f5d, 0xd3014c5d, 0xa1e1485d, 0x9947645d, 0xfab8ff5c, 0xa979e65b, + 0xa879e65b, 0x9f79e65b, 0x9fa3d25b, 0x112a925b, 0x7b92905b, 0x60647a5b, 0x1e389d5a, 0x851afa59, + 0x0185ef59, 0x26549b59, 0x1c9efe57, 0xc54c1256, 0x1ad51955, 0x19d21955, 0x73c41955, 0x3f74ee55, + 0x633eea55, 0x6883d655, 0xfb72c655, 0x5360a653, 0x17c1ea52, 0xc661c852, 0x1ecdc852, 0x006a9752, + 0xf72d9252, 0x82650551, 0x36f1c851, 0x33f1c851, 0xd5c1864f, 0xb6bf1b4e, 0x96da184e, 0x40d0234d, + 0x9a96ab4c, 0x8fc2a84c, 0xb5dbd048, 0xf4644447, 0x2d51af47, 0xa9625445, 0x83f05243, 0x89672941, + 0x3a8bad3e, 0xf0a05436, 0x6ab7c936, 0x49971d32, 0xadd4482e, 0xcffd212e, 0x6730bc2e, 0x839aa12e, + 0x68d9692e, 0xc7183b25, 0x6c47bb25, 0x2490bb25, 0xad651c1f, 0x048a861f, 0x6937811f, 0x064b2d05, + 0x4d226805, +}; + +const char* pchTorSeed[] = +{ + "seedp4knqnoei57u.onion", + "seedr3hhlepyi7fd.onion", + "seed3uuomkclbiz4.onion", + "seedeh7qck3ouff5.onion", + "5rg3vq4jagckeckf.onion", + "seedt3sraf53ajiy.onion", + "seedg4qyccsg42oq.onion", + "novaqrtoywpg7jly.onion", + "seed3d5wolqbgrcb.onion", + "seed24u5dwph3qw4.onion", + "mj26ulzbs2oskgym.onion", + "eqon4usunavt76m7.onion", + "seedd3aldwpslzl3.onion" }; void DumpAddresses() { + int64_t nStart = GetTimeMillis(); + CAddrDB adb; - adb.WriteAddrman(addrman); + adb.Write(addrman); + + printf("Flushed %d addresses to peers.dat %" PRId64 "ms\n", + addrman.size(), GetTimeMillis() - nStart); } void ThreadDumpAddress2(void* parg) { + printf("ThreadDumpAddress started\n"); + vnThreadsRunning[THREAD_DUMPADDRESS]++; while (!fShutdown) { DumpAddresses(); vnThreadsRunning[THREAD_DUMPADDRESS]--; - Sleep(100000); + Sleep(600000); vnThreadsRunning[THREAD_DUMPADDRESS]++; } vnThreadsRunning[THREAD_DUMPADDRESS]--; @@ -1074,7 +1073,9 @@ void ThreadDumpAddress2(void* parg) void ThreadDumpAddress(void* parg) { - IMPLEMENT_RANDOMIZE_STACK(ThreadDumpAddress(parg)); + // Make this thread recognisable as the address dumping thread + RenameThread("novacoin-adrdump"); + try { ThreadDumpAddress2(parg); @@ -1082,12 +1083,14 @@ void ThreadDumpAddress(void* parg) catch (std::exception& e) { PrintException(&e, "ThreadDumpAddress()"); } - printf("ThreadDumpAddress exiting\n"); + printf("ThreadDumpAddress exited\n"); } void ThreadOpenConnections(void* parg) { - IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg)); + // Make this thread recognisable as the connection opening thread + RenameThread("novacoin-opencon"); + try { vnThreadsRunning[THREAD_OPENCONNECTIONS]++; @@ -1101,7 +1104,25 @@ void ThreadOpenConnections(void* parg) vnThreadsRunning[THREAD_OPENCONNECTIONS]--; PrintException(NULL, "ThreadOpenConnections()"); } - printf("ThreadOpenConnections exiting\n"); + printf("ThreadOpenConnections exited\n"); +} + +void static ProcessOneShot() +{ + string strDest; + { + LOCK(cs_vOneShots); + if (vOneShots.empty()) + return; + strDest = vOneShots.front(); + vOneShots.pop_front(); + } + CAddress addr; + CSemaphoreGrant grant(*semOutbound, true); + if (grant) { + if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true)) + AddOneShot(strDest); + } } void ThreadOpenConnections2(void* parg) @@ -1109,15 +1130,15 @@ void ThreadOpenConnections2(void* parg) printf("ThreadOpenConnections started\n"); // Connect to specific addresses - if (mapArgs.count("-connect")) + if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { - for (int64 nLoop = 0;; nLoop++) + for (int64_t nLoop = 0;; nLoop++) { + ProcessOneShot(); BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"]) { - CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS)); - if (addr.IsValid()) - OpenNetworkConnection(addr, false); + CAddress addr; + OpenNetworkConnection(addr, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { Sleep(500); @@ -1125,13 +1146,16 @@ void ThreadOpenConnections2(void* parg) return; } } + Sleep(500); } } // Initiate network connections - int64 nStart = GetTime(); - loop + int64_t nStart = GetTime(); + for ( ; ; ) { + ProcessOneShot(); + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; Sleep(500); vnThreadsRunning[THREAD_OPENCONNECTIONS]++; @@ -1140,14 +1164,13 @@ void ThreadOpenConnections2(void* parg) vnThreadsRunning[THREAD_OPENCONNECTIONS]--; - semOutbound->wait(); + CSemaphoreGrant grant(*semOutbound); vnThreadsRunning[THREAD_OPENCONNECTIONS]++; if (fShutdown) return; // Add seed nodes if IRC isn't working - bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050); - if (addrman.size()==0 && (GetTime() - nStart > 60 || fTOR) && !fTestNet) + if (!IsLimited(NET_IPV4) && addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet) { std::vector vAdd; for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++) @@ -1156,7 +1179,6 @@ void ThreadOpenConnections2(void* parg) // it'll get a pile of addresses with newer timestamps. // Seed nodes are given a random 'last seen time' of between one and two // weeks ago. - const int64 nOneWeek = 7*24*60*60; struct in_addr ip; memcpy(&ip, &pnSeed[i], sizeof(ip)); CAddress addr(CService(ip, GetDefaultPort())); @@ -1166,37 +1188,59 @@ void ThreadOpenConnections2(void* parg) addrman.Add(vAdd, CNetAddr("127.0.0.1")); } + // Add Tor nodes if we have connection with onion router + if (mapArgs.count("-tor")) + { + std::vector vAdd; + for (unsigned int i = 0; i < ARRAYLEN(pchTorSeed); i++) + { + CAddress addr(CService(pchTorSeed[i], GetDefaultPort())); + addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek; + vAdd.push_back(addr); + } + addrman.Add(vAdd, CNetAddr("dummyaddress.onion")); + } + // // Choose an address to connect to based on most recently seen // CAddress addrConnect; - // Only connect to one address per a.b.?.? range. + // Only connect out to one peer per network group (/16 for IPv4). // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. int nOutbound = 0; set > setConnected; { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - setConnected.insert(pnode->addr.GetGroup()); - if (!pnode->fInbound) + if (!pnode->fInbound) { + setConnected.insert(pnode->addr.GetGroup()); nOutbound++; + } } } - int64 nANow = GetAdjustedTime(); + int64_t nANow = GetAdjustedTime(); int nTries = 0; - loop + for ( ; ; ) { // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections) CAddress addr = addrman.Select(10 + min(nOutbound,8)*10); // if we selected an invalid address, restart - if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || addr == addrLocalHost) + if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) break; + // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman, + // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates + // already-connected network ranges, ...) before trying new addrman addresses. nTries++; + if (nTries > 100) + break; + + if (IsLimited(addr)) + continue; // only consider very recently tried nodes after 30 failed attempts if (nANow - addr.nLastTry < 600 && nTries < 30) @@ -1211,15 +1255,15 @@ void ThreadOpenConnections2(void* parg) } if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect); - else - semOutbound->post(); + OpenNetworkConnection(addrConnect, &grant); } } void ThreadOpenAddedConnections(void* parg) { - IMPLEMENT_RANDOMIZE_STACK(ThreadOpenAddedConnections(parg)); + // Make this thread recognisable as the connection opening thread + RenameThread("novacoin-opencon"); + try { vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; @@ -1233,51 +1277,87 @@ void ThreadOpenAddedConnections(void* parg) vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; PrintException(NULL, "ThreadOpenAddedConnections()"); } - printf("ThreadOpenAddedConnections exiting\n"); + printf("ThreadOpenAddedConnections exited\n"); } void ThreadOpenAddedConnections2(void* parg) { printf("ThreadOpenAddedConnections started\n"); - if (mapArgs.count("-addnode") == 0) + { + LOCK(cs_vAddedNodes); + vAddedNodes = mapMultiArgs["-addnode"]; + } + + if (HaveNameProxy()) { + while(!fShutdown) { + list lAddresses(0); + { + LOCK(cs_vAddedNodes); + BOOST_FOREACH(string& strAddNode, vAddedNodes) + lAddresses.push_back(strAddNode); + } + BOOST_FOREACH(string& strAddNode, lAddresses) { + CAddress addr; + CSemaphoreGrant grant(*semOutbound); + OpenNetworkConnection(addr, &grant, strAddNode.c_str()); + Sleep(500); + } + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; + Sleep(120000); // Retry every 2 minutes + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; + } return; + } - vector > vservAddressesToAdd(0); - BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) + for (uint32_t i = 0; true; i++) { - vector vservNode(0); - if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0)) + list lAddresses(0); + { + LOCK(cs_vAddedNodes); + BOOST_FOREACH(string& strAddNode, vAddedNodes) + lAddresses.push_back(strAddNode); + } + + list > lservAddressesToAdd(0); + BOOST_FOREACH(string& strAddNode, lAddresses) { - vservAddressesToAdd.push_back(vservNode); + vector vservNode(0); + if (Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0)) { - LOCK(cs_setservAddNodeAddresses); - BOOST_FOREACH(CService& serv, vservNode) - setservAddNodeAddresses.insert(serv); + lservAddressesToAdd.push_back(vservNode); + { + LOCK(cs_setservAddNodeAddresses); + BOOST_FOREACH(CService& serv, vservNode) + setservAddNodeAddresses.insert(serv); + } } } - } - loop - { - vector > vservConnectAddresses = vservAddressesToAdd; // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry - // (keeping in mind that addnode entries can have many IPs if fAllowDNS) + // (keeping in mind that addnode entries can have many IPs if fNameLookup) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) - for (vector >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++) + for (list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) + { BOOST_FOREACH(CService& addrNode, *(it)) if (pnode->addr == addrNode) { - it = vservConnectAddresses.erase(it); - it--; + it = lservAddressesToAdd.erase(it); + if(it != lservAddressesToAdd.begin()) + it--; break; } + if (it == lservAddressesToAdd.end()) + break; + } } - BOOST_FOREACH(vector& vserv, vservConnectAddresses) + BOOST_FOREACH(vector& vserv, lservAddressesToAdd) { - semOutbound->wait(); - OpenNetworkConnection(CAddress(*(vserv.begin()))); + if (vserv.size() == 0) + continue; + CSemaphoreGrant grant(*semOutbound); + OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); Sleep(500); if (fShutdown) return; @@ -1292,52 +1372,75 @@ void ThreadOpenAddedConnections2(void* parg) } } -bool static ReleaseGrant(bool fUseGrant) { - if (fUseGrant) - semOutbound->post(); - return false; -} - -// only call this function when semOutbound has been waited for -bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant) +// if successful, this moves the passed grant to the constructed node +bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot) { // // Initiate outbound network connection // if (fShutdown) return false; - if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() || - FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect)) - return ReleaseGrant(fUseGrant); + if (!strDest) + if (IsLocal(addrConnect) || + FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) || + FindNode(addrConnect.ToStringIPPort().c_str())) + return false; + if (strDest && FindNode(strDest)) + return false; vnThreadsRunning[THREAD_OPENCONNECTIONS]--; - CNode* pnode = ConnectNode(addrConnect); + CNode* pnode = ConnectNode(addrConnect, strDest); vnThreadsRunning[THREAD_OPENCONNECTIONS]++; if (fShutdown) return false; if (!pnode) - return ReleaseGrant(fUseGrant); - if (pnode->fHasGrant) { - // node already has connection grant, release the one that was passed to us - ReleaseGrant(fUseGrant); - } else { - pnode->fHasGrant = fUseGrant; - } + return false; + if (grantOutbound) + grantOutbound->MoveTo(pnode->grantOutbound); pnode->fNetworkNode = true; + if (fOneShot) + pnode->fOneShot = true; return true; } +// for now, use a very simple selection metric: the node from which we received +// most recently +static int64_t NodeSyncScore(const CNode *pnode) { + return pnode->nLastRecv; +} - - - - - +void static StartSync(const vector &vNodes) { + CNode *pnodeNewSync = NULL; + int64_t nBestScore = 0; + + // Iterate over all nodes + BOOST_FOREACH(CNode* pnode, vNodes) { + // check preconditions for allowing a sync + if (!pnode->fClient && !pnode->fOneShot && + !pnode->fDisconnect && pnode->fSuccessfullyConnected && + (pnode->nStartingHeight > (nBestHeight - 144)) && + (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) { + // if ok, compare node's score with the best so far + int64_t nScore = NodeSyncScore(pnode); + if (pnodeNewSync == NULL || nScore > nBestScore) { + pnodeNewSync = pnode; + nBestScore = nScore; + } + } + } + // if a new sync candidate was found, start sync! + if (pnodeNewSync) { + pnodeNewSync->fStartSync = true; + pnodeSync = pnodeNewSync; + } +} void ThreadMessageHandler(void* parg) { - IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg)); + // Make this thread recognisable as the message handling thread + RenameThread("novacoin-msghand"); + try { vnThreadsRunning[THREAD_MESSAGEHANDLER]++; @@ -1351,7 +1454,7 @@ void ThreadMessageHandler(void* parg) vnThreadsRunning[THREAD_MESSAGEHANDLER]--; PrintException(NULL, "ThreadMessageHandler()"); } - printf("ThreadMessageHandler exiting\n"); + printf("ThreadMessageHandler exited\n"); } void ThreadMessageHandler2(void* parg) @@ -1360,14 +1463,21 @@ void ThreadMessageHandler2(void* parg) SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); while (!fShutdown) { + bool fHaveSyncNode = false; vector vNodesCopy; { LOCK(cs_vNodes); vNodesCopy = vNodes; - BOOST_FOREACH(CNode* pnode, vNodesCopy) + BOOST_FOREACH(CNode* pnode, vNodesCopy) { pnode->AddRef(); + if (pnode == pnodeSync) + fHaveSyncNode = true; + } } + if (!fHaveSyncNode) + StartSync(vNodesCopy); + // Poll the connected nodes for messages CNode* pnodeTrickle = NULL; if (!vNodesCopy.empty()) @@ -1395,8 +1505,7 @@ void ThreadMessageHandler2(void* parg) { LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodesCopy) - pnode->Release(); + for_each(vNodesCopy.begin(), vNodesCopy.end(), Release); } // Wait and allow messages to bunch up. @@ -1412,52 +1521,31 @@ void ThreadMessageHandler2(void* parg) } } -// ppcoin: stake minter thread -void static ThreadStakeMinter(void* parg) -{ - printf("ThreadStakeMinter started\n"); - CWallet* pwallet = (CWallet*)parg; - try - { - vnThreadsRunning[THREAD_MINTER]++; - BitcoinMiner(pwallet, true); - vnThreadsRunning[THREAD_MINTER]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_MINTER]--; - PrintException(&e, "ThreadStakeMinter()"); - } catch (...) { - vnThreadsRunning[THREAD_MINTER]--; - PrintException(NULL, "ThreadStakeMinter()"); - } - printf("ThreadStakeMinter exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINTER]); -} - -bool BindListenPort(string& strError) +bool BindListenPort(const CService &addrBind, string& strError) { strError = ""; int nOne = 1; - addrLocalHost.SetPort(GetListenPort()); -#ifdef WIN32 - // Initialize Windows Sockets - WSADATA wsadata; - int ret = WSAStartup(MAKEWORD(2,2), &wsadata); - if (ret != NO_ERROR) + // Create socket for listening for incoming connections +#ifdef USE_IPV6 + struct sockaddr_storage sockaddr; +#else + struct sockaddr sockaddr; +#endif + socklen_t len = sizeof(sockaddr); + if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len)) { - strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret); + strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str()); printf("%s\n", strError.c_str()); return false; } -#endif - // Create socket for listening for incoming connections - hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP); if (hListenSocket == INVALID_SOCKET) { strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); @@ -1465,19 +1553,18 @@ bool BindListenPort(string& strError) return false; } +#ifndef WIN32 #ifdef SO_NOSIGPIPE // Different way of disabling SIGPIPE on BSD setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)); #endif - -#ifndef WIN32 // Allow binding if the port is still in TIME_WAIT state after - // the program was closed and restarted. Not an issue on windows. + // the program was closed and restarted. Not an issue on windows! setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); #endif #ifdef WIN32 - // Set to nonblocking, incoming connections will also inherit this + // Set to non-blocking, incoming connections will also inherit this if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) #else if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) @@ -1488,57 +1575,61 @@ bool BindListenPort(string& strError) return false; } - // The sockaddr_in structure specifies the address family, - // IP address, and port for the socket that is being bound - struct sockaddr_in sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer - sockaddr.sin_port = htons(GetListenPort()); - if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) +#ifdef USE_IPV6 + // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option + // and enable it by default or not. Try to enable it, if possible. + if (addrBind.IsIPv6()) { +#ifdef IPV6_V6ONLY +#ifdef WIN32 + setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int)); +#else + setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)); +#endif +#endif +#ifdef WIN32 + int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED; + setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)); +#endif + } +#endif + + if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) { int nErr = WSAGetLastError(); if (nErr == WSAEADDRINUSE) - strError = strprintf(_("Unable to bind to port %d on this computer. NovaCoin is probably already running."), ntohs(sockaddr.sin_port)); + strError = strprintf(_("Unable to bind to %s on this computer. NovaCoin is probably already running."), addrBind.ToString().c_str()); else - strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr); + strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr)); printf("%s\n", strError.c_str()); + CloseSocket(hListenSocket); return false; } - printf("Bound to port %d\n", ntohs(sockaddr.sin_port)); + printf("Bound to %s\n", addrBind.ToString().c_str()); // Listen for incoming connections if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) { strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError()); printf("%s\n", strError.c_str()); + CloseSocket(hListenSocket); return false; } + vhListenSocket.push_back(hListenSocket); + + if (addrBind.IsRoutable() && fDiscover) + AddLocal(addrBind, LOCAL_BIND); + return true; } -void StartNode(void* parg) +void static Discover() { - if (semOutbound == NULL) { - // initialize semaphore - int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125)); - semOutbound = new CSemaphore(nMaxOutbound); - } - -#ifdef USE_UPNP -#if USE_UPNP - fUseUPnP = GetBoolArg("-upnp", true); -#else - fUseUPnP = GetBoolArg("-upnp", false); -#endif -#endif - - if (pnodeLocalHost == NULL) - pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); + if (!fDiscover) + return; #ifdef WIN32 - // Get local host ip + // Get local host IP char pszHostName[1000] = ""; if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { @@ -1547,11 +1638,7 @@ void StartNode(void* parg) { BOOST_FOREACH (const CNetAddr &addr, vaddr) { - if (!addr.IsLocal()) - { - addrLocalHost.SetIP(addr); - break; - } + AddLocal(addr, LOCAL_IF); } } } @@ -1566,93 +1653,95 @@ void StartNode(void* parg) if ((ifa->ifa_flags & IFF_UP) == 0) continue; if (strcmp(ifa->ifa_name, "lo") == 0) continue; if (strcmp(ifa->ifa_name, "lo0") == 0) continue; - char pszIP[100]; if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr); - if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL) - printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP); - - // Take the first IP that isn't loopback 127.x.x.x - CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices); - if (addr.IsValid() && !addr.IsLocal()) - { - addrLocalHost = addr; - break; - } + CNetAddr addr(s4->sin_addr); + if (AddLocal(addr, LOCAL_IF)) + printf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); } +#ifdef USE_IPV6 else if (ifa->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr); - if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL) - printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP); + CNetAddr addr(s6->sin6_addr); + if (AddLocal(addr, LOCAL_IF)) + printf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); } +#endif } freeifaddrs(myaddrs); } #endif - printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); - if (fUseProxy || mapArgs.count("-connect") || fNoListen) - { - // Proxies can't take incoming connections - addrLocalHost.SetIP(CNetAddr("0.0.0.0")); - printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); - } - else - { - CreateThread(ThreadGetMyExternalIP, NULL); + // Don't use external IPv4 discovery, when -onlynet="IPv6" + if (!IsLimited(NET_IPV4)) + NewThread(ThreadGetMyExternalIP, NULL); +} + +void StartNode(void* parg) +{ + // Make this thread recognisable as the startup thread + RenameThread("novacoin-start"); + + if (semOutbound == NULL) { + // initialize semaphore + int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, GetArgInt("-maxconnections", 125)); + semOutbound = new CSemaphore(nMaxOutbound); } + if (pnodeLocalHost == NULL) + pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", nPortZero), nLocalServices)); + + Discover(); + // // Start threads // -/* if (!GetBoolArg("-dnsseed", true)) printf("DNS seeding disabled\n"); else - if (!CreateThread(ThreadDNSAddressSeed, NULL)) - printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n"); -*/ - - if (GetBoolArg("-dnsseed", false)) - printf("DNS seeding NYI\n"); - - // Map ports with UPnP - if (fHaveUPnP) - MapPort(fUseUPnP); + if (!NewThread(ThreadDNSAddressSeed, NULL)) + printf("Error: NewThread(ThreadDNSAddressSeed) failed\n"); // Get addresses from IRC and advertise ours - if (!CreateThread(ThreadIRCSeed, NULL)) - printf("Error: CreateThread(ThreadIRCSeed) failed\n"); + if (!GetBoolArg("-irc", true)) + printf("IRC seeding disabled\n"); + else + if (!NewThread(ThreadIRCSeed, NULL)) + printf("Error: NewThread(ThreadIRCSeed) failed\n"); // Send and receive from sockets, accept connections - if (!CreateThread(ThreadSocketHandler, NULL)) - printf("Error: CreateThread(ThreadSocketHandler) failed\n"); + if (!NewThread(ThreadSocketHandler, NULL)) + printf("Error: NewThread(ThreadSocketHandler) failed\n"); // Initiate outbound connections from -addnode - if (!CreateThread(ThreadOpenAddedConnections, NULL)) - printf("Error: CreateThread(ThreadOpenAddedConnections) failed\n"); + if (!NewThread(ThreadOpenAddedConnections, NULL)) + printf("Error: NewThread(ThreadOpenAddedConnections) failed\n"); // Initiate outbound connections - if (!CreateThread(ThreadOpenConnections, NULL)) - printf("Error: CreateThread(ThreadOpenConnections) failed\n"); + if (!NewThread(ThreadOpenConnections, NULL)) + printf("Error: NewThread(ThreadOpenConnections) failed\n"); // Process messages - if (!CreateThread(ThreadMessageHandler, NULL)) - printf("Error: CreateThread(ThreadMessageHandler) failed\n"); + if (!NewThread(ThreadMessageHandler, NULL)) + printf("Error: NewThread(ThreadMessageHandler) failed\n"); // Dump network addresses - if (!CreateThread(ThreadDumpAddress, NULL)) - printf("Error; CreateThread(ThreadDumpAddress) failed\n"); + if (!NewThread(ThreadDumpAddress, NULL)) + printf("Error; NewThread(ThreadDumpAddress) failed\n"); + + // Mine proof-of-stake blocks in the background + if (!NewThread(ThreadStakeMiner, pwalletMain)) + printf("Error: NewThread(ThreadStakeMiner) failed\n"); + + // Trusted NTP server, it's localhost by default. + strTrustedUpstream = GetArg("-ntp", "localhost"); - // Generate coins in the background - GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain); + // Start periodical NTP sampling thread + NewThread(ThreadNtpSamples, NULL); - // ppcoin: mint proof-of-stake blocks in the background - if (!CreateThread(ThreadStakeMinter, pwalletMain)) - printf("Error: CreateThread(ThreadStakeMinter) failed\n"); } bool StopNode() @@ -1660,11 +1749,15 @@ bool StopNode() printf("StopNode()\n"); fShutdown = true; nTransactionsUpdated++; - int64 nStart = GetTime(); + int64_t nStart = GetTime(); + { + LOCK(cs_main); + ThreadScriptCheckQuit(); + } if (semOutbound) for (int i=0; ipost(); - do + for ( ; ; ) { int nThreadsRunning = 0; for (int n = 0; n < THREAD_MAX; n++) @@ -1674,21 +1767,22 @@ bool StopNode() if (GetTime() - nStart > 20) break; Sleep(20); - } while(true); + }; if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n"); if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n"); if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n"); - if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n"); - if (vnThreadsRunning[THREAD_RPCSERVER] > 0) printf("ThreadRPCServer still running\n"); - if (fHaveUPnP && vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n"); + if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n"); + if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n"); if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n"); if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n"); if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n"); if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStakeMinter still running\n"); - while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCSERVER] > 0) + if (vnThreadsRunning[THREAD_SCRIPTCHECK] > 0) printf("ThreadScriptCheck still running\n"); + while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0 || vnThreadsRunning[THREAD_SCRIPTCHECK] > 0) Sleep(20); Sleep(50); DumpAddresses(); + return true; } @@ -1703,10 +1797,23 @@ public: // Close sockets BOOST_FOREACH(CNode* pnode, vNodes) if (pnode->hSocket != INVALID_SOCKET) - closesocket(pnode->hSocket); - if (hListenSocket != INVALID_SOCKET) - if (closesocket(hListenSocket) == SOCKET_ERROR) - printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); + CloseSocket(pnode->hSocket); + BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) + if (hListenSocket != INVALID_SOCKET) + if (!CloseSocket(hListenSocket)) + printf("CloseSocket(hListenSocket) failed with error %d\n", WSAGetLastError()); + + // clean up some globals (to help leak detection) + BOOST_FOREACH(CNode *pnode, vNodes) + delete pnode; + BOOST_FOREACH(CNode *pnode, vNodesDisconnected) + delete pnode; + vNodes.clear(); + vNodesDisconnected.clear(); + delete semOutbound; + semOutbound = NULL; + delete pnodeLocalHost; + pnodeLocalHost = NULL; #ifdef WIN32 // Shutdown Windows Sockets @@ -1715,3 +1822,55 @@ public: } } instance_of_cnetcleanup; + +void RelayTransaction(const CTransaction& tx, const uint256& hash) +{ + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(10000); + ss << tx; + RelayTransaction(tx, hash, ss); +} + +void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss) +{ + CInv inv(MSG_TX, hash); + { + LOCK(cs_mapRelay); + // Expire old relay messages + while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) + { + mapRelay.erase(vRelayExpiration.front().second); + vRelayExpiration.pop_front(); + } + + // Save original serialized message so newer versions are preserved + mapRelay.insert(std::make_pair(inv, ss)); + vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); + } + + RelayInventory(inv); +} + +void CNode::RecordBytesRecv(uint64_t bytes) +{ + LOCK(cs_totalBytesRecv); + nTotalBytesRecv += bytes; +} + +void CNode::RecordBytesSent(uint64_t bytes) +{ + LOCK(cs_totalBytesSent); + nTotalBytesSent += bytes; +} + +uint64_t CNode::GetTotalBytesRecv() +{ + LOCK(cs_totalBytesRecv); + return nTotalBytesRecv; +} + +uint64_t CNode::GetTotalBytesSent() +{ + LOCK(cs_totalBytesSent); + return nTotalBytesSent; +}