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>
21 #include <NetworkAddress.h>
22 #include <NetworkAddressResolver.h>
25 #undef B_TRANSLATION_CONTEXT
26 #define B_TRANSLATION_CONTEXT "Time"
29 /* This structure and its data fields are described in RFC 1305
30 * "Network Time Protocol (Version 3)" in appendix A.
38 SetTo(int16 integer
, uint16 fraction
= 0)
40 this->integer
= htons(integer
);
41 this->fraction
= htons(fraction
);
44 int16
Integer() { return htons(integer
); }
45 uint16
Fraction() { return htons(fraction
); }
53 SetTo(uint32 integer
, uint32 fraction
= 0)
55 this->integer
= htonl(integer
);
56 this->fraction
= htonl(fraction
);
59 uint32
Integer() { return htonl(integer
); }
60 uint32
Fraction() { return htonl(fraction
); }
66 uint8 leap_indicator
: 2;
70 int8 precision
; /* in seconds of the nearest power of two */
73 fixed32 root_dispersion
;
74 uint32 root_identifier
;
76 ufixed64 reference_timestamp
;
77 ufixed64 originate_timestamp
;
78 ufixed64 receive_timestamp
;
79 ufixed64 transmit_timestamp
;
81 /* optional authenticator follows (96 bits) */
85 #define NTP_VERSION_3 3
87 enum ntp_leap_warnings
{
89 LEAP_LAST_MINUTE_61_SECONDS
,
90 LEAP_LAST_MINUTE_59_SECONDS
,
91 LEAP_CLOCK_NOT_IN_SYNC
,
96 MODE_SYMMETRIC_ACTIVE
,
97 MODE_SYMMETRIC_PASSIVE
,
101 MODE_NTP_CONTROL_MESSAGE
,
105 const uint32 kSecondsBetween1900And1970
= 2208988800UL;
109 seconds_since_1900(void)
111 return kSecondsBetween1900And1970
+ real_time_clock();
116 ntp_update_time(const char* hostname
, const char** errorString
,
119 BNetworkAddressResolver
resolver(hostname
, NTP_PORT
);
120 BNetworkAddress address
;
122 bool success
= false;
124 if (resolver
.InitCheck() != B_OK
) {
125 *errorString
= B_TRANSLATE("Could not resolve server address");
126 return B_ENTRY_NOT_FOUND
;
130 memset(&message
, 0, sizeof(ntp_data
));
132 message
.leap_indicator
= LEAP_CLOCK_NOT_IN_SYNC
;
133 message
.version
= NTP_VERSION_3
;
134 message
.mode
= MODE_CLIENT
;
136 message
.stratum
= 1; // primary reference
137 message
.precision
= -5; // 2^-5 ~ 32-64 Hz precision
139 message
.root_delay
.SetTo(1); // 1 sec
140 message
.root_dispersion
.SetTo(1);
142 message
.transmit_timestamp
.SetTo(seconds_since_1900());
144 int connection
= socket(AF_INET
, SOCK_DGRAM
, 0);
145 if (connection
< 0) {
146 *errorString
= B_TRANSLATE("Could not create socket");
151 while (resolver
.GetNextAddress(&cookie
, address
) == B_OK
) {
152 if (sendto(connection
, reinterpret_cast<char*>(&message
),
153 sizeof(ntp_data
), 0, &address
.SockAddr(),
154 address
.Length()) != -1) {
161 *errorString
= B_TRANSLATE("Sending request failed");
166 fd_set waitForReceived
;
167 FD_ZERO(&waitForReceived
);
168 FD_SET(connection
, &waitForReceived
);
170 struct timeval timeout
;
173 // we'll wait 3 seconds for the answer
175 if (select(connection
+ 1, &waitForReceived
, NULL
, NULL
, &timeout
) <= 0) {
176 *errorString
= B_TRANSLATE("Waiting for answer failed");
182 message
.transmit_timestamp
.SetTo(0);
184 socklen_t addressSize
= address
.Length();
185 if (recvfrom(connection
, reinterpret_cast<char*>(&message
), sizeof(ntp_data
), 0,
186 &address
.SockAddr(), &addressSize
) < (ssize_t
)sizeof(ntp_data
)) {
187 *errorString
= B_TRANSLATE("Message receiving failed");
195 if (message
.transmit_timestamp
.Integer() == 0) {
196 *errorString
= B_TRANSLATE("Received invalid time");
200 time_t now
= message
.transmit_timestamp
.Integer() - kSecondsBetween1900And1970
;
201 set_real_time_clock(now
);