2 * Copyright 2010-2011, Ryan Leavengood. All Rights Reserved.
3 * Copyright 2004-2009, pinc Software. All Rights Reserved.
4 * Distributed under the terms of the MIT license.
14 #include <sys/select.h>
15 #include <sys/socket.h>
23 #undef B_TRANSLATION_CONTEXT
24 #define B_TRANSLATION_CONTEXT "Time"
27 /* This structure and its data fields are described in RFC 1305
28 * "Network Time Protocol (Version 3)" in appendix A.
36 SetTo(int16 integer
, uint16 fraction
= 0)
38 this->integer
= htons(integer
);
39 this->fraction
= htons(fraction
);
42 int16
Integer() { return htons(integer
); }
43 uint16
Fraction() { return htons(fraction
); }
51 SetTo(uint32 integer
, uint32 fraction
= 0)
53 this->integer
= htonl(integer
);
54 this->fraction
= htonl(fraction
);
57 uint32
Integer() { return htonl(integer
); }
58 uint32
Fraction() { return htonl(fraction
); }
64 uint8 leap_indicator
: 2;
68 int8 precision
; /* in seconds of the nearest power of two */
71 fixed32 root_dispersion
;
72 uint32 root_identifier
;
74 ufixed64 reference_timestamp
;
75 ufixed64 originate_timestamp
;
76 ufixed64 receive_timestamp
;
77 ufixed64 transmit_timestamp
;
79 /* optional authenticator follows (96 bits) */
83 #define NTP_VERSION_3 3
85 enum ntp_leap_warnings
{
87 LEAP_LAST_MINUTE_61_SECONDS
,
88 LEAP_LAST_MINUTE_59_SECONDS
,
89 LEAP_CLOCK_NOT_IN_SYNC
,
94 MODE_SYMMETRIC_ACTIVE
,
95 MODE_SYMMETRIC_PASSIVE
,
99 MODE_NTP_CONTROL_MESSAGE
,
103 const uint32 kSecondsBetween1900And1970
= 2208988800UL;
107 seconds_since_1900(void)
109 return kSecondsBetween1900And1970
+ real_time_clock();
114 ntp_update_time(const char* hostname
, const char** errorString
,
117 hostent
*server
= gethostbyname(hostname
);
119 if (server
== NULL
) {
121 *errorString
= B_TRANSLATE("Could not contact server");
122 return B_ENTRY_NOT_FOUND
;
126 memset(&message
, 0, sizeof(ntp_data
));
128 message
.leap_indicator
= LEAP_CLOCK_NOT_IN_SYNC
;
129 message
.version
= NTP_VERSION_3
;
130 message
.mode
= MODE_CLIENT
;
132 message
.stratum
= 1; // primary reference
133 message
.precision
= -5; // 2^-5 ~ 32-64 Hz precision
135 message
.root_delay
.SetTo(1); // 1 sec
136 message
.root_dispersion
.SetTo(1);
138 message
.transmit_timestamp
.SetTo(seconds_since_1900());
140 int connection
= socket(AF_INET
, SOCK_DGRAM
, 0);
141 if (connection
< 0) {
142 *errorString
= B_TRANSLATE("Could not create socket");
147 struct sockaddr_in address
;
148 address
.sin_family
= AF_INET
;
149 address
.sin_port
= htons(NTP_PORT
);
150 address
.sin_addr
.s_addr
= *(uint32
*)server
->h_addr_list
[0];
152 if (sendto(connection
, (char *)&message
, sizeof(ntp_data
),
153 0, (struct sockaddr
*)&address
, sizeof(address
)) < 0) {
154 *errorString
= B_TRANSLATE("Sending request failed");
160 fd_set waitForReceived
;
161 FD_ZERO(&waitForReceived
);
162 FD_SET(connection
, &waitForReceived
);
164 struct timeval timeout
;
167 // we'll wait 3 seconds for the answer
169 if (select(connection
+ 1, &waitForReceived
, NULL
, NULL
, &timeout
) <= 0) {
170 *errorString
= B_TRANSLATE("Waiting for answer failed");
176 message
.transmit_timestamp
.SetTo(0);
178 socklen_t addressSize
= sizeof(address
);
179 if (recvfrom(connection
, (char *)&message
, sizeof(ntp_data
), 0,
180 (sockaddr
*)&address
, &addressSize
) < (ssize_t
)sizeof(ntp_data
)) {
181 *errorString
= B_TRANSLATE("Message receiving failed");
189 if (message
.transmit_timestamp
.Integer() == 0) {
190 *errorString
= B_TRANSLATE("Received invalid time");
194 time_t now
= message
.transmit_timestamp
.Integer() - kSecondsBetween1900And1970
;
195 set_real_time_clock(now
);