Ticket #12319: ntp (without deprecated calls).cpp

File ntp (without deprecated calls).cpp, 5.8 KB (added by ttcoder, 9 years ago)

Modified to use BNetworkAddressResolver: we now pass all the "torture tests"..!

Line 
1/*
2
3gcc -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
47struct 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
62struct 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
77struct 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
101enum 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
108enum 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
119const uint32 kSecondsBetween1900And1970 = 2208988800UL;
120
121
122uint32
123seconds_since_1900(void)
124{
125 return kSecondsBetween1900And1970 + real_time_clock();
126}
127
128
129status_t
130ntp_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
235static 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
249int 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