X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fntp.cpp;h=76b0afdf34d8fed2032cc12fa425b2a4c74700e4;hp=25772c0c9df12c3e41c1a4779bc2e869b11738b5;hb=4ca0237ec0d2825004fa3aa2b00a94da2a083b8b;hpb=d6a773b1bef3c444da6baa29a441b9376e5143b7 diff --git a/src/ntp.cpp b/src/ntp.cpp index 25772c0..76b0afd 100644 --- a/src/ntp.cpp +++ b/src/ntp.cpp @@ -1,4 +1,3 @@ - #ifdef WIN32 #include #else @@ -13,7 +12,9 @@ #endif #include "netbase.h" -#include "util.h" +#include "net.h" +//#include "util.h" +#include "ui_interface.h" extern int GetRandInt(int nMax); @@ -51,15 +52,13 @@ typedef struct { } l_fp; -inline void Ntp2Unix(uint32_t &n, time_t &u) -{ +inline void Ntp2Unix(const uint32_t &n, time_t &u) { // Ntp's time scale starts in 1900, Unix in 1970. u = n - 0x83aa7e80; // 2208988800 1970 - 1900 in seconds } -inline void ntohl_fp(l_fp *n, l_fp *h) -{ +inline void ntohl_fp(l_fp *n, l_fp *h) { (h)->Ul_i.Xl_ui = ntohl((n)->Ul_i.Xl_ui); (h)->Ul_f.Xl_uf = ntohl((n)->Ul_f.Xl_uf); } @@ -81,9 +80,12 @@ struct pkt { uint8_t mac[5 * sizeof(uint32_t)]; /* mac */ }; -int nServersCount = 107; +const int nServersCount = 154; + +std::string NtpServers[nServersCount] = { + // Apple + "time.apple.com", -std::string NtpServers[107] = { // Microsoft "time.windows.com", @@ -93,19 +95,27 @@ std::string NtpServers[107] = { "time3.google.com", "time4.google.com", + // Hurricane Electric + "clock.sjc.he.net", + "clock.nyc.he.net", + // Russian Federation + "ntp.karelia.pro", + "ntp.alpet.me", + "aviel.alpet.me", + "ntp.sampo.ru", + "ntp.szt.ru", "ntp.ix.ru", "ntp1.stratum2.ru", "ntp2.stratum2.ru", "ntp3.stratum2.ru", "ntp4.stratum2.ru", "ntp5.stratum2.ru", - "ntp6.stratum2.ru", - "ntp7.stratum2.ru", "ntp1.stratum1.ru", "ntp2.stratum1.ru", "ntp3.stratum1.ru", "ntp4.stratum1.ru", + "ntp5.stratum1.ru", "ntp1.vniiftri.ru", "ntp2.vniiftri.ru", "ntp3.vniiftri.ru", @@ -123,31 +133,40 @@ std::string NtpServers[107] = { "3.ru.pool.ntp.org", // United States + "tock.cs.unlv.edu", + "timex.cs.columbia.edu", + "tick.cs.unlv.edu", + "sundial.columbia.edu", + "ntp-1.ece.cmu.edu", + "ntp-2.ece.cmu.edu", + "ntp-3.ece.cmu.edu", + "ntp1.cs.wisc.edu", + "ntp2.cs.wisc.edu", + "ntp3.cs.wisc.edu", + "ntp4.cs.wisc.edu", "ntp-01.caltech.edu", "ntp-02.caltech.edu", "ntp-03.caltech.edu", "ntp-04.caltech.edu", + "nist0-pa.ustiming.org", "nist1-pa.ustiming.org", - "time-a.nist.gov ", - "time-b.nist.gov ", - "time-c.nist.gov ", - "time-d.nist.gov ", + "nist2-pa.ustiming.org", + "time.nist.gov", + "time-a.nist.gov", + "time-b.nist.gov", + "time-c.nist.gov", + "time-d.nist.gov", + "time-nw.nist.gov", "nist1-macon.macon.ga.us", "nist.netservicesgroup.com", - "nisttime.carsoncity.k12.mi.us", - "nist1-lnk.binary.net", "wwv.nist.gov", "time-a.timefreq.bldrdoc.gov", "time-b.timefreq.bldrdoc.gov", "time-c.timefreq.bldrdoc.gov", - "time.nist.gov", "utcnist.colorado.edu", "utcnist2.colorado.edu", - "ntp-nist.ldsbc.net", "nist1-lv.ustiming.org", "time-nw.nist.gov", - "nist-time-server.eoni.com", - "nist-time-server.eoni.com", "ntp1.bu.edu", "ntp2.bu.edu", "ntp3.bu.edu", @@ -155,6 +174,12 @@ std::string NtpServers[107] = { "1.us.pool.ntp.org", "2.us.pool.ntp.org", "3.us.pool.ntp.org", + "otc1.psu.edu", + "otc2.psu.edu", + "now.okstate.edu", + "ntp.colby.edu", + "bonehed.lcs.mit.edu", + "ntp-s1.cise.ufl.edu", // South Africa "ntp1.meraka.csir.co.za", @@ -174,6 +199,9 @@ std::string NtpServers[107] = { "3.za.pool.ntp.org", // Italy + "ntp0.ien.it", + "ntp1.ien.it", + "ntp2.ien.it", "ntp1.inrim.it", "ntp2.inrim.it", "0.it.pool.ntp.org", @@ -194,6 +222,7 @@ std::string NtpServers[107] = { // United Kingdom "ntp2d.mcc.ac.uk", "ntp2c.mcc.ac.uk", + "ntp2b.mcc.ac.uk", "ntp.exnet.com", "ntp.cis.strath.ac.uk", "ntppub.le.ac.uk", @@ -202,6 +231,17 @@ std::string NtpServers[107] = { "2.uk.pool.ntp.org", "3.uk.pool.ntp.org", + // Canada + "chime.utoronto.ca", + "tick.utoronto.ca", + "time.nrc.ca", + "timelord.uregina.ca", + "tock.utoronto.ca", + "0.ca.pool.ntp.org", + "1.ca.pool.ntp.org", + "2.ca.pool.ntp.org", + "3.ca.pool.ntp.org", + // Japan "ntp.nict.jp", "0.jp.pool.ntp.org", @@ -209,91 +249,60 @@ std::string NtpServers[107] = { "2.jp.pool.ntp.org", "3.jp.pool.ntp.org", - // ... To be continued -}; - -bool InitWithRandom(SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) -{ - int nAttempt = 0; - - while(nAttempt < 100) - { - sockfd = -1; - nAttempt++; - - int nServerNum = GetRandInt(nServersCount); - - std::vector vIP; - bool fRet = LookupHost(NtpServers[nServerNum].c_str(), vIP, 10, true); - if (!fRet) - continue; - - struct sockaddr_in servaddr; - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(123); - - bool found = false; - for(unsigned int i = 0; i < vIP.size(); i++) - { - if ((found = vIP[i].GetInAddr(&servaddr.sin_addr))) - { - break; - } - } - - if (!found) - continue; - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); + // Australia + "ntp.cs.mu.oz.au", + "augean.eleceng.adelaide.edu.au", + "0.au.pool.ntp.org", + "1.au.pool.ntp.org", + "2.au.pool.ntp.org", + "3.au.pool.ntp.org", - if (sockfd == INVALID_SOCKET) - continue; // socket initialization error + // Slovenia + "time.ijs.si", - if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 ) - { - continue; // "connection" error - } + // Austria + "0.at.pool.ntp.org", + "1.at.pool.ntp.org", + "2.at.pool.ntp.org", + "3.at.pool.ntp.org", - *pcliaddr = *((struct sockaddr *) &servaddr); - servlen = sizeof(servaddr); - return true; - } + // ??? + "clepsydra.dec.com", - return false; -} + // ... To be continued +}; -bool InitWithHost(std::string &strHostName, SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) -{ - sockfd = -1; +bool InitWithHost(const std::string &strHostName, SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) { + + sockfd = INVALID_SOCKET; std::vector vIP; bool fRet = LookupHost(strHostName.c_str(), vIP, 10, true); - if (!fRet) + if (!fRet) { return false; + } struct sockaddr_in servaddr; servaddr.sin_family = AF_INET; servaddr.sin_port = htons(123); bool found = false; - for(unsigned int i = 0; i < vIP.size(); i++) - { - if ((found = vIP[i].GetInAddr(&servaddr.sin_addr))) - { + for(unsigned int i = 0; i < vIP.size(); i++) { + if ((found = vIP[i].GetInAddr(&servaddr.sin_addr)) != false) { break; } } - if (!found) + if (!found) { return false; + } sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd == INVALID_SOCKET) return false; // socket initialization error - if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 ) - { + if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 ) { return false; // "connection" error } @@ -304,25 +313,37 @@ bool InitWithHost(std::string &strHostName, SOCKET &sockfd, socklen_t &servlen, return true; } +bool InitWithRandom(SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) { + + for (int nAttempt = 0; nAttempt < nServersCount; nAttempt++) { + int nServerNum = GetRandInt(nServersCount); + if (InitWithHost(NtpServers[nServerNum], sockfd, servlen, pcliaddr)) { + return true; + } + } + + return false; +} + +int64_t DoReq(SOCKET sockfd, socklen_t servlen, struct sockaddr cliaddr) { -int64_t DoReq(SOCKET sockfd, socklen_t servlen, struct sockaddr cliaddr) -{ #ifdef WIN32 u_long nOne = 1; - if (ioctlsocket(sockfd, FIONBIO, &nOne) == SOCKET_ERROR) - { + if (ioctlsocket(sockfd, FIONBIO, &nOne) == SOCKET_ERROR) { printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError()); #else - if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) - { + if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) { printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno); #endif return -2; } + struct timeval timeout = {10, 0}; struct pkt *msg = new pkt; struct pkt *prt = new pkt; + time_t seconds_transmit; + int len = 48; msg->li_vn_mode=227; msg->stratum=0; @@ -340,44 +361,37 @@ int64_t DoReq(SOCKET sockfd, socklen_t servlen, struct sockaddr cliaddr) msg->xmt.Ul_i.Xl_i=0; msg->xmt.Ul_f.Xl_f=0; - int len=48; int retcode = sendto(sockfd, (char *) msg, len, 0, &cliaddr, servlen); if (retcode < 0) { - printf("sendto() failed: %d", retcode); - return -3; + printf("sendto() failed: %d\n", retcode); + seconds_transmit = -3; + goto _end; } fd_set fdset; - struct timeval timeout = {5, 0}; FD_ZERO(&fdset); FD_SET(sockfd, &fdset); retcode = select(sockfd + 1, &fdset, NULL, NULL, &timeout); - if (retcode <= 0) - { - printf("recvfrom() error"); - return -4; + if (retcode <= 0) { + printf("recvfrom() error\n"); + seconds_transmit = -4; + goto _end; } recvfrom(sockfd, (char *) msg, len, 0, NULL, NULL); - - ntohl_fp(&msg->rec, &prt->rec); ntohl_fp(&msg->xmt, &prt->xmt); - - time_t seconds_receive; - time_t seconds_transmit; - - Ntp2Unix(prt->rec.Ul_i.Xl_ui, seconds_receive); Ntp2Unix(prt->xmt.Ul_i.Xl_ui, seconds_transmit); + _end: + delete msg; delete prt; - return (seconds_receive + seconds_transmit) / 2; + return seconds_transmit; } -int64_t NtpGetTime() -{ +int64_t NtpGetTime(CNetAddr& ip) { struct sockaddr cliaddr; SOCKET sockfd; @@ -386,44 +400,128 @@ int64_t NtpGetTime() if (!InitWithRandom(sockfd, servlen, &cliaddr)) return -1; + ip = CNetAddr(((sockaddr_in *)&cliaddr)->sin_addr); int64_t nTime = DoReq(sockfd, servlen, cliaddr); - closesocket(sockfd); + CloseSocket(sockfd); return nTime; } -int64_t NtpGetTime(CNetAddr& ip) +int64_t NtpGetTime(const std::string &strHostName) { struct sockaddr cliaddr; SOCKET sockfd; socklen_t servlen; - if (!InitWithRandom(sockfd, servlen, &cliaddr)) + if (!InitWithHost(strHostName, sockfd, servlen, &cliaddr)) return -1; - ip = CNetAddr(((sockaddr_in *)&cliaddr)->sin_addr); int64_t nTime = DoReq(sockfd, servlen, cliaddr); - closesocket(sockfd); + CloseSocket(sockfd); return nTime; } -int64_t NtpGetTime(std::string &strHostName) -{ - struct sockaddr cliaddr; +// NTP server, which we unconditionally trust. This may be your own installation of ntpd somewhere, for example. +// "localhost" means "trust no one" +std::string strTrustedUpstream = "localhost"; - SOCKET sockfd; - socklen_t servlen; +// Current offset +int64_t nNtpOffset = INT64_MAX; - if (!InitWithHost(strHostName, sockfd, servlen, &cliaddr)) - return -1; +int64_t GetNtpOffset() { + return nNtpOffset; +} - int64_t nTime = DoReq(sockfd, servlen, cliaddr); +void ThreadNtpSamples(void* parg) { + const int64_t nMaxOffset = nOneDay; // Not a real limit, just sanity threshold. - closesocket(sockfd); + printf("Trying to find NTP server at localhost...\n"); - return nTime; + std::string strLocalHost = "127.0.0.1"; + if (NtpGetTime(strLocalHost) == GetTime()) { + printf("There is NTP server active at localhost, we don't need NTP thread.\n"); + + nNtpOffset = 0; + return; + } + + printf("ThreadNtpSamples started\n"); + vnThreadsRunning[THREAD_NTP]++; + + // Make this thread recognisable as time synchronization thread + RenameThread("novacoin-ntp-samples"); + + CMedianFilter vTimeOffsets(200,0); + + while (!fShutdown) { + if (strTrustedUpstream != "localhost") { + // Trying to get new offset sample from trusted NTP server. + int64_t nClockOffset = NtpGetTime(strTrustedUpstream) - GetTime(); + + if (abs64(nClockOffset) < nMaxOffset) { + // Everything seems right, remember new trusted offset. + printf("ThreadNtpSamples: new offset sample from %s, offset=%" PRId64 ".\n", strTrustedUpstream.c_str(), nClockOffset); + nNtpOffset = nClockOffset; + } + else { + // Something went wrong, disable trusted offset sampling. + nNtpOffset = INT64_MAX; + strTrustedUpstream = "localhost"; + + int nSleepMinutes = 1 + GetRandInt(9); // Sleep for 1-10 minutes. + for (int i = 0; i < nSleepMinutes * 60 && !fShutdown; i++) + Sleep(1000); + + continue; + } + } + else { + // Now, trying to get 2-4 samples from random NTP servers. + int nSamplesCount = 2 + GetRandInt(2); + + for (int i = 0; i < nSamplesCount; i++) { + CNetAddr ip; + int64_t nClockOffset = NtpGetTime(ip) - GetTime(); + + if (abs64(nClockOffset) < nMaxOffset) { // Skip the deliberately wrong timestamps + printf("ThreadNtpSamples: new offset sample from %s, offset=%" PRId64 ".\n", ip.ToString().c_str(), nClockOffset); + vTimeOffsets.input(nClockOffset); + } + } + + if (vTimeOffsets.size() > 1) { + nNtpOffset = vTimeOffsets.median(); + } + else { + // Not enough offsets yet, try to collect additional samples later. + nNtpOffset = INT64_MAX; + int nSleepMinutes = 1 + GetRandInt(4); // Sleep for 1-5 minutes. + for (int i = 0; i < nSleepMinutes * 60 && !fShutdown; i++) + Sleep(1000); + continue; + } + } + + if (GetNodesOffset() == INT_MAX && abs64(nNtpOffset) > 40 * 60) + { + // If there is not enough node offsets data and NTP time offset is greater than 40 minutes then give a warning. + std::string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong NovaCoin will not work properly."); + strMiscWarning = strMessage; + printf("*** %s\n", strMessage.c_str()); + uiInterface.ThreadSafeMessageBox(strMessage+" ", std::string("NovaCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION); + } + + printf("nNtpOffset = %+" PRId64 " (%+" PRId64 " minutes)\n", nNtpOffset, nNtpOffset/60); + + int nSleepHours = 1 + GetRandInt(5); // Sleep for 1-6 hours. + for (int i = 0; i < nSleepHours * 3600 && !fShutdown; i++) + Sleep(1000); + } + + vnThreadsRunning[THREAD_NTP]--; + printf("ThreadNtpSamples exited\n"); }