1*323ba9b7SRyan Leavengood /* 2*323ba9b7SRyan Leavengood * Copyright 2010-2011, Ryan Leavengood. All Rights Reserved. 3*323ba9b7SRyan Leavengood * Copyright 2004-2009, pinc Software. All Rights Reserved. 4*323ba9b7SRyan Leavengood * Distributed under the terms of the MIT license. 5*323ba9b7SRyan Leavengood */ 6*323ba9b7SRyan Leavengood 7*323ba9b7SRyan Leavengood #include "ntp.h" 8*323ba9b7SRyan Leavengood 9*323ba9b7SRyan Leavengood #include <errno.h> 10*323ba9b7SRyan Leavengood #include <netdb.h> 11*323ba9b7SRyan Leavengood #include <string.h> 12*323ba9b7SRyan Leavengood #include <stdio.h> 13*323ba9b7SRyan Leavengood #include <stdlib.h> 14*323ba9b7SRyan Leavengood #include <sys/select.h> 15*323ba9b7SRyan Leavengood #include <sys/socket.h> 16*323ba9b7SRyan Leavengood #include <unistd.h> 17*323ba9b7SRyan Leavengood 18*323ba9b7SRyan Leavengood #include <OS.h> 19*323ba9b7SRyan Leavengood 20*323ba9b7SRyan Leavengood 21*323ba9b7SRyan Leavengood /* This structure and its data fields are described in RFC 1305 22*323ba9b7SRyan Leavengood * "Network Time Protocol (Version 3)" in appendix A. 23*323ba9b7SRyan Leavengood */ 24*323ba9b7SRyan Leavengood 25*323ba9b7SRyan Leavengood struct fixed32 { 26*323ba9b7SRyan Leavengood int16 integer; 27*323ba9b7SRyan Leavengood uint16 fraction; 28*323ba9b7SRyan Leavengood 29*323ba9b7SRyan Leavengood void 30*323ba9b7SRyan Leavengood SetTo(int16 integer, uint16 fraction = 0) 31*323ba9b7SRyan Leavengood { 32*323ba9b7SRyan Leavengood this->integer = htons(integer); 33*323ba9b7SRyan Leavengood this->fraction = htons(fraction); 34*323ba9b7SRyan Leavengood } 35*323ba9b7SRyan Leavengood 36*323ba9b7SRyan Leavengood int16 Integer() { return htons(integer); } 37*323ba9b7SRyan Leavengood uint16 Fraction() { return htons(fraction); } 38*323ba9b7SRyan Leavengood }; 39*323ba9b7SRyan Leavengood 40*323ba9b7SRyan Leavengood struct ufixed64 { 41*323ba9b7SRyan Leavengood uint32 integer; 42*323ba9b7SRyan Leavengood uint32 fraction; 43*323ba9b7SRyan Leavengood 44*323ba9b7SRyan Leavengood void 45*323ba9b7SRyan Leavengood SetTo(uint32 integer, uint32 fraction = 0) 46*323ba9b7SRyan Leavengood { 47*323ba9b7SRyan Leavengood this->integer = htonl(integer); 48*323ba9b7SRyan Leavengood this->fraction = htonl(fraction); 49*323ba9b7SRyan Leavengood } 50*323ba9b7SRyan Leavengood 51*323ba9b7SRyan Leavengood uint32 Integer() { return htonl(integer); } 52*323ba9b7SRyan Leavengood uint32 Fraction() { return htonl(fraction); } 53*323ba9b7SRyan Leavengood }; 54*323ba9b7SRyan Leavengood 55*323ba9b7SRyan Leavengood struct ntp_data { 56*323ba9b7SRyan Leavengood uint8 mode : 3; 57*323ba9b7SRyan Leavengood uint8 version : 3; 58*323ba9b7SRyan Leavengood uint8 leap_indicator : 2; 59*323ba9b7SRyan Leavengood 60*323ba9b7SRyan Leavengood uint8 stratum; 61*323ba9b7SRyan Leavengood int8 poll; 62*323ba9b7SRyan Leavengood int8 precision; /* in seconds of the nearest power of two */ 63*323ba9b7SRyan Leavengood 64*323ba9b7SRyan Leavengood fixed32 root_delay; 65*323ba9b7SRyan Leavengood fixed32 root_dispersion; 66*323ba9b7SRyan Leavengood uint32 root_identifier; 67*323ba9b7SRyan Leavengood 68*323ba9b7SRyan Leavengood ufixed64 reference_timestamp; 69*323ba9b7SRyan Leavengood ufixed64 originate_timestamp; 70*323ba9b7SRyan Leavengood ufixed64 receive_timestamp; 71*323ba9b7SRyan Leavengood ufixed64 transmit_timestamp; 72*323ba9b7SRyan Leavengood 73*323ba9b7SRyan Leavengood /* optional authenticator follows (96 bits) */ 74*323ba9b7SRyan Leavengood }; 75*323ba9b7SRyan Leavengood 76*323ba9b7SRyan Leavengood #define NTP_PORT 123 77*323ba9b7SRyan Leavengood #define NTP_VERSION_3 3 78*323ba9b7SRyan Leavengood 79*323ba9b7SRyan Leavengood enum ntp_leap_warnings { 80*323ba9b7SRyan Leavengood LEAP_NO_WARNING = 0, 81*323ba9b7SRyan Leavengood LEAP_LAST_MINUTE_61_SECONDS, 82*323ba9b7SRyan Leavengood LEAP_LAST_MINUTE_59_SECONDS, 83*323ba9b7SRyan Leavengood LEAP_CLOCK_NOT_IN_SYNC, 84*323ba9b7SRyan Leavengood }; 85*323ba9b7SRyan Leavengood 86*323ba9b7SRyan Leavengood enum ntp_modes { 87*323ba9b7SRyan Leavengood MODE_RESERVED = 0, 88*323ba9b7SRyan Leavengood MODE_SYMMETRIC_ACTIVE, 89*323ba9b7SRyan Leavengood MODE_SYMMETRIC_PASSIVE, 90*323ba9b7SRyan Leavengood MODE_CLIENT, 91*323ba9b7SRyan Leavengood MODE_SERVER, 92*323ba9b7SRyan Leavengood MODE_BROADCAST, 93*323ba9b7SRyan Leavengood MODE_NTP_CONTROL_MESSAGE, 94*323ba9b7SRyan Leavengood }; 95*323ba9b7SRyan Leavengood 96*323ba9b7SRyan Leavengood 97*323ba9b7SRyan Leavengood const uint32 kSecondsBetween1900And1970 = 2208988800UL; 98*323ba9b7SRyan Leavengood 99*323ba9b7SRyan Leavengood 100*323ba9b7SRyan Leavengood uint32 101*323ba9b7SRyan Leavengood seconds_since_1900(void) 102*323ba9b7SRyan Leavengood { 103*323ba9b7SRyan Leavengood return kSecondsBetween1900And1970 + real_time_clock(); 104*323ba9b7SRyan Leavengood } 105*323ba9b7SRyan Leavengood 106*323ba9b7SRyan Leavengood 107*323ba9b7SRyan Leavengood status_t 108*323ba9b7SRyan Leavengood ntp_update_time(const char* hostname, const char** errorString, 109*323ba9b7SRyan Leavengood int32* errorCode) 110*323ba9b7SRyan Leavengood { 111*323ba9b7SRyan Leavengood hostent *server = gethostbyname(hostname); 112*323ba9b7SRyan Leavengood 113*323ba9b7SRyan Leavengood if (server == NULL) { 114*323ba9b7SRyan Leavengood 115*323ba9b7SRyan Leavengood *errorString = "Could not contact server"; 116*323ba9b7SRyan Leavengood return B_ENTRY_NOT_FOUND; 117*323ba9b7SRyan Leavengood } 118*323ba9b7SRyan Leavengood 119*323ba9b7SRyan Leavengood ntp_data message; 120*323ba9b7SRyan Leavengood memset(&message, 0, sizeof(ntp_data)); 121*323ba9b7SRyan Leavengood 122*323ba9b7SRyan Leavengood message.leap_indicator = LEAP_CLOCK_NOT_IN_SYNC; 123*323ba9b7SRyan Leavengood message.version = NTP_VERSION_3; 124*323ba9b7SRyan Leavengood message.mode = MODE_CLIENT; 125*323ba9b7SRyan Leavengood 126*323ba9b7SRyan Leavengood message.stratum = 1; // primary reference 127*323ba9b7SRyan Leavengood message.precision = -5; // 2^-5 ~ 32-64 Hz precision 128*323ba9b7SRyan Leavengood 129*323ba9b7SRyan Leavengood message.root_delay.SetTo(1); // 1 sec 130*323ba9b7SRyan Leavengood message.root_dispersion.SetTo(1); 131*323ba9b7SRyan Leavengood 132*323ba9b7SRyan Leavengood message.transmit_timestamp.SetTo(seconds_since_1900()); 133*323ba9b7SRyan Leavengood 134*323ba9b7SRyan Leavengood int connection = socket(AF_INET, SOCK_DGRAM, 0); 135*323ba9b7SRyan Leavengood if (connection < 0) { 136*323ba9b7SRyan Leavengood *errorString = "Could not create socket"; 137*323ba9b7SRyan Leavengood *errorCode = errno; 138*323ba9b7SRyan Leavengood return B_ERROR; 139*323ba9b7SRyan Leavengood } 140*323ba9b7SRyan Leavengood 141*323ba9b7SRyan Leavengood struct sockaddr_in address; 142*323ba9b7SRyan Leavengood address.sin_family = AF_INET; 143*323ba9b7SRyan Leavengood address.sin_port = htons(NTP_PORT); 144*323ba9b7SRyan Leavengood address.sin_addr.s_addr = *(uint32 *)server->h_addr_list[0]; 145*323ba9b7SRyan Leavengood 146*323ba9b7SRyan Leavengood if (sendto(connection, (char *)&message, sizeof(ntp_data), 147*323ba9b7SRyan Leavengood 0, (struct sockaddr *)&address, sizeof(address)) < 0) { 148*323ba9b7SRyan Leavengood *errorString = "Sending request failed"; 149*323ba9b7SRyan Leavengood *errorCode = errno; 150*323ba9b7SRyan Leavengood return B_ERROR; 151*323ba9b7SRyan Leavengood } 152*323ba9b7SRyan Leavengood 153*323ba9b7SRyan Leavengood fd_set waitForReceived; 154*323ba9b7SRyan Leavengood FD_ZERO(&waitForReceived); 155*323ba9b7SRyan Leavengood FD_SET(connection, &waitForReceived); 156*323ba9b7SRyan Leavengood 157*323ba9b7SRyan Leavengood struct timeval timeout; 158*323ba9b7SRyan Leavengood timeout.tv_sec = 3; 159*323ba9b7SRyan Leavengood timeout.tv_usec = 0; 160*323ba9b7SRyan Leavengood // we'll wait 3 seconds for the answer 161*323ba9b7SRyan Leavengood 162*323ba9b7SRyan Leavengood if (select(connection + 1, &waitForReceived, NULL, NULL, &timeout) <= 0) { 163*323ba9b7SRyan Leavengood *errorString = "Waiting for answer failed"; 164*323ba9b7SRyan Leavengood *errorCode = errno; 165*323ba9b7SRyan Leavengood return B_ERROR; 166*323ba9b7SRyan Leavengood } 167*323ba9b7SRyan Leavengood 168*323ba9b7SRyan Leavengood message.transmit_timestamp.SetTo(0); 169*323ba9b7SRyan Leavengood 170*323ba9b7SRyan Leavengood socklen_t addressSize = sizeof(address); 171*323ba9b7SRyan Leavengood if (recvfrom(connection, (char *)&message, sizeof(ntp_data), 0, 172*323ba9b7SRyan Leavengood (sockaddr *)&address, &addressSize) < (ssize_t)sizeof(ntp_data)) { 173*323ba9b7SRyan Leavengood *errorString = "Message receiving failed"; 174*323ba9b7SRyan Leavengood *errorCode = errno; 175*323ba9b7SRyan Leavengood close(connection); 176*323ba9b7SRyan Leavengood return B_ERROR; 177*323ba9b7SRyan Leavengood } 178*323ba9b7SRyan Leavengood 179*323ba9b7SRyan Leavengood close(connection); 180*323ba9b7SRyan Leavengood 181*323ba9b7SRyan Leavengood if (message.transmit_timestamp.Integer() == 0) { 182*323ba9b7SRyan Leavengood *errorString = "Received invalid time"; 183*323ba9b7SRyan Leavengood return B_BAD_VALUE; 184*323ba9b7SRyan Leavengood } 185*323ba9b7SRyan Leavengood 186*323ba9b7SRyan Leavengood time_t now = message.transmit_timestamp.Integer() - kSecondsBetween1900And1970; 187*323ba9b7SRyan Leavengood set_real_time_clock(now); 188*323ba9b7SRyan Leavengood return B_OK; 189*323ba9b7SRyan Leavengood } 190