1323ba9b7SRyan Leavengood /* 2323ba9b7SRyan Leavengood * Copyright 2010-2011, Ryan Leavengood. All Rights Reserved. 3323ba9b7SRyan Leavengood * Copyright 2004-2009, pinc Software. All Rights Reserved. 4323ba9b7SRyan Leavengood * Distributed under the terms of the MIT license. 5323ba9b7SRyan Leavengood */ 6323ba9b7SRyan Leavengood 7323ba9b7SRyan Leavengood #include "ntp.h" 8323ba9b7SRyan Leavengood 9323ba9b7SRyan Leavengood #include <errno.h> 10323ba9b7SRyan Leavengood #include <netdb.h> 11323ba9b7SRyan Leavengood #include <string.h> 12323ba9b7SRyan Leavengood #include <stdio.h> 13323ba9b7SRyan Leavengood #include <stdlib.h> 14323ba9b7SRyan Leavengood #include <sys/select.h> 15323ba9b7SRyan Leavengood #include <sys/socket.h> 16323ba9b7SRyan Leavengood #include <unistd.h> 17323ba9b7SRyan Leavengood 18323ba9b7SRyan Leavengood #include <OS.h> 19323ba9b7SRyan Leavengood 20*8c333297SRyan Leavengood #include <Catalog.h> 21*8c333297SRyan Leavengood 22*8c333297SRyan Leavengood 23*8c333297SRyan Leavengood #undef B_TRANSLATE_CONTEXT 24*8c333297SRyan Leavengood #define B_TRANSLATE_CONTEXT "Time" 25*8c333297SRyan Leavengood 26323ba9b7SRyan Leavengood 27323ba9b7SRyan Leavengood /* This structure and its data fields are described in RFC 1305 28323ba9b7SRyan Leavengood * "Network Time Protocol (Version 3)" in appendix A. 29323ba9b7SRyan Leavengood */ 30323ba9b7SRyan Leavengood 31323ba9b7SRyan Leavengood struct fixed32 { 32323ba9b7SRyan Leavengood int16 integer; 33323ba9b7SRyan Leavengood uint16 fraction; 34323ba9b7SRyan Leavengood 35323ba9b7SRyan Leavengood void 36323ba9b7SRyan Leavengood SetTo(int16 integer, uint16 fraction = 0) 37323ba9b7SRyan Leavengood { 38323ba9b7SRyan Leavengood this->integer = htons(integer); 39323ba9b7SRyan Leavengood this->fraction = htons(fraction); 40323ba9b7SRyan Leavengood } 41323ba9b7SRyan Leavengood 42323ba9b7SRyan Leavengood int16 Integer() { return htons(integer); } 43323ba9b7SRyan Leavengood uint16 Fraction() { return htons(fraction); } 44323ba9b7SRyan Leavengood }; 45323ba9b7SRyan Leavengood 46323ba9b7SRyan Leavengood struct ufixed64 { 47323ba9b7SRyan Leavengood uint32 integer; 48323ba9b7SRyan Leavengood uint32 fraction; 49323ba9b7SRyan Leavengood 50323ba9b7SRyan Leavengood void 51323ba9b7SRyan Leavengood SetTo(uint32 integer, uint32 fraction = 0) 52323ba9b7SRyan Leavengood { 53323ba9b7SRyan Leavengood this->integer = htonl(integer); 54323ba9b7SRyan Leavengood this->fraction = htonl(fraction); 55323ba9b7SRyan Leavengood } 56323ba9b7SRyan Leavengood 57323ba9b7SRyan Leavengood uint32 Integer() { return htonl(integer); } 58323ba9b7SRyan Leavengood uint32 Fraction() { return htonl(fraction); } 59323ba9b7SRyan Leavengood }; 60323ba9b7SRyan Leavengood 61323ba9b7SRyan Leavengood struct ntp_data { 62323ba9b7SRyan Leavengood uint8 mode : 3; 63323ba9b7SRyan Leavengood uint8 version : 3; 64323ba9b7SRyan Leavengood uint8 leap_indicator : 2; 65323ba9b7SRyan Leavengood 66323ba9b7SRyan Leavengood uint8 stratum; 67323ba9b7SRyan Leavengood int8 poll; 68323ba9b7SRyan Leavengood int8 precision; /* in seconds of the nearest power of two */ 69323ba9b7SRyan Leavengood 70323ba9b7SRyan Leavengood fixed32 root_delay; 71323ba9b7SRyan Leavengood fixed32 root_dispersion; 72323ba9b7SRyan Leavengood uint32 root_identifier; 73323ba9b7SRyan Leavengood 74323ba9b7SRyan Leavengood ufixed64 reference_timestamp; 75323ba9b7SRyan Leavengood ufixed64 originate_timestamp; 76323ba9b7SRyan Leavengood ufixed64 receive_timestamp; 77323ba9b7SRyan Leavengood ufixed64 transmit_timestamp; 78323ba9b7SRyan Leavengood 79323ba9b7SRyan Leavengood /* optional authenticator follows (96 bits) */ 80323ba9b7SRyan Leavengood }; 81323ba9b7SRyan Leavengood 82323ba9b7SRyan Leavengood #define NTP_PORT 123 83323ba9b7SRyan Leavengood #define NTP_VERSION_3 3 84323ba9b7SRyan Leavengood 85323ba9b7SRyan Leavengood enum ntp_leap_warnings { 86323ba9b7SRyan Leavengood LEAP_NO_WARNING = 0, 87323ba9b7SRyan Leavengood LEAP_LAST_MINUTE_61_SECONDS, 88323ba9b7SRyan Leavengood LEAP_LAST_MINUTE_59_SECONDS, 89323ba9b7SRyan Leavengood LEAP_CLOCK_NOT_IN_SYNC, 90323ba9b7SRyan Leavengood }; 91323ba9b7SRyan Leavengood 92323ba9b7SRyan Leavengood enum ntp_modes { 93323ba9b7SRyan Leavengood MODE_RESERVED = 0, 94323ba9b7SRyan Leavengood MODE_SYMMETRIC_ACTIVE, 95323ba9b7SRyan Leavengood MODE_SYMMETRIC_PASSIVE, 96323ba9b7SRyan Leavengood MODE_CLIENT, 97323ba9b7SRyan Leavengood MODE_SERVER, 98323ba9b7SRyan Leavengood MODE_BROADCAST, 99323ba9b7SRyan Leavengood MODE_NTP_CONTROL_MESSAGE, 100323ba9b7SRyan Leavengood }; 101323ba9b7SRyan Leavengood 102323ba9b7SRyan Leavengood 103323ba9b7SRyan Leavengood const uint32 kSecondsBetween1900And1970 = 2208988800UL; 104323ba9b7SRyan Leavengood 105323ba9b7SRyan Leavengood 106323ba9b7SRyan Leavengood uint32 107323ba9b7SRyan Leavengood seconds_since_1900(void) 108323ba9b7SRyan Leavengood { 109323ba9b7SRyan Leavengood return kSecondsBetween1900And1970 + real_time_clock(); 110323ba9b7SRyan Leavengood } 111323ba9b7SRyan Leavengood 112323ba9b7SRyan Leavengood 113323ba9b7SRyan Leavengood status_t 114323ba9b7SRyan Leavengood ntp_update_time(const char* hostname, const char** errorString, 115323ba9b7SRyan Leavengood int32* errorCode) 116323ba9b7SRyan Leavengood { 117323ba9b7SRyan Leavengood hostent *server = gethostbyname(hostname); 118323ba9b7SRyan Leavengood 119323ba9b7SRyan Leavengood if (server == NULL) { 120323ba9b7SRyan Leavengood 121*8c333297SRyan Leavengood *errorString = B_TRANSLATE("Could not contact server"); 122323ba9b7SRyan Leavengood return B_ENTRY_NOT_FOUND; 123323ba9b7SRyan Leavengood } 124323ba9b7SRyan Leavengood 125323ba9b7SRyan Leavengood ntp_data message; 126323ba9b7SRyan Leavengood memset(&message, 0, sizeof(ntp_data)); 127323ba9b7SRyan Leavengood 128323ba9b7SRyan Leavengood message.leap_indicator = LEAP_CLOCK_NOT_IN_SYNC; 129323ba9b7SRyan Leavengood message.version = NTP_VERSION_3; 130323ba9b7SRyan Leavengood message.mode = MODE_CLIENT; 131323ba9b7SRyan Leavengood 132323ba9b7SRyan Leavengood message.stratum = 1; // primary reference 133323ba9b7SRyan Leavengood message.precision = -5; // 2^-5 ~ 32-64 Hz precision 134323ba9b7SRyan Leavengood 135323ba9b7SRyan Leavengood message.root_delay.SetTo(1); // 1 sec 136323ba9b7SRyan Leavengood message.root_dispersion.SetTo(1); 137323ba9b7SRyan Leavengood 138323ba9b7SRyan Leavengood message.transmit_timestamp.SetTo(seconds_since_1900()); 139323ba9b7SRyan Leavengood 140323ba9b7SRyan Leavengood int connection = socket(AF_INET, SOCK_DGRAM, 0); 141323ba9b7SRyan Leavengood if (connection < 0) { 142*8c333297SRyan Leavengood *errorString = B_TRANSLATE("Could not create socket"); 143323ba9b7SRyan Leavengood *errorCode = errno; 144323ba9b7SRyan Leavengood return B_ERROR; 145323ba9b7SRyan Leavengood } 146323ba9b7SRyan Leavengood 147323ba9b7SRyan Leavengood struct sockaddr_in address; 148323ba9b7SRyan Leavengood address.sin_family = AF_INET; 149323ba9b7SRyan Leavengood address.sin_port = htons(NTP_PORT); 150323ba9b7SRyan Leavengood address.sin_addr.s_addr = *(uint32 *)server->h_addr_list[0]; 151323ba9b7SRyan Leavengood 152323ba9b7SRyan Leavengood if (sendto(connection, (char *)&message, sizeof(ntp_data), 153323ba9b7SRyan Leavengood 0, (struct sockaddr *)&address, sizeof(address)) < 0) { 154*8c333297SRyan Leavengood *errorString = B_TRANSLATE("Sending request failed"); 155323ba9b7SRyan Leavengood *errorCode = errno; 156323ba9b7SRyan Leavengood return B_ERROR; 157323ba9b7SRyan Leavengood } 158323ba9b7SRyan Leavengood 159323ba9b7SRyan Leavengood fd_set waitForReceived; 160323ba9b7SRyan Leavengood FD_ZERO(&waitForReceived); 161323ba9b7SRyan Leavengood FD_SET(connection, &waitForReceived); 162323ba9b7SRyan Leavengood 163323ba9b7SRyan Leavengood struct timeval timeout; 164323ba9b7SRyan Leavengood timeout.tv_sec = 3; 165323ba9b7SRyan Leavengood timeout.tv_usec = 0; 166323ba9b7SRyan Leavengood // we'll wait 3 seconds for the answer 167323ba9b7SRyan Leavengood 168323ba9b7SRyan Leavengood if (select(connection + 1, &waitForReceived, NULL, NULL, &timeout) <= 0) { 169*8c333297SRyan Leavengood *errorString = B_TRANSLATE("Waiting for answer failed"); 170323ba9b7SRyan Leavengood *errorCode = errno; 171323ba9b7SRyan Leavengood return B_ERROR; 172323ba9b7SRyan Leavengood } 173323ba9b7SRyan Leavengood 174323ba9b7SRyan Leavengood message.transmit_timestamp.SetTo(0); 175323ba9b7SRyan Leavengood 176323ba9b7SRyan Leavengood socklen_t addressSize = sizeof(address); 177323ba9b7SRyan Leavengood if (recvfrom(connection, (char *)&message, sizeof(ntp_data), 0, 178323ba9b7SRyan Leavengood (sockaddr *)&address, &addressSize) < (ssize_t)sizeof(ntp_data)) { 179*8c333297SRyan Leavengood *errorString = B_TRANSLATE("Message receiving failed"); 180323ba9b7SRyan Leavengood *errorCode = errno; 181323ba9b7SRyan Leavengood close(connection); 182323ba9b7SRyan Leavengood return B_ERROR; 183323ba9b7SRyan Leavengood } 184323ba9b7SRyan Leavengood 185323ba9b7SRyan Leavengood close(connection); 186323ba9b7SRyan Leavengood 187323ba9b7SRyan Leavengood if (message.transmit_timestamp.Integer() == 0) { 188*8c333297SRyan Leavengood *errorString = B_TRANSLATE("Received invalid time"); 189323ba9b7SRyan Leavengood return B_BAD_VALUE; 190323ba9b7SRyan Leavengood } 191323ba9b7SRyan Leavengood 192323ba9b7SRyan Leavengood time_t now = message.transmit_timestamp.Integer() - kSecondsBetween1900And1970; 193323ba9b7SRyan Leavengood set_real_time_clock(now); 194323ba9b7SRyan Leavengood return B_OK; 195323ba9b7SRyan Leavengood } 196