1 | /*
|
---|
2 |
|
---|
3 | gcc -lnet -lnetapi ntp.cpp
|
---|
4 |
|
---|
5 | */
|
---|
6 |
|
---|
7 |
|
---|
8 | /*
|
---|
9 | * Copyright 2010-2011, Ryan Leavengood. All Rights Reserved.
|
---|
10 | * Copyright 2004-2009, pinc Software. All Rights Reserved.
|
---|
11 | * Distributed under the terms of the MIT license.
|
---|
12 | */
|
---|
13 |
|
---|
14 | #if 0
|
---|
15 | #include "ntp.h"
|
---|
16 | #else
|
---|
17 | #include "NetworkAddress.h"
|
---|
18 | #include "NetworkAddressResolver.h"
|
---|
19 | #endif
|
---|
20 |
|
---|
21 | #include <errno.h>
|
---|
22 | #include <netdb.h>
|
---|
23 | #include <string.h>
|
---|
24 | #include <stdio.h>
|
---|
25 | #include <stdlib.h>
|
---|
26 | #include <sys/select.h>
|
---|
27 | #include <sys/socket.h>
|
---|
28 | #include <unistd.h>
|
---|
29 |
|
---|
30 | #include <OS.h>
|
---|
31 |
|
---|
32 | #if 0
|
---|
33 | #include <Catalog.h>
|
---|
34 | #else
|
---|
35 | #define B_TRANSLATE(x) x
|
---|
36 | #endif
|
---|
37 |
|
---|
38 |
|
---|
39 | #undef B_TRANSLATION_CONTEXT
|
---|
40 | #define B_TRANSLATION_CONTEXT "Time"
|
---|
41 |
|
---|
42 |
|
---|
43 | /* This structure and its data fields are described in RFC 1305
|
---|
44 | * "Network Time Protocol (Version 3)" in appendix A.
|
---|
45 | */
|
---|
46 |
|
---|
47 | struct fixed32 {
|
---|
48 | int16 integer;
|
---|
49 | uint16 fraction;
|
---|
50 |
|
---|
51 | void
|
---|
52 | SetTo(int16 integer, uint16 fraction = 0)
|
---|
53 | {
|
---|
54 | this->integer = htons(integer);
|
---|
55 | this->fraction = htons(fraction);
|
---|
56 | }
|
---|
57 |
|
---|
58 | int16 Integer() { return htons(integer); }
|
---|
59 | uint16 Fraction() { return htons(fraction); }
|
---|
60 | };
|
---|
61 |
|
---|
62 | struct ufixed64 {
|
---|
63 | uint32 integer;
|
---|
64 | uint32 fraction;
|
---|
65 |
|
---|
66 | void
|
---|
67 | SetTo(uint32 integer, uint32 fraction = 0)
|
---|
68 | {
|
---|
69 | this->integer = htonl(integer);
|
---|
70 | this->fraction = htonl(fraction);
|
---|
71 | }
|
---|
72 |
|
---|
73 | uint32 Integer() { return htonl(integer); }
|
---|
74 | uint32 Fraction() { return htonl(fraction); }
|
---|
75 | };
|
---|
76 |
|
---|
77 | struct ntp_data {
|
---|
78 | uint8 mode : 3;
|
---|
79 | uint8 version : 3;
|
---|
80 | uint8 leap_indicator : 2;
|
---|
81 |
|
---|
82 | uint8 stratum;
|
---|
83 | int8 poll;
|
---|
84 | int8 precision; /* in seconds of the nearest power of two */
|
---|
85 |
|
---|
86 | fixed32 root_delay;
|
---|
87 | fixed32 root_dispersion;
|
---|
88 | uint32 root_identifier;
|
---|
89 |
|
---|
90 | ufixed64 reference_timestamp;
|
---|
91 | ufixed64 originate_timestamp;
|
---|
92 | ufixed64 receive_timestamp;
|
---|
93 | ufixed64 transmit_timestamp;
|
---|
94 |
|
---|
95 | /* optional authenticator follows (96 bits) */
|
---|
96 | };
|
---|
97 |
|
---|
98 | #define NTP_PORT 123
|
---|
99 | #define NTP_VERSION_3 3
|
---|
100 |
|
---|
101 | enum ntp_leap_warnings {
|
---|
102 | LEAP_NO_WARNING = 0,
|
---|
103 | LEAP_LAST_MINUTE_61_SECONDS,
|
---|
104 | LEAP_LAST_MINUTE_59_SECONDS,
|
---|
105 | LEAP_CLOCK_NOT_IN_SYNC,
|
---|
106 | };
|
---|
107 |
|
---|
108 | enum ntp_modes {
|
---|
109 | MODE_RESERVED = 0,
|
---|
110 | MODE_SYMMETRIC_ACTIVE,
|
---|
111 | MODE_SYMMETRIC_PASSIVE,
|
---|
112 | MODE_CLIENT,
|
---|
113 | MODE_SERVER,
|
---|
114 | MODE_BROADCAST,
|
---|
115 | MODE_NTP_CONTROL_MESSAGE,
|
---|
116 | };
|
---|
117 |
|
---|
118 |
|
---|
119 | const uint32 kSecondsBetween1900And1970 = 2208988800UL;
|
---|
120 |
|
---|
121 |
|
---|
122 | uint32
|
---|
123 | seconds_since_1900(void)
|
---|
124 | {
|
---|
125 | return kSecondsBetween1900And1970 + real_time_clock();
|
---|
126 | }
|
---|
127 |
|
---|
128 |
|
---|
129 | status_t
|
---|
130 | ntp_update_time(const char* hostname, const char** errorString,
|
---|
131 | int32* errorCode)
|
---|
132 | {
|
---|
133 | #if 0
|
---|
134 | hostent *server = gethostbyname(hostname);
|
---|
135 |
|
---|
136 | if (server == NULL) {
|
---|
137 |
|
---|
138 | *errorString = B_TRANSLATE("Could not contact server");
|
---|
139 | return B_ENTRY_NOT_FOUND;
|
---|
140 | }
|
---|
141 | #else
|
---|
142 | BNetworkAddressResolver resolver(hostname, NTP_PORT);
|
---|
143 |
|
---|
144 | BNetworkAddress address;
|
---|
145 | uint32 cookie = 0;
|
---|
146 |
|
---|
147 | if (resolver.InitCheck() != B_OK || resolver.GetNextAddress(&cookie, address) != B_OK) {
|
---|
148 |
|
---|
149 | *errorString = B_TRANSLATE("Could not contact server");
|
---|
150 | return B_ENTRY_NOT_FOUND;
|
---|
151 | }
|
---|
152 | #endif
|
---|
153 |
|
---|
154 | ntp_data message;
|
---|
155 | memset(&message, 0, sizeof(ntp_data));
|
---|
156 |
|
---|
157 | message.leap_indicator = LEAP_CLOCK_NOT_IN_SYNC;
|
---|
158 | message.version = NTP_VERSION_3;
|
---|
159 | message.mode = MODE_CLIENT;
|
---|
160 |
|
---|
161 | message.stratum = 1; // primary reference
|
---|
162 | message.precision = -5; // 2^-5 ~ 32-64 Hz precision
|
---|
163 |
|
---|
164 | message.root_delay.SetTo(1); // 1 sec
|
---|
165 | message.root_dispersion.SetTo(1);
|
---|
166 |
|
---|
167 | message.transmit_timestamp.SetTo(seconds_since_1900());
|
---|
168 |
|
---|
169 | int connection = socket(AF_INET, SOCK_DGRAM, 0);
|
---|
170 | if (connection < 0) {
|
---|
171 | *errorString = B_TRANSLATE("Could not create socket");
|
---|
172 | *errorCode = errno;
|
---|
173 | return B_ERROR;
|
---|
174 | }
|
---|
175 |
|
---|
176 | #if 0
|
---|
177 | struct sockaddr_in address;
|
---|
178 | address.sin_family = AF_INET;
|
---|
179 | address.sin_port = htons(NTP_PORT);
|
---|
180 | address.sin_addr.s_addr = *(uint32 *)server->h_addr_list[0];
|
---|
181 |
|
---|
182 | if (sendto(connection, (char *)&message, sizeof(ntp_data),
|
---|
183 | 0, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
---|
184 | #else
|
---|
185 | if (sendto(connection, reinterpret_cast<char *>(&message), sizeof(ntp_data),
|
---|
186 | 0, &address.SockAddr(), sizeof(address.SockAddr())) < 0) {
|
---|
187 | #endif
|
---|
188 | *errorString = B_TRANSLATE("Sending request failed");
|
---|
189 | *errorCode = errno;
|
---|
190 | close(connection);
|
---|
191 | return B_ERROR;
|
---|
192 | }
|
---|
193 |
|
---|
194 | fd_set waitForReceived;
|
---|
195 | FD_ZERO(&waitForReceived);
|
---|
196 | FD_SET(connection, &waitForReceived);
|
---|
197 |
|
---|
198 | struct timeval timeout;
|
---|
199 | timeout.tv_sec = 3;
|
---|
200 | timeout.tv_usec = 0;
|
---|
201 | // we'll wait 3 seconds for the answer
|
---|
202 |
|
---|
203 | if (select(connection + 1, &waitForReceived, NULL, NULL, &timeout) <= 0) {
|
---|
204 | *errorString = B_TRANSLATE("Waiting for answer failed");
|
---|
205 | *errorCode = errno;
|
---|
206 | close(connection);
|
---|
207 | return B_ERROR;
|
---|
208 | }
|
---|
209 |
|
---|
210 | message.transmit_timestamp.SetTo(0);
|
---|
211 |
|
---|
212 | socklen_t addressSize = sizeof(address);
|
---|
213 | if (recvfrom(connection, (char *)&message, sizeof(ntp_data), 0,
|
---|
214 | (sockaddr *)&address, &addressSize) < (ssize_t)sizeof(ntp_data)) {
|
---|
215 | *errorString = B_TRANSLATE("Message receiving failed");
|
---|
216 | *errorCode = errno;
|
---|
217 | close(connection);
|
---|
218 | return B_ERROR;
|
---|
219 | }
|
---|
220 |
|
---|
221 | close(connection);
|
---|
222 |
|
---|
223 | if (message.transmit_timestamp.Integer() == 0) {
|
---|
224 | *errorString = B_TRANSLATE("Received invalid time");
|
---|
225 | return B_BAD_VALUE;
|
---|
226 | }
|
---|
227 |
|
---|
228 | time_t now = message.transmit_timestamp.Integer() - kSecondsBetween1900And1970;
|
---|
229 | set_real_time_clock(now);
|
---|
230 | return B_OK;
|
---|
231 | }
|
---|
232 |
|
---|
233 |
|
---|
234 |
|
---|
235 | static status_t thread_f(void * dummy)
|
---|
236 | {
|
---|
237 | const char * resp = NULL;
|
---|
238 | int32 code = 0;
|
---|
239 | status_t result = ntp_update_time("pool.ntp.org", &resp, &code);
|
---|
240 |
|
---|
241 | printf("status=%ld code=%ld <%s>\n", result, code, resp);
|
---|
242 | if( B_OK != result )
|
---|
243 | printf(" ** -> failed\n");
|
---|
244 |
|
---|
245 | return 0;
|
---|
246 | }
|
---|
247 |
|
---|
248 |
|
---|
249 | int main()
|
---|
250 | {
|
---|
251 | printf("ntp..\n");
|
---|
252 |
|
---|
253 | while(1)
|
---|
254 | {
|
---|
255 | #if 0
|
---|
256 | const char * resp = NULL;
|
---|
257 | int32 code = 0;
|
---|
258 | ntp_update_time("pool.ntp.org", &resp, &code);
|
---|
259 |
|
---|
260 | printf("result code=%ld <%s>\n", code, resp);
|
---|
261 |
|
---|
262 | #else
|
---|
263 | thread_id updaterThread = spawn_thread(
|
---|
264 | thread_f, "(add-on)ntp_update_time",
|
---|
265 | B_NORMAL_PRIORITY,
|
---|
266 | NULL
|
---|
267 | );
|
---|
268 | resume_thread( updaterThread );
|
---|
269 |
|
---|
270 | /******/
|
---|
271 |
|
---|
272 | //snooze( 190000 );
|
---|
273 | //snooze( 20000 );
|
---|
274 | snooze( 110000 );
|
---|
275 | status_t test = resume_thread( updaterThread );
|
---|
276 | printf(" thread still exists?: 0x%lx <%s>\n", test, strerror(test));
|
---|
277 |
|
---|
278 | if( updaterThread > 0 )
|
---|
279 | kill_thread( updaterThread );
|
---|
280 | #endif
|
---|
281 | //snooze(1000000);
|
---|
282 | }
|
---|
283 |
|
---|
284 | return 0;
|
---|
285 | }
|
---|
286 |
|
---|
287 |
|
---|