7 #include "ui_interface.h"
9 extern int GetRandInt(int nMax);
12 * NTP uses two fixed point formats. The first (l_fp) is the "long"
13 * format and is 64 bits long with the decimal between bits 31 and 32.
14 * This is used for time stamps in the NTP packet header (in network
15 * byte order) and for internal computations of offsets (in local host
16 * byte order). We use the same structure for both signed and unsigned
17 * values, which is a big hack but saves rewriting all the operators
18 * twice. Just to confuse this, we also sometimes just carry the
19 * fractional part in calculations, in both signed and unsigned forms.
20 * Anyway, an l_fp looks like:
23 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
24 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29 * REF http://www.eecis.udel.edu/~mills/database/rfc/rfc2030.txt
45 inline void Ntp2Unix(const uint32_t &n, time_t &u) {
46 // Ntp's time scale starts in 1900, Unix in 1970.
48 u = n - 0x83aa7e80; // 2208988800 1970 - 1900 in seconds
51 inline void ntohl_fp(l_fp *n, l_fp *h) {
52 (h)->Ul_i.Xl_ui = ntohl((n)->Ul_i.Xl_ui);
53 (h)->Ul_f.Xl_uf = ntohl((n)->Ul_f.Xl_uf);
57 uint8_t li_vn_mode=227; /* leap indicator, version and mode */
58 uint8_t stratum=0; /* peer stratum */
59 uint8_t ppoll=4; /* peer poll interval */
60 int8_t precision=0; /* peer clock precision */
61 uint32_t rootdelay=0; /* distance to primary clock */
62 uint32_t rootdispersion=0; /* clock dispersion */
63 uint32_t refid=0; /* reference clock ID */
64 l_fp ref; /* time peer clock was last updated */
65 l_fp org; /* originate time stamp */
66 l_fp rec; /* receive time stamp */
67 l_fp xmt; /* transmit time stamp */
69 uint32_t exten[1] = {0}; /* misused */
70 uint8_t mac[5 * sizeof(uint32_t)] = {0}; /* mac */
73 const int nServersCount = 162;
75 std::string NtpServers[162] = {
118 "ntp1.niiftri.irkutsk.ru",
119 "ntp2.niiftri.irkutsk.ru",
131 "timex.cs.columbia.edu",
133 "sundial.columbia.edu",
139 "ntp-01.caltech.edu",
140 "ntp-02.caltech.edu",
141 "ntp-03.caltech.edu",
142 "ntp-04.caltech.edu",
143 "nist1-pa.ustiming.org",
150 "nist1-macon.macon.ga.us",
151 "nist.netservicesgroup.com",
152 "nisttime.carsoncity.k12.mi.us",
153 "nist1-lnk.binary.net",
155 "time-a.timefreq.bldrdoc.gov",
156 "time-b.timefreq.bldrdoc.gov",
157 "time-c.timefreq.bldrdoc.gov",
158 "utcnist.colorado.edu",
159 "utcnist2.colorado.edu",
160 "ntp-nist.ldsbc.net",
161 "nist1-lv.ustiming.org",
163 "nist-time-server.eoni.com",
164 "nist-time-server.eoni.com",
177 "bonehed.lcs.mit.edu",
178 "ntp-s1.cise.ufl.edu",
181 "ntp1.meraka.csir.co.za",
185 "ntp1.neology.co.za",
186 "ntp2.neology.co.za",
187 "tick.meraka.csir.co.za",
188 "tock.meraka.csir.co.za",
190 "ntp1.meraka.csir.co.za",
191 "ntp2.meraka.csir.co.za",
223 "ntp.cis.strath.ac.uk",
234 "timelord.uregina.ca",
252 "augean.eleceng.adelaide.edu.au",
270 // ... To be continued
273 bool InitWithHost(const std::string &strHostName, SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) {
275 sockfd = INVALID_SOCKET;
277 std::vector<CNetAddr> vIP;
278 bool fRet = LookupHost(strHostName, vIP, 10, true);
283 struct sockaddr_in servaddr = {};
284 servaddr.sin_family = AF_INET;
285 servaddr.sin_port = htons(123);
288 for(unsigned int i = 0; i < vIP.size(); i++) {
289 if ((found = vIP[i].GetInAddr(&servaddr.sin_addr)) != false) {
298 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
300 if (sockfd == INVALID_SOCKET)
301 return false; // socket initialization error
303 if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 ) {
304 return false; // "connection" error
308 *pcliaddr = *((struct sockaddr *) &servaddr);
309 servlen = sizeof(servaddr);
314 bool InitWithRandom(SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) {
316 for (int nAttempt = 0; nAttempt < nServersCount; nAttempt++) {
317 int nServerNum = GetRandInt(nServersCount);
318 if (InitWithHost(NtpServers[nServerNum], sockfd, servlen, pcliaddr)) {
326 int64_t DoReq(SOCKET sockfd, socklen_t servlen, struct sockaddr cliaddr) {
331 if (ioctlsocket(sockfd, FIONBIO, &nOne) == SOCKET_ERROR) {
332 printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
334 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) {
335 printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
340 struct timeval timeout = {10, 0};
341 struct pkt *msg = new pkt;
342 struct pkt *prt = new pkt;
343 time_t seconds_transmit;
346 int retcode = sendto(sockfd, (char *) msg, len, 0, &cliaddr, servlen);
348 printf("sendto() failed: %d\n", retcode);
349 seconds_transmit = -3;
355 FD_SET(sockfd, &fdset);
357 retcode = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
359 printf("recvfrom() error\n");
360 seconds_transmit = -4;
364 recvfrom(sockfd, (char *) msg, len, 0, NULL, NULL);
365 ntohl_fp(&msg->xmt, &prt->xmt);
366 Ntp2Unix(prt->xmt.Ul_i.Xl_ui, seconds_transmit);
373 return seconds_transmit;
376 int64_t NtpGetTime(CNetAddr& ip) {
377 struct sockaddr cliaddr;
382 if (!InitWithRandom(sockfd, servlen, &cliaddr))
385 ip = CNetAddr(((sockaddr_in *)&cliaddr)->sin_addr);
386 int64_t nTime = DoReq(sockfd, servlen, cliaddr);
393 int64_t NtpGetTime(const std::string &strHostName)
395 struct sockaddr cliaddr;
400 if (!InitWithHost(strHostName, sockfd, servlen, &cliaddr))
403 int64_t nTime = DoReq(sockfd, servlen, cliaddr);
410 // NTP server, which we unconditionally trust. This may be your own installation of ntpd somewhere, for example.
411 // "localhost" means "trust no one"
412 std::string strTrustedUpstream = "localhost";
415 int64_t nNtpOffset = numeric_limits<int64_t>::max();
417 int64_t GetNtpOffset() {
421 void ThreadNtpSamples(void* parg) {
422 const int64_t nMaxOffset = nOneDay; // Not a real limit, just sanity threshold.
424 printf("Trying to find NTP server at localhost...\n");
426 std::string strLocalHost = "127.0.0.1";
427 if (NtpGetTime(strLocalHost) == GetTime()) {
428 printf("There is NTP server active at localhost, we don't need NTP thread.\n");
434 printf("ThreadNtpSamples started\n");
435 vnThreadsRunning[THREAD_NTP]++;
437 // Make this thread recognisable as time synchronization thread
438 RenameThread("novacoin-ntp-samples");
440 CMedianFilter<int64_t> vTimeOffsets(200,0);
443 if (strTrustedUpstream != "localhost") {
444 // Trying to get new offset sample from trusted NTP server.
445 int64_t nClockOffset = NtpGetTime(strTrustedUpstream) - GetTime();
447 if (abs(nClockOffset) < nMaxOffset) {
448 // Everything seems right, remember new trusted offset.
449 printf("ThreadNtpSamples: new offset sample from %s, offset=%" PRId64 ".\n", strTrustedUpstream.c_str(), nClockOffset);
450 nNtpOffset = nClockOffset;
453 // Something went wrong, disable trusted offset sampling.
454 nNtpOffset = numeric_limits<int64_t>::max();
455 strTrustedUpstream = "localhost";
457 int nSleepMinutes = 1 + GetRandInt(9); // Sleep for 1-10 minutes.
458 for (int i = 0; i < nSleepMinutes * 60 && !fShutdown; i++)
465 // Now, trying to get 2-4 samples from random NTP servers.
466 int nSamplesCount = 2 + GetRandInt(2);
468 for (int i = 0; i < nSamplesCount; i++) {
470 int64_t nClockOffset = NtpGetTime(ip) - GetTime();
472 if (abs(nClockOffset) < nMaxOffset) { // Skip the deliberately wrong timestamps
473 printf("ThreadNtpSamples: new offset sample from %s, offset=%" PRId64 ".\n", ip.ToString().c_str(), nClockOffset);
474 vTimeOffsets.input(nClockOffset);
478 if (vTimeOffsets.size() > 1) {
479 nNtpOffset = vTimeOffsets.median();
482 // Not enough offsets yet, try to collect additional samples later.
483 nNtpOffset = numeric_limits<int64_t>::max();
484 int nSleepMinutes = 1 + GetRandInt(4); // Sleep for 1-5 minutes.
485 for (int i = 0; i < nSleepMinutes * 60 && !fShutdown; i++)
491 if (GetNodesOffset() == numeric_limits<int64_t>::max() && abs(nNtpOffset) > 40 * 60)
493 // If there is not enough node offsets data and NTP time offset is greater than 40 minutes then give a warning.
494 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.");
495 strMiscWarning = strMessage;
496 printf("*** %s\n", strMessage.c_str());
497 uiInterface.ThreadSafeMessageBox(strMessage+" ", std::string("NovaCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION);
500 printf("nNtpOffset = %+" PRId64 " (%+" PRId64 " minutes)\n", nNtpOffset, nNtpOffset/60);
502 int nSleepHours = 1 + GetRandInt(5); // Sleep for 1-6 hours.
503 for (int i = 0; i < nSleepHours * 3600 && !fShutdown; i++)
507 vnThreadsRunning[THREAD_NTP]--;
508 printf("ThreadNtpSamples exited\n");