5 #include <sys/socket.h>
7 #include <netinet/in.h>
19 extern int GetRandInt(int nMax);
22 * NTP uses two fixed point formats. The first (l_fp) is the "long"
23 * format and is 64 bits long with the decimal between bits 31 and 32.
24 * This is used for time stamps in the NTP packet header (in network
25 * byte order) and for internal computations of offsets (in local host
26 * byte order). We use the same structure for both signed and unsigned
27 * values, which is a big hack but saves rewriting all the operators
28 * twice. Just to confuse this, we also sometimes just carry the
29 * fractional part in calculations, in both signed and unsigned forms.
30 * Anyway, an l_fp looks like:
33 * 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
34 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 * REF http://www.eecis.udel.edu/~mills/database/rfc/rfc2030.txt
55 inline void Ntp2Unix(uint32_t &n, time_t &u) {
56 // Ntp's time scale starts in 1900, Unix in 1970.
58 u = n - 0x83aa7e80; // 2208988800 1970 - 1900 in seconds
61 inline void ntohl_fp(l_fp *n, l_fp *h) {
62 (h)->Ul_i.Xl_ui = ntohl((n)->Ul_i.Xl_ui);
63 (h)->Ul_f.Xl_uf = ntohl((n)->Ul_f.Xl_uf);
67 uint8_t li_vn_mode; /* leap indicator, version and mode */
68 uint8_t stratum; /* peer stratum */
69 uint8_t ppoll; /* peer poll interval */
70 int8_t precision; /* peer clock precision */
71 uint32_t rootdelay; /* distance to primary clock */
72 uint32_t rootdispersion; /* clock dispersion */
73 uint32_t refid; /* reference clock ID */
74 l_fp ref; /* time peer clock was last updated */
75 l_fp org; /* originate time stamp */
76 l_fp rec; /* receive time stamp */
77 l_fp xmt; /* transmit time stamp */
79 uint32_t exten[1]; /* misused */
80 uint8_t mac[5 * sizeof(uint32_t)]; /* mac */
83 int nServersCount = 118;
85 std::string NtpServers[118] = {
105 // Russian Federation
128 "ntp1.niiftri.irkutsk.ru",
129 "ntp2.niiftri.irkutsk.ru",
140 "ntp-01.caltech.edu",
141 "ntp-02.caltech.edu",
142 "ntp-03.caltech.edu",
143 "ntp-04.caltech.edu",
144 "nist1-pa.ustiming.org",
149 "nist1-macon.macon.ga.us",
150 "nist.netservicesgroup.com",
151 "nisttime.carsoncity.k12.mi.us",
152 "nist1-lnk.binary.net",
154 "time-a.timefreq.bldrdoc.gov",
155 "time-b.timefreq.bldrdoc.gov",
156 "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",
174 "ntp1.meraka.csir.co.za",
178 "ntp1.neology.co.za",
179 "ntp2.neology.co.za",
180 "tick.meraka.csir.co.za",
181 "tock.meraka.csir.co.za",
183 "ntp1.meraka.csir.co.za",
184 "ntp2.meraka.csir.co.za",
212 "ntp.cis.strath.ac.uk",
226 // ... To be continued
229 bool InitWithRandom(SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) {
232 while(nAttempt < 100) {
236 int nServerNum = GetRandInt(nServersCount);
238 std::vector<CNetAddr> vIP;
239 bool fRet = LookupHost(NtpServers[nServerNum].c_str(), vIP, 10, true);
243 struct sockaddr_in servaddr;
244 servaddr.sin_family = AF_INET;
245 servaddr.sin_port = htons(123);
248 for(unsigned int i = 0; i < vIP.size(); i++) {
249 if ((found = vIP[i].GetInAddr(&servaddr.sin_addr))) {
257 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
259 if (sockfd == INVALID_SOCKET)
260 continue; // socket initialization error
262 if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 ) {
263 continue; // "connection" error
266 *pcliaddr = *((struct sockaddr *) &servaddr);
267 servlen = sizeof(servaddr);
274 bool InitWithHost(std::string &strHostName, SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) {
277 std::vector<CNetAddr> vIP;
278 bool fRet = LookupHost(strHostName.c_str(), 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))) {
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);
315 int64_t DoReq(SOCKET sockfd, socklen_t servlen, struct sockaddr cliaddr) {
318 if (ioctlsocket(sockfd, FIONBIO, &nOne) == SOCKET_ERROR) {
319 printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
321 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) {
322 printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
327 struct pkt *msg = new pkt;
328 struct pkt *prt = new pkt;
335 msg->rootdispersion=0;
337 msg->ref.Ul_i.Xl_i=0;
338 msg->ref.Ul_f.Xl_f=0;
339 msg->org.Ul_i.Xl_i=0;
340 msg->org.Ul_f.Xl_f=0;
341 msg->rec.Ul_i.Xl_i=0;
342 msg->rec.Ul_f.Xl_f=0;
343 msg->xmt.Ul_i.Xl_i=0;
344 msg->xmt.Ul_f.Xl_f=0;
347 int retcode = sendto(sockfd, (char *) msg, len, 0, &cliaddr, servlen);
349 printf("sendto() failed: %d", retcode);
354 struct timeval timeout = {10, 0};
356 FD_SET(sockfd, &fdset);
358 retcode = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
360 printf("recvfrom() error");
364 recvfrom(sockfd, (char *) msg, len, 0, NULL, NULL);
366 ntohl_fp(&msg->rec, &prt->rec);
367 ntohl_fp(&msg->xmt, &prt->xmt);
369 time_t seconds_receive;
370 time_t seconds_transmit;
372 Ntp2Unix(prt->rec.Ul_i.Xl_ui, seconds_receive);
373 Ntp2Unix(prt->xmt.Ul_i.Xl_ui, seconds_transmit);
378 return (seconds_receive + seconds_transmit) / 2;
381 int64_t NtpGetTime() {
382 struct sockaddr cliaddr;
387 if (!InitWithRandom(sockfd, servlen, &cliaddr))
390 int64_t nTime = DoReq(sockfd, servlen, cliaddr);
397 int64_t NtpGetTime(CNetAddr& ip) {
398 struct sockaddr cliaddr;
403 if (!InitWithRandom(sockfd, servlen, &cliaddr))
406 ip = CNetAddr(((sockaddr_in *)&cliaddr)->sin_addr);
407 int64_t nTime = DoReq(sockfd, servlen, cliaddr);
414 int64_t NtpGetTime(std::string &strHostName)
416 struct sockaddr cliaddr;
421 if (!InitWithHost(strHostName, sockfd, servlen, &cliaddr))
424 int64_t nTime = DoReq(sockfd, servlen, cliaddr);
431 void ThreadNtpSamples(void* parg)
433 printf("ThreadNtpSamples started\n");
434 vnThreadsRunning[THREAD_NTP]++;
436 // Make this thread recognisable as time synchronization thread
437 RenameThread("novacoin-ntp-samples");
441 int64_t nTime = NtpGetTime(ip);
443 if (nTime > 0 && nTime != 2085978496) { // Skip the deliberately wrong timestamps
444 AddTimeData(ip, nTime);
447 Sleep(600000); // In case of failure wait 600 seconds and then try again
451 Sleep(43200000); // Sleep for 12 hours
454 vnThreadsRunning[THREAD_NTP]--;
455 printf("ThreadNtpSamples exited\n");