Add 5 new ntp servers.
[novacoin.git] / src / ntp.cpp
1
2 #ifdef WIN32
3 #include <winsock2.h>
4 #else
5 #include <sys/socket.h>
6 #include <sys/time.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <netdb.h>
10 #endif
11 #ifndef WIN32
12 #include <unistd.h>
13 #endif
14
15 #include "netbase.h"
16 #include "util.h"
17 #include "net.h"
18
19 extern int GetRandInt(int nMax);
20
21 /*
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:
31  *
32  *    0                   1                   2                   3
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  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35  *   |                         Integral Part                         |
36  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37  *   |                         Fractional Part                       |
38  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39  * REF http://www.eecis.udel.edu/~mills/database/rfc/rfc2030.txt
40  */
41
42
43 typedef struct {
44   union {
45     uint32_t Xl_ui;
46     int32_t Xl_i;
47   } Ul_i;
48   union {
49     uint32_t Xl_uf;
50     int32_t Xl_f;
51   } Ul_f;
52 } l_fp;
53
54
55 inline void Ntp2Unix(uint32_t &n, time_t &u) {
56     // Ntp's time scale starts in 1900, Unix in 1970.
57
58     u = n - 0x83aa7e80; // 2208988800 1970 - 1900 in seconds
59 }
60
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);
64 }
65
66 struct pkt {
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 */
78
79   uint32_t exten[1];       /* misused */
80   uint8_t  mac[5 * sizeof(uint32_t)]; /* mac */
81 };
82
83 int nServersCount = 112;
84
85 std::string NtpServers[112] = {
86     // Microsoft
87     "time.windows.com",
88
89     // Google
90     "time1.google.com",
91     "time2.google.com",
92     "time3.google.com",
93     "time4.google.com",
94
95     // Russian Federation
96     "ntp.karelia.pro",
97     "ntp.alpet.me",
98     "aviel.alpet.me",
99     "ntp.sampo.ru",
100     "ntp.szt.ru",
101     "ntp.ix.ru",
102     "ntp1.stratum2.ru",
103     "ntp2.stratum2.ru",
104     "ntp3.stratum2.ru",
105     "ntp4.stratum2.ru",
106     "ntp5.stratum2.ru",
107     "ntp6.stratum2.ru",
108     "ntp7.stratum2.ru",
109     "ntp1.stratum1.ru",
110     "ntp2.stratum1.ru",
111     "ntp3.stratum1.ru",
112     "ntp4.stratum1.ru",
113     "ntp1.vniiftri.ru",
114     "ntp2.vniiftri.ru",
115     "ntp3.vniiftri.ru",
116     "ntp4.vniiftri.ru",
117     "ntp21.vniiftri.ru",
118     "ntp1.niiftri.irkutsk.ru",
119     "ntp2.niiftri.irkutsk.ru",
120     "vniiftri.khv.ru",
121     "vniiftri2.khv.ru",
122     "ntp0.zenon.net",
123     "ntp.mobatime.ru",
124     "0.ru.pool.ntp.org",
125     "1.ru.pool.ntp.org",
126     "2.ru.pool.ntp.org",
127     "3.ru.pool.ntp.org",
128
129     // United States
130     "ntp-01.caltech.edu",
131     "ntp-02.caltech.edu",
132     "ntp-03.caltech.edu",
133     "ntp-04.caltech.edu",
134     "nist1-pa.ustiming.org",
135     "time-a.nist.gov ",
136     "time-b.nist.gov ",
137     "time-c.nist.gov ",
138     "time-d.nist.gov ",
139     "nist1-macon.macon.ga.us",
140     "nist.netservicesgroup.com",
141     "nisttime.carsoncity.k12.mi.us",
142     "nist1-lnk.binary.net",
143     "wwv.nist.gov",
144     "time-a.timefreq.bldrdoc.gov",
145     "time-b.timefreq.bldrdoc.gov",
146     "time-c.timefreq.bldrdoc.gov",
147     "time.nist.gov",
148     "utcnist.colorado.edu",
149     "utcnist2.colorado.edu",
150     "ntp-nist.ldsbc.net",
151     "nist1-lv.ustiming.org",
152     "time-nw.nist.gov",
153     "nist-time-server.eoni.com",
154     "nist-time-server.eoni.com",
155     "ntp1.bu.edu",
156     "ntp2.bu.edu",
157     "ntp3.bu.edu",
158     "0.us.pool.ntp.org",
159     "1.us.pool.ntp.org",
160     "2.us.pool.ntp.org",
161     "3.us.pool.ntp.org",
162
163     // South Africa
164     "ntp1.meraka.csir.co.za",
165     "ntp.is.co.za",
166     "ntp2.is.co.za",
167     "igubu.saix.net",
168     "ntp1.neology.co.za",
169     "ntp2.neology.co.za",
170     "tick.meraka.csir.co.za",
171     "tock.meraka.csir.co.za",
172     "ntp.time.org.za",
173     "ntp1.meraka.csir.co.za",
174     "ntp2.meraka.csir.co.za",
175     "0.za.pool.ntp.org",
176     "1.za.pool.ntp.org",
177     "2.za.pool.ntp.org",
178     "3.za.pool.ntp.org",
179
180     // Italy
181     "ntp1.inrim.it",
182     "ntp2.inrim.it",
183     "0.it.pool.ntp.org",
184     "1.it.pool.ntp.org",
185     "2.it.pool.ntp.org",
186     "3.it.pool.ntp.org",
187
188     // Netherlands
189     "ntp0.nl.net",
190     "ntp1.nl.net",
191     "ntp2.nl.net",
192     "ntp.utwente.nl",
193     "0.nl.pool.ntp.org",
194     "1.nl.pool.ntp.org",
195     "2.nl.pool.ntp.org",
196     "3.nl.pool.ntp.org",
197
198     // United Kingdom
199     "ntp2d.mcc.ac.uk",
200     "ntp2c.mcc.ac.uk",
201     "ntp.exnet.com",
202     "ntp.cis.strath.ac.uk",
203     "ntppub.le.ac.uk",
204     "0.uk.pool.ntp.org",
205     "1.uk.pool.ntp.org",
206     "2.uk.pool.ntp.org",
207     "3.uk.pool.ntp.org",
208
209     // Japan
210     "ntp.nict.jp",
211     "0.jp.pool.ntp.org",
212     "1.jp.pool.ntp.org",
213     "2.jp.pool.ntp.org",
214     "3.jp.pool.ntp.org",
215
216     // ... To be continued
217 };
218
219 bool InitWithRandom(SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) {
220     int nAttempt = 0;
221
222     while(nAttempt < 100) {
223         sockfd = -1;
224         nAttempt++;
225
226         int nServerNum = GetRandInt(nServersCount);
227
228         std::vector<CNetAddr> vIP;
229         bool fRet = LookupHost(NtpServers[nServerNum].c_str(), vIP, 10, true);
230         if (!fRet)
231             continue;
232
233         struct sockaddr_in servaddr;
234         servaddr.sin_family = AF_INET;
235         servaddr.sin_port = htons(123);
236
237         bool found = false;
238         for(unsigned int i = 0; i < vIP.size(); i++) {
239             if ((found = vIP[i].GetInAddr(&servaddr.sin_addr))) {
240                 break;
241             }
242         }
243
244         if (!found)
245             continue;
246
247         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
248
249         if (sockfd == INVALID_SOCKET)
250             continue; // socket initialization error
251
252         if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 ) {
253             continue; // "connection" error
254         }
255
256         *pcliaddr = *((struct sockaddr *) &servaddr);
257         servlen = sizeof(servaddr);
258         return true;
259     }
260
261     return false;
262 }
263
264 bool InitWithHost(std::string &strHostName, SOCKET &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr) {
265     sockfd = -1;
266
267     std::vector<CNetAddr> vIP;
268     bool fRet = LookupHost(strHostName.c_str(), vIP, 10, true);
269     if (!fRet) {
270         return false;
271     }
272
273     struct sockaddr_in servaddr;
274     servaddr.sin_family = AF_INET;
275     servaddr.sin_port = htons(123);
276
277     bool found = false;
278     for(unsigned int i = 0; i < vIP.size(); i++) {
279         if ((found = vIP[i].GetInAddr(&servaddr.sin_addr))) {
280             break;
281         }
282     }
283
284     if (!found) {
285         return false;
286     }
287
288     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
289
290     if (sockfd == INVALID_SOCKET)
291         return false; // socket initialization error
292
293     if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 ) {
294         return false; // "connection" error
295     }
296
297
298     *pcliaddr = *((struct sockaddr *) &servaddr);
299     servlen = sizeof(servaddr);
300
301     return true;
302 }
303
304
305 int64_t DoReq(SOCKET sockfd, socklen_t servlen, struct sockaddr cliaddr) {
306 #ifdef WIN32
307     u_long nOne = 1;
308     if (ioctlsocket(sockfd, FIONBIO, &nOne) == SOCKET_ERROR) {
309         printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
310 #else
311     if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) {
312         printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
313 #endif
314         return -2;
315     }
316
317     struct pkt *msg = new pkt;
318     struct pkt *prt  = new pkt;
319
320     msg->li_vn_mode=227;
321     msg->stratum=0;
322     msg->ppoll=4;
323     msg->precision=0;
324     msg->rootdelay=0;
325     msg->rootdispersion=0;
326
327     msg->ref.Ul_i.Xl_i=0;
328     msg->ref.Ul_f.Xl_f=0;
329     msg->org.Ul_i.Xl_i=0;
330     msg->org.Ul_f.Xl_f=0;
331     msg->rec.Ul_i.Xl_i=0;
332     msg->rec.Ul_f.Xl_f=0;
333     msg->xmt.Ul_i.Xl_i=0;
334     msg->xmt.Ul_f.Xl_f=0;
335
336     int len=48;
337     int retcode = sendto(sockfd, (char *) msg, len, 0, &cliaddr, servlen);
338     if (retcode < 0) {
339         printf("sendto() failed: %d", retcode);
340         return -3;
341     }
342
343     fd_set fdset;
344     struct timeval timeout = {10, 0};
345     FD_ZERO(&fdset);
346     FD_SET(sockfd, &fdset);
347
348     retcode = select(sockfd + 1, &fdset, NULL, NULL, &timeout);
349     if (retcode <= 0) {
350         printf("recvfrom() error");
351         return -4;
352     }
353
354     recvfrom(sockfd, (char *) msg, len, 0, NULL, NULL);
355
356     ntohl_fp(&msg->rec, &prt->rec);
357     ntohl_fp(&msg->xmt, &prt->xmt);
358
359     time_t seconds_receive;
360     time_t seconds_transmit;
361
362     Ntp2Unix(prt->rec.Ul_i.Xl_ui, seconds_receive);
363     Ntp2Unix(prt->xmt.Ul_i.Xl_ui, seconds_transmit);
364
365     delete msg;
366     delete prt;
367
368     return (seconds_receive + seconds_transmit) / 2;
369 }
370
371 int64_t NtpGetTime() {
372     struct sockaddr cliaddr;
373
374     SOCKET sockfd;
375     socklen_t servlen;
376
377     if (!InitWithRandom(sockfd, servlen, &cliaddr))
378         return -1;
379
380     int64_t nTime = DoReq(sockfd, servlen, cliaddr);
381
382     closesocket(sockfd);
383
384     return nTime;
385 }
386
387 int64_t NtpGetTime(CNetAddr& ip) {
388     struct sockaddr cliaddr;
389
390     SOCKET sockfd;
391     socklen_t servlen;
392
393     if (!InitWithRandom(sockfd, servlen, &cliaddr))
394         return -1;
395
396     ip = CNetAddr(((sockaddr_in *)&cliaddr)->sin_addr);
397     int64_t nTime = DoReq(sockfd, servlen, cliaddr);
398
399     closesocket(sockfd);
400
401     return nTime;
402 }
403
404 int64_t NtpGetTime(std::string &strHostName)
405 {
406     struct sockaddr cliaddr;
407
408     SOCKET sockfd;
409     socklen_t servlen;
410
411     if (!InitWithHost(strHostName, sockfd, servlen, &cliaddr))
412         return -1;
413
414     int64_t nTime = DoReq(sockfd, servlen, cliaddr);
415
416     closesocket(sockfd);
417
418     return nTime;
419 }
420
421 void ThreadNtpSamples(void* parg)
422 {
423     printf("ThreadNtpSamples started\n");
424     vnThreadsRunning[THREAD_NTP]++;
425
426     // Make this thread recognisable as time synchronization thread
427     RenameThread("novacoin-ntp-samples");
428
429     while (!fShutdown) {
430         CNetAddr ip;
431         int64_t nTime = NtpGetTime(ip);
432
433         if (nTime > 0 && nTime != 2085978496) { // Skip the deliberately wrong timestamps
434             AddTimeData(ip, nTime);
435         }
436         else {
437             Sleep(600000); // In case of failure wait 600 seconds and then try again
438             continue;
439         }
440
441         Sleep(43200000); // Sleep for 12 hours
442     }
443
444     vnThreadsRunning[THREAD_NTP]--;
445     printf("ThreadNtpSamples exited\n");
446 }