4 #include <sys/socket.h>
6 #include <netinet/in.h>
18 extern int GetRandInt(int nMax);
21 * NTP uses two fixed point formats. The first (l_fp) is the "long"
22 * format and is 64 bits long with the decimal between bits 31 and 32.
23 * This is used for time stamps in the NTP packet header (in network
24 * byte order) and for internal computations of offsets (in local host
25 * byte order). We use the same structure for both signed and unsigned
26 * values, which is a big hack but saves rewriting all the operators
27 * twice. Just to confuse this, we also sometimes just carry the
28 * fractional part in calculations, in both signed and unsigned forms.
29 * Anyway, an l_fp looks like:
32 * 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
33 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 * REF http://www.eecis.udel.edu/~mills/database/rfc/rfc2030.txt
54 inline void Ntp2Unix(uint32_t &n, time_t &u) {
55 // Ntp's time scale starts in 1900, Unix in 1970.
57 u = n - 0x83aa7e80; // 2208988800 1970 - 1900 in seconds
60 inline void ntohl_fp(l_fp *n, l_fp *h) {
61 (h)->Ul_i.Xl_ui = ntohl((n)->Ul_i.Xl_ui);
62 (h)->Ul_f.Xl_uf = ntohl((n)->Ul_f.Xl_uf);
66 uint8_t li_vn_mode; /* leap indicator, version and mode */
67 uint8_t stratum; /* peer stratum */
68 uint8_t ppoll; /* peer poll interval */
69 int8_t precision; /* peer clock precision */
70 uint32_t rootdelay; /* distance to primary clock */
71 uint32_t rootdispersion; /* clock dispersion */
72 uint32_t refid; /* reference clock ID */
73 l_fp ref; /* time peer clock was last updated */
74 l_fp org; /* originate time stamp */
75 l_fp rec; /* receive time stamp */
76 l_fp xmt; /* transmit time stamp */
78 uint32_t exten[1]; /* misused */
79 uint8_t mac[5 * sizeof(uint32_t)]; /* mac */
82 const int nServersCount = 147;
84 const std::string NtpServers[147] = {
104 // Russian Federation
127 "ntp1.niiftri.irkutsk.ru",
128 "ntp2.niiftri.irkutsk.ru",
140 "timex.cs.columbia.edu",
142 "sundial.columbia.edu",
148 "ntp-01.caltech.edu",
149 "ntp-02.caltech.edu",
150 "ntp-03.caltech.edu",
151 "ntp-04.caltech.edu",
152 "nist1-pa.ustiming.org",
157 "nist1-macon.macon.ga.us",
158 "nist.netservicesgroup.com",
159 "nisttime.carsoncity.k12.mi.us",
160 "nist1-lnk.binary.net",
162 "time-a.timefreq.bldrdoc.gov",
163 "time-b.timefreq.bldrdoc.gov",
164 "time-c.timefreq.bldrdoc.gov",
166 "utcnist.colorado.edu",
167 "utcnist2.colorado.edu",
168 "ntp-nist.ldsbc.net",
169 "nist1-lv.ustiming.org",
171 "nist-time-server.eoni.com",
172 "nist-time-server.eoni.com",
182 "ntp1.meraka.csir.co.za",
186 "ntp1.neology.co.za",
187 "ntp2.neology.co.za",
188 "tick.meraka.csir.co.za",
189 "tock.meraka.csir.co.za",
191 "ntp1.meraka.csir.co.za",
192 "ntp2.meraka.csir.co.za",
221 "ntp.cis.strath.ac.uk",
232 "timelord.uregina.ca",
250 "augean.eleceng.adelaide.edu.au",
262 // ... To be continued
265 bool InitWithHost(const std::string &strHostName, SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) {
268 std::vector<CNetAddr> vIP;
269 bool fRet = LookupHost(strHostName.c_str(), vIP, 10, true);
274 struct sockaddr_in servaddr;
275 servaddr.sin_family = AF_INET;
276 servaddr.sin_port = htons(123);
279 for(unsigned int i = 0; i < vIP.size(); i++) {
280 if ((found = vIP[i].GetInAddr(&servaddr.sin_addr))) {
289 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
291 if (sockfd == INVALID_SOCKET)
292 return false; // socket initialization error
294 if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 ) {
295 return false; // "connection" error
299 *pcliaddr = *((struct sockaddr *) &servaddr);
300 servlen = sizeof(servaddr);
305 bool InitWithRandom(SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) {
307 for (int nAttempt = 0; nAttempt < nServersCount; nAttempt++) {
308 int nServerNum = GetRandInt(nServersCount);
309 if (InitWithHost(NtpServers[nServerNum], sockfd, servlen, pcliaddr)) {
317 int64_t DoReq(SOCKET sockfd, socklen_t servlen, struct sockaddr cliaddr) {
320 if (ioctlsocket(sockfd, FIONBIO, &nOne) == SOCKET_ERROR) {
321 printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
323 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) {
324 printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
329 struct pkt *msg = new pkt;
330 struct pkt *prt = new pkt;
337 msg->rootdispersion=0;
339 msg->ref.Ul_i.Xl_i=0;
340 msg->ref.Ul_f.Xl_f=0;
341 msg->org.Ul_i.Xl_i=0;
342 msg->org.Ul_f.Xl_f=0;
343 msg->rec.Ul_i.Xl_i=0;
344 msg->rec.Ul_f.Xl_f=0;
345 msg->xmt.Ul_i.Xl_i=0;
346 msg->xmt.Ul_f.Xl_f=0;
349 int retcode = sendto(sockfd, (char *) msg, len, 0, &cliaddr, servlen);
351 printf("sendto() failed: %d", retcode);
356 struct timeval timeout = {10, 0};
358 FD_SET(sockfd, &fdset);
360 retcode = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
362 printf("recvfrom() error");
366 recvfrom(sockfd, (char *) msg, len, 0, NULL, NULL);
367 ntohl_fp(&msg->xmt, &prt->xmt);
368 time_t seconds_transmit;
369 Ntp2Unix(prt->xmt.Ul_i.Xl_ui, seconds_transmit);
374 return seconds_transmit;
377 int64_t NtpGetTime(CNetAddr& ip) {
378 struct sockaddr cliaddr;
383 if (!InitWithRandom(sockfd, servlen, &cliaddr))
386 ip = CNetAddr(((sockaddr_in *)&cliaddr)->sin_addr);
387 int64_t nTime = DoReq(sockfd, servlen, cliaddr);
394 int64_t NtpGetTime(const std::string &strHostName)
396 struct sockaddr cliaddr;
401 if (!InitWithHost(strHostName, sockfd, servlen, &cliaddr))
404 int64_t nTime = DoReq(sockfd, servlen, cliaddr);
411 // NTP server, which we unconditionally trust. This may be your own installation of ntpd somewhere, for example.
412 // "localhost" means "trust no one"
413 std::string strTrustedUpstream = "localhost";
416 int64_t nNtpOffset = INT64_MAX;
418 int64_t GetNtpOffset() {
422 void ThreadNtpSamples(void* parg) {
424 // Maximum offset is 2 hours.
425 const int64_t nMaxOffset = 7200;
427 printf("Trying to find NTP server at localhost...\n");
429 const std::string strLocalHost = "127.0.0.1";
430 if (NtpGetTime(strLocalHost) == GetTime()) {
431 printf("There is NTP server active at localhost, we don't need NTP thread.\n");
437 printf("ThreadNtpSamples started\n");
438 vnThreadsRunning[THREAD_NTP]++;
440 // Make this thread recognisable as time synchronization thread
441 RenameThread("novacoin-ntp-samples");
443 CMedianFilter<int64_t> vTimeOffsets(200,0);
446 if (strTrustedUpstream != strLocalHost) {
447 // Trying to get new offset sample from trusted NTP server.
448 int64_t nClockOffset = NtpGetTime(strTrustedUpstream) - GetTime();
450 if (abs64(nClockOffset) < nMaxOffset) {
451 // Everything seems right, remember new trusted offset.
452 nNtpOffset = nClockOffset;
455 // Something went wrong, disable trusted offset sampling.
456 nNtpOffset = INT64_MAX;
457 strTrustedUpstream = strLocalHost;
459 int nSleepMinutes = 1 + GetRandInt(9); // Sleep for 1-10 minutes.
460 for (int i = 0; i < nSleepMinutes * 60 && !fShutdown; i++)
467 // Now, trying to get 2-4 samples from random NTP servers.
468 int nSamplesCount = 2 + GetRandInt(2);
470 for (int i = 0; i < nSamplesCount; i++) {
472 int64_t nClockOffset = NtpGetTime(ip) - GetTime();
474 if (abs64(nClockOffset) < nMaxOffset) { // Skip the deliberately wrong timestamps
475 vTimeOffsets.input(nClockOffset);
479 if (vTimeOffsets.size() > 2) {
480 nNtpOffset = vTimeOffsets.median();
483 // Not enough offsets yet, try again later.
484 nNtpOffset = INT64_MAX;
485 int nSleepMinutes = 1 + GetRandInt(4); // Sleep for 1-5 minutes.
486 for (int i = 0; i < nSleepMinutes * 60 && !fShutdown; i++)
492 printf("nNtpOffset = %+" PRId64 " (%+" PRId64 " minutes)\n", nNtpOffset, nNtpOffset/60);
494 int nSleepHours = 1 + GetRandInt(5); // Sleep for 1-6 hours.
495 for (int i = 0; i < nSleepHours * 3600 && !fShutdown; i++)
499 vnThreadsRunning[THREAD_NTP]--;
500 printf("ThreadNtpSamples exited\n");