X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fnet.cpp;h=c69e83c0abc5e8403c215a125a0bf2f00f94f475;hp=027a1ef8fa1389118dc7f07ba24da4b2dcce39ca;hb=86ca35296e3e65c9a769a946f90a59b273063d9c;hpb=2bb194b8d6bd1137877bbb34830c8f56967846dd diff --git a/src/net.cpp b/src/net.cpp index 027a1ef..c69e83c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -7,21 +7,15 @@ #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; @@ -31,16 +25,22 @@ 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, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); +// 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; - int nPort; + uint16_t nPort; }; // @@ -48,25 +48,25 @@ struct LocalServiceInfo { // bool fClient = false; bool fDiscover = true; -bool fUseUPnP = false; -uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); +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; -CAddress addrSeenByPeer(CService("0.0.0.0", 0), nLocalServices); -uint64 nLocalHostNonce = 0; -array vnThreadsRunning; +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; @@ -74,6 +74,9 @@ CCriticalSection cs_vOneShots; set setservAddNodeAddresses; CCriticalSection cs_setservAddNodeAddresses; +vector vAddedNodes; +CCriticalSection cs_vAddedNodes; + static CSemaphore *semOutbound = NULL; void AddOneShot(string strDest) @@ -126,7 +129,7 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer) // get best local address for a particular peer as a CAddress CAddress GetLocalAddress(const CNetAddr *paddrPeer) { - CAddress ret(CService("0.0.0.0",0),0); + CAddress ret(CService("0.0.0.0", nPortZero), 0); CService addr; if (GetLocal(addr, paddrPeer)) { @@ -140,7 +143,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer) bool RecvLine(SOCKET hSocket, string& strLine) { strLine = ""; - while (true) + for ( ; ; ) { char c; int nBytes = recv(hSocket, &c, 1, 0); @@ -198,7 +201,7 @@ void static AdvertizeLocal() if (pnode->fSuccessfullyConnected) { CAddress addrLocal = GetLocalAddress(&pnode->addr); - if (addrLocal.IsRoutable() && (CService)addrLocal != (CService)pnode->addrLocal) + if (addrLocal.IsRoutable() && (CService)addrLocal != pnode->addrLocal) { pnode->PushAddress(addrLocal); pnode->addrLocal = addrLocal; @@ -300,116 +303,27 @@ bool IsReachable(const CNetAddr& addr) return vfReachable[net] && !vfLimited[net]; } -bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) -{ - 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)) - { - if (strLine.empty()) // HTTP response is separated from headers by blank line - { - while (true) - { - 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; - } - } - 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"); -} +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) { - CService addrConnect; - const char* pszGet; - const char* pszKeyword; - - 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 web server that prints the client IP: - // - if (nHost == 1) - { - addrConnect = CService("91.198.22.70",80); // checkip.dyndns.org - - if (nLookup == 1) - { - CService addrIP("checkip.dyndns.org", 80, true); - if (addrIP.IsValid()) - addrConnect = addrIP; - } - - 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"; - - pszKeyword = "Address:"; - } - else if (nHost == 2) - { - addrConnect = CService("74.208.43.192", 80); // www.showmyip.com - - if (nLookup == 1) - { - CService addrIP("www.showmyip.com", 80, true); - if (addrIP.IsValid()) - addrConnect = addrIP; - } - - 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"; - - pszKeyword = NULL; // Returns just IP address - } - - if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet)) - return true; + 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) { // Make this thread recognisable as the external IP detection thread - RenameThread("bitcoin-ext-ip"); + RenameThread("novacoin-ext-ip"); CNetAddr addrLocalHost; if (GetMyExternalIP(addrLocalHost)) @@ -431,17 +345,17 @@ 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; } @@ -456,16 +370,14 @@ CNode* FindNode(std::string addrName) 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, const char *pszDest, int64 nTimeout) +CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64_t nTimeout) { if (pszDest == NULL) { if (IsLocal(addrConnect)) @@ -535,10 +447,18 @@ void CNode::CloseSocketDisconnect() if (hSocket != INVALID_SOCKET) { printf("disconnecting node %s\n", addrName.c_str()); - closesocket(hSocket); - hSocket = INVALID_SOCKET; + 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() @@ -548,10 +468,28 @@ void CNode::Cleanup() void CNode::PushVersion() { - /// when NTP implemented, change to just nTime = GetAdjustedTime() - int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); - CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0))); - CAddress addrMe = GetLocalAddress(&addr); + 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, @@ -562,7 +500,7 @@ void CNode::PushVersion() -std::map CNode::setBanned; +std::map CNode::setBanned; CCriticalSection CNode::cs_setBanned; void CNode::ClearBanned() @@ -575,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; } @@ -595,9 +533,9 @@ bool CNode::Misbehaving(int howmuch) } 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); @@ -626,13 +564,15 @@ void CNode::copyStats(CNodeStats &stats) X(nReleaseTime); X(nStartingHeight); X(nMisbehavior); + X(nSendBytes); + X(nRecvBytes); + stats.fSyncNode = (this == pnodeSync); } #undef X - - - - +void Release(CNode* node) { + node->Release(); +} @@ -641,7 +581,7 @@ void CNode::copyStats(CNodeStats &stats) void ThreadSocketHandler(void* parg) { // Make this thread recognisable as the networking thread - RenameThread("bitcoin-net"); + RenameThread("novacoin-net"); try { @@ -659,13 +599,13 @@ void ThreadSocketHandler(void* parg) printf("ThreadSocketHandler exited\n"); } +static list vNodesDisconnected; + void ThreadSocketHandler2(void* parg) { printf("ThreadSocketHandler started\n"); - list vNodesDisconnected; - unsigned int nPrevNodeCount = 0; - - while (true) + size_t nPrevNodeCount = 0; + for ( ; ; ) { // // Disconnect nodes @@ -830,18 +770,18 @@ void ThreadSocketHandler2(void* parg) 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 { @@ -882,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 (%"PRIszu" bytes)\n", vRecv.size()); + printf("socket recv flood control disconnect (%" PRIszu " bytes)\n", vRecv.size()); pnode->CloseSocketDisconnect(); } else { @@ -898,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) { @@ -939,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) { @@ -980,185 +924,28 @@ 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) -{ - // Make this thread recognisable as the UPnP thread - RenameThread("bitcoin-UPnP"); - - 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 exited\n"); -} - -void ThreadMapPort2(void* parg) -{ - printf("ThreadMapPort started\n"); - - std::string port = strprintf("%u", 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 (fDiscover) { - 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); - AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP); - } - 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.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0); -#else - /* miniupnpc 1.6 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); -#endif - - if(r!=UPNPCOMMAND_SUCCESS) - printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - port.c_str(), port.c_str(), lanaddr, r, strupnperror(r)); - else - printf("UPnP Port Mapping successful.\n"); - int i = 1; - while (true) - { - if (fShutdown || !fUseUPnP) - { - r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "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.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0); -#else - /* miniupnpc 1.6 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); -#endif - - if(r!=UPNPCOMMAND_SUCCESS) - printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - port.c_str(), port.c_str(), 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); - while (true) - { - if (fShutdown || !fUseUPnP) - return; - Sleep(2000); - } - } -} - -void MapPort() -{ - if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1) - { - if (!NewThread(ThreadMapPort, NULL)) - printf("Error: ThreadMapPort(ThreadMapPort) failed\n"); - } -} -#else -void MapPort() -{ - // 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. static const char *strDNSSeed[][2] = { - {"novacoin.su", "dnsseed.novacoin.su"}, + {"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) { // Make this thread recognisable as the DNS seeding thread - RenameThread("bitcoin-dnsseed"); + RenameThread("novacoin-dnsseed"); try { @@ -1195,7 +982,6 @@ void ThreadDNSAddressSeed2(void* parg) { BOOST_FOREACH(CNetAddr& ip, 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); @@ -1221,24 +1007,59 @@ void ThreadDNSAddressSeed2(void* parg) -unsigned int pnSeed[] = +uint32_t pnSeed[] = { - 0x90EF78BC, 0x33F1C851, 0x36F1C851, 0xC6F5C851, + 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 nStart = GetTimeMillis(); + int64_t nStart = GetTimeMillis(); CAddrDB adb; adb.Write(addrman); - printf("Flushed %d addresses to peers.dat %"PRI64d"ms\n", + 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) { @@ -1253,7 +1074,7 @@ void ThreadDumpAddress2(void* parg) void ThreadDumpAddress(void* parg) { // Make this thread recognisable as the address dumping thread - RenameThread("bitcoin-adrdump"); + RenameThread("novacoin-adrdump"); try { @@ -1268,7 +1089,7 @@ void ThreadDumpAddress(void* parg) void ThreadOpenConnections(void* parg) { // Make this thread recognisable as the connection opening thread - RenameThread("bitcoin-opencon"); + RenameThread("novacoin-opencon"); try { @@ -1304,27 +1125,6 @@ void static ProcessOneShot() } } -// ppcoin: stake minter thread -void static ThreadStakeMinter(void* parg) -{ - printf("ThreadStakeMinter started\n"); - CWallet* pwallet = (CWallet*)parg; - try - { - vnThreadsRunning[THREAD_MINTER]++; - StakeMiner(pwallet); - 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]); -} - void ThreadOpenConnections2(void* parg) { printf("ThreadOpenConnections started\n"); @@ -1332,7 +1132,7 @@ void ThreadOpenConnections2(void* parg) // Connect to specific addresses 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"]) @@ -1351,8 +1151,8 @@ void ThreadOpenConnections2(void* parg) } // Initiate network connections - int64 nStart = GetTime(); - while (true) + int64_t nStart = GetTime(); + for ( ; ; ) { ProcessOneShot(); @@ -1370,7 +1170,7 @@ void ThreadOpenConnections2(void* parg) return; // Add seed nodes if IRC isn't working - if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet) + if (!IsLimited(NET_IPV4) && addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet) { std::vector vAdd; for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++) @@ -1379,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())); @@ -1389,6 +1188,19 @@ 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 // @@ -1408,10 +1220,10 @@ void ThreadOpenConnections2(void* parg) } } - int64 nANow = GetAdjustedTime(); + int64_t nANow = GetAdjustedTime(); int nTries = 0; - while (true) + for ( ; ; ) { // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections) CAddress addr = addrman.Select(10 + min(nOutbound,8)*10); @@ -1450,7 +1262,7 @@ void ThreadOpenConnections2(void* parg) void ThreadOpenAddedConnections(void* parg) { // Make this thread recognisable as the connection opening thread - RenameThread("bitcoin-opencon"); + RenameThread("novacoin-opencon"); try { @@ -1472,12 +1284,20 @@ void ThreadOpenAddedConnections2(void* parg) { printf("ThreadOpenAddedConnections started\n"); - if (mapArgs.count("-addnode") == 0) - return; + { + LOCK(cs_vAddedNodes); + vAddedNodes = mapMultiArgs["-addnode"]; + } if (HaveNameProxy()) { while(!fShutdown) { - BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) { + 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()); @@ -1490,41 +1310,54 @@ void ThreadOpenAddedConnections2(void* parg) 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(), fNameLookup, 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); + } } } - } - while (true) - { - 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 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) { + if (vserv.size() == 0) + continue; CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(CAddress(*(vserv.begin())), &grant); + OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); Sleep(500); if (fShutdown) return; @@ -1571,17 +1404,42 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu 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) { // Make this thread recognisable as the message handling thread - RenameThread("bitcoin-msghand"); + RenameThread("novacoin-msghand"); try { @@ -1605,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()) @@ -1640,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. @@ -1667,18 +1531,6 @@ bool BindListenPort(const CService &addrBind, string& strError) strError = ""; int nOne = 1; -#ifdef WIN32 - // Initialize Windows Sockets - WSADATA wsadata; - int ret = WSAStartup(MAKEWORD(2,2), &wsadata); - if (ret != NO_ERROR) - { - strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret); - printf("%s\n", strError.c_str()); - return false; - } -#endif - // Create socket for listening for incoming connections #ifdef USE_IPV6 struct sockaddr_storage sockaddr; @@ -1701,18 +1553,16 @@ bool BindListenPort(const CService &addrBind, 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 non-blocking, incoming connections will also inherit this if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) @@ -1737,10 +1587,8 @@ bool BindListenPort(const CService &addrBind, string& strError) #endif #endif #ifdef WIN32 - int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */; - int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */; - // this call is allowed to fail - setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int)); + int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED; + setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)); #endif } #endif @@ -1753,6 +1601,7 @@ bool BindListenPort(const CService &addrBind, string& strError) else 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 %s\n", addrBind.ToString().c_str()); @@ -1762,6 +1611,7 @@ bool BindListenPort(const CService &addrBind, string& strError) { strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError()); printf("%s\n", strError.c_str()); + CloseSocket(hListenSocket); return false; } @@ -1832,16 +1682,16 @@ void static Discover() void StartNode(void* parg) { // Make this thread recognisable as the startup thread - RenameThread("bitcoin-start"); + RenameThread("novacoin-start"); if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125)); + 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", 0), nLocalServices)); + pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", nPortZero), nLocalServices)); Discover(); @@ -1855,13 +1705,12 @@ void StartNode(void* parg) if (!NewThread(ThreadDNSAddressSeed, NULL)) printf("Error: NewThread(ThreadDNSAddressSeed) failed\n"); - // Map ports with UPnP - if (fUseUPnP) - MapPort(); - // Get addresses from IRC and advertise ours - if (!NewThread(ThreadIRCSeed, NULL)) - printf("Error: NewThread(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 (!NewThread(ThreadSocketHandler, NULL)) @@ -1883,9 +1732,16 @@ void StartNode(void* parg) if (!NewThread(ThreadDumpAddress, NULL)) printf("Error; NewThread(ThreadDumpAddress) failed\n"); - // ppcoin: mint proof-of-stake blocks in the background - if (!NewThread(ThreadStakeMinter, pwalletMain)) - printf("Error: NewThread(ThreadStakeMinter) 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"); + + // Start periodical NTP sampling thread + NewThread(ThreadNtpSamples, NULL); + } bool StopNode() @@ -1893,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++) @@ -1907,23 +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_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n"); if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n"); -#ifdef USE_UPNP - if (vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n"); -#endif 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_RPCHANDLER] > 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; } @@ -1938,11 +1797,23 @@ public: // Close sockets BOOST_FOREACH(CNode* pnode, vNodes) if (pnode->hSocket != INVALID_SOCKET) - closesocket(pnode->hSocket); + CloseSocket(pnode->hSocket); BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) if (hListenSocket != INVALID_SOCKET) - if (closesocket(hListenSocket) == SOCKET_ERROR) - printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); + 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 @@ -1979,3 +1850,27 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt 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; +}