tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / preferences / time / ntp.cpp
blob167ef2ca4bf396df6b3cba3423a6858b01af8339
1 /*
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.
5 */
7 #include "ntp.h"
9 #include <errno.h>
10 #include <netdb.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <sys/select.h>
15 #include <sys/socket.h>
16 #include <unistd.h>
18 #include <OS.h>
20 #include <Catalog.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.
31 struct fixed32 {
32 int16 integer;
33 uint16 fraction;
35 void
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); }
46 struct ufixed64 {
47 uint32 integer;
48 uint32 fraction;
50 void
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); }
61 struct ntp_data {
62 uint8 mode : 3;
63 uint8 version : 3;
64 uint8 leap_indicator : 2;
66 uint8 stratum;
67 int8 poll;
68 int8 precision; /* in seconds of the nearest power of two */
70 fixed32 root_delay;
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) */
82 #define NTP_PORT 123
83 #define NTP_VERSION_3 3
85 enum ntp_leap_warnings {
86 LEAP_NO_WARNING = 0,
87 LEAP_LAST_MINUTE_61_SECONDS,
88 LEAP_LAST_MINUTE_59_SECONDS,
89 LEAP_CLOCK_NOT_IN_SYNC,
92 enum ntp_modes {
93 MODE_RESERVED = 0,
94 MODE_SYMMETRIC_ACTIVE,
95 MODE_SYMMETRIC_PASSIVE,
96 MODE_CLIENT,
97 MODE_SERVER,
98 MODE_BROADCAST,
99 MODE_NTP_CONTROL_MESSAGE,
103 const uint32 kSecondsBetween1900And1970 = 2208988800UL;
106 uint32
107 seconds_since_1900(void)
109 return kSecondsBetween1900And1970 + real_time_clock();
113 status_t
114 ntp_update_time(const char* hostname, const char** errorString,
115 int32* errorCode)
117 hostent *server = gethostbyname(hostname);
119 if (server == NULL) {
121 *errorString = B_TRANSLATE("Could not contact server");
122 return B_ENTRY_NOT_FOUND;
125 ntp_data message;
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");
143 *errorCode = errno;
144 return B_ERROR;
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");
155 *errorCode = errno;
156 close(connection);
157 return B_ERROR;
160 fd_set waitForReceived;
161 FD_ZERO(&waitForReceived);
162 FD_SET(connection, &waitForReceived);
164 struct timeval timeout;
165 timeout.tv_sec = 3;
166 timeout.tv_usec = 0;
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");
171 *errorCode = errno;
172 close(connection);
173 return B_ERROR;
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");
182 *errorCode = errno;
183 close(connection);
184 return B_ERROR;
187 close(connection);
189 if (message.transmit_timestamp.Integer() == 0) {
190 *errorString = B_TRANSLATE("Received invalid time");
191 return B_BAD_VALUE;
194 time_t now = message.transmit_timestamp.Integer() - kSecondsBetween1900And1970;
195 set_real_time_clock(now);
196 return B_OK;