6 #include <sys/socket.h>
7 #include <netinet/in.h>
17 extern int GetRandInt(int nMax);
20 * NTP uses two fixed point formats. The first (l_fp) is the "long"
21 * format and is 64 bits long with the decimal between bits 31 and 32.
22 * This is used for time stamps in the NTP packet header (in network
23 * byte order) and for internal computations of offsets (in local host
24 * byte order). We use the same structure for both signed and unsigned
25 * values, which is a big hack but saves rewriting all the operators
26 * twice. Just to confuse this, we also sometimes just carry the
27 * fractional part in calculations, in both signed and unsigned forms.
28 * Anyway, an l_fp looks like:
31 * 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
32 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 * REF http://www.eecis.udel.edu/~mills/database/rfc/rfc2030.txt
53 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 HTONL_FP(l_fp *h, l_fp *n)
62 (n)->Ul_i.Xl_ui = htonl((h)->Ul_i.Xl_ui);
63 (n)->Ul_f.Xl_uf = htonl((h)->Ul_f.Xl_uf);
66 inline void ntohl_fp(l_fp *n, l_fp *h)
68 (h)->Ul_i.Xl_ui = ntohl((n)->Ul_i.Xl_ui);
69 (h)->Ul_f.Xl_uf = ntohl((n)->Ul_f.Xl_uf);
73 uint8_t li_vn_mode; /* leap indicator, version and mode */
74 uint8_t stratum; /* peer stratum */
75 uint8_t ppoll; /* peer poll interval */
76 int8_t precision; /* peer clock precision */
77 uint32_t rootdelay; /* distance to primary clock */
78 uint32_t rootdispersion; /* clock dispersion */
79 uint32_t refid; /* reference clock ID */
80 l_fp ref; /* time peer clock was last updated */
81 l_fp org; /* originate time stamp */
82 l_fp rec; /* receive time stamp */
83 l_fp xmt; /* transmit time stamp */
85 uint32_t exten[1]; /* misused */
86 uint8_t mac[5 * sizeof(uint32_t)]; /* mac */
89 int nServersCount = 65;
91 std::string NtpServers[65] = {
121 "ntp1.niiftri.irkutsk.ru",
122 "ntp2.niiftri.irkutsk.ru",
127 "nist1-pa.ustiming.org",
132 "nist1-macon.macon.ga.us",
133 "nist.netservicesgroup.com",
134 "nisttime.carsoncity.k12.mi.us",
135 "nist1-lnk.binary.net",
137 "time-a.timefreq.bldrdoc.gov",
138 "time-b.timefreq.bldrdoc.gov",
139 "time-c.timefreq.bldrdoc.gov",
141 "utcnist.colorado.edu",
142 "utcnist2.colorado.edu",
143 "ntp-nist.ldsbc.net",
144 "nist1-lv.ustiming.org",
146 "nist-time-server.eoni.com",
147 "nist-time-server.eoni.com",
153 "ntp1.meraka.csir.co.za",
157 "ntp1.neology.co.za",
158 "ntp2.neology.co.za",
159 "tick.meraka.csir.co.za",
160 "tock.meraka.csir.co.za",
162 "ntp1.meraka.csir.co.za",
163 "ntp2.meraka.csir.co.za",
169 // ... To be continued
173 bool InitWithRandom(int &sockfd, int &servlen, struct sockaddr *pcliaddr)
175 bool InitWithRandom(int &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr)
180 while(nAttempt < 100)
185 int nServerNum = GetRandInt(nServersCount);
187 std::vector<CNetAddr> vIP;
188 bool fRet = LookupHost(NtpServers[nServerNum].c_str(), vIP, 10, true);
192 struct sockaddr_in servaddr;
193 servaddr.sin_family = AF_INET;
194 servaddr.sin_port = htons(123);
197 for(unsigned int i = 0; i < vIP.size(); i++)
199 if ((found = vIP[i].GetInAddr(&servaddr.sin_addr)))
208 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
211 continue; // socket initialization error
213 if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 )
215 continue; // "connection" error
218 *pcliaddr = *((struct sockaddr *) &servaddr);
219 servlen = sizeof(servaddr);
227 bool InitWithHost(std::string &strHostName, int &sockfd, int &servlen, struct sockaddr *pcliaddr)
229 bool InitWithHost(std::string &strHostName, int &sockfd, socklen_t &servlen, struct sockaddr *pcliaddr)
234 std::vector<CNetAddr> vIP;
235 bool fRet = LookupHost(strHostName.c_str(), vIP, 10, true);
239 struct sockaddr_in servaddr;
240 servaddr.sin_family = AF_INET;
241 servaddr.sin_port = htons(123);
244 for(unsigned int i = 0; i < vIP.size(); i++)
246 if ((found = vIP[i].GetInAddr(&servaddr.sin_addr)))
255 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
258 return false; // socket initialization error
260 if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1 )
262 return false; // "connection" error
265 *pcliaddr = *((struct sockaddr *) &servaddr);
266 servlen = sizeof(servaddr);
273 int64_t DoReq(int sockfd, int servlen, struct sockaddr cliaddr)
275 int64_t DoReq(int sockfd, socklen_t servlen, struct sockaddr cliaddr)
278 struct pkt *msg = new pkt;
279 struct pkt *prt = new pkt;
286 msg->rootdispersion=0;
288 msg->ref.Ul_i.Xl_i=0;
289 msg->ref.Ul_f.Xl_f=0;
290 msg->org.Ul_i.Xl_i=0;
291 msg->org.Ul_f.Xl_f=0;
292 msg->rec.Ul_i.Xl_i=0;
293 msg->rec.Ul_f.Xl_f=0;
294 msg->xmt.Ul_i.Xl_i=0;
295 msg->xmt.Ul_f.Xl_f=0;
298 sendto(sockfd, (char *) msg, len, 0, &cliaddr, servlen);
299 int n = recvfrom(sockfd, msg, len, 0, NULL, NULL);
301 ntohl_fp(&msg->rec, &prt->rec);
302 ntohl_fp(&msg->xmt, &prt->xmt);
304 time_t seconds_receive;
305 time_t seconds_transmit;
307 Ntp2Unix(prt->rec.Ul_i.Xl_ui, seconds_receive);
308 Ntp2Unix(prt->xmt.Ul_i.Xl_ui, seconds_transmit);
313 return (seconds_receive + seconds_transmit) / 2;
319 struct sockaddr cliaddr;
327 if (!InitWithRandom(sockfd, servlen, &cliaddr))
330 int64_t nTime = DoReq(sockfd, servlen, cliaddr);
341 int64_t NtpGetTime(std::string &strHostName)
344 struct sockaddr cliaddr;
352 if (!InitWithHost(strHostName, sockfd, servlen, &cliaddr))
355 int64_t nTime = DoReq(sockfd, servlen, cliaddr);