NTP Client for the mbed networking libraries. The small change to this version is that there can be only one cause for the return value zero.
Fork of NTPClient by
NTPClient.cpp
00001 /* NTPClient.cpp */ 00002 /* Copyright (C) 2012 mbed.org, MIT License 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00005 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00006 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00007 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00008 * furnished to do so, subject to the following conditions: 00009 * 00010 * The above copyright notice and this permission notice shall be included in all copies or 00011 * substantial portions of the Software. 00012 * 00013 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00014 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00015 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00016 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00017 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00018 */ 00019 #include "mbed.h" //time() and set_time() 00020 00021 //#define DEBUG "NTPc" 00022 00023 #if (defined(DEBUG)) 00024 #include <cstdio> 00025 #define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00026 #define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00027 #define ERR(x, ...) std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00028 static void HexDump(const char * title, const uint8_t * p, int count) 00029 { 00030 int i; 00031 char buf[100] = "0000: "; 00032 00033 if (*title) 00034 INFO("%s", title); 00035 for (i=0; i<count; ) { 00036 sprintf(buf + strlen(buf), "%02X ", *(p+i)); 00037 if ((++i & 0x0F) == 0x00) { 00038 INFO("%s", buf); 00039 if (i < count) 00040 sprintf(buf, "%04X: ", i); 00041 else 00042 buf[0] = '\0'; 00043 } 00044 } 00045 if (strlen(buf)) 00046 INFO("%s", buf); 00047 } 00048 #else 00049 //Disable debug 00050 #define INFO(x, ...) 00051 #define WARN(x, ...) 00052 #define ERR(x, ...) 00053 #define HexDump(a,b,c) 00054 #endif 00055 00056 #include "NTPClient.h" 00057 00058 #include "UDPSocket.h" 00059 00060 00061 #define NTP_PORT 123 00062 #define NTP_CLIENT_PORT 0 //Random port 00063 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900) 00064 00065 NTPClient::NTPClient() : m_sock() 00066 { 00067 00068 } 00069 00070 NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout) 00071 { 00072 #ifdef DEBUG 00073 time_t ctTime; 00074 ctTime = time(NULL); 00075 INFO("Time is currently (UTC): %s", ctime(&ctTime)); 00076 #endif 00077 00078 //Create & bind socket 00079 INFO("Binding socket"); 00080 m_sock.bind(0); //Bind to a random port 00081 00082 m_sock.set_blocking(false, timeout); //Set not blocking 00083 00084 struct NTPPacket pkt; 00085 00086 //Now ping the server and wait for response 00087 INFO("Ping"); 00088 //Prepare NTP Packet: 00089 pkt.li = 0; //Leap Indicator : No warning 00090 pkt.vn = 4; //Version Number : 4 00091 pkt.mode = 3; //Client mode 00092 pkt.stratum = 0; //Not relevant here 00093 pkt.poll = 0; //Not significant as well 00094 pkt.precision = 0; //Neither this one is 00095 00096 pkt.rootDelay = 0; //Or this one 00097 pkt.rootDispersion = 0; //Or that one 00098 pkt.refId = 0; //... 00099 00100 pkt.refTm_s = 0; 00101 pkt.origTm_s = 0; 00102 pkt.rxTm_s = 0; 00103 pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE 00104 INFO("pkt.txTm_s = %u", ntohl(pkt.txTm_s) ); 00105 pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0; 00106 00107 HexDump("NTP Post", (uint8_t *)&pkt, sizeof(NTPPacket)); 00108 00109 Endpoint outEndpoint; 00110 INFO("outEndpoint instantiated"); 00111 00112 if( outEndpoint.set_address(host, port) < 0) { 00113 m_sock.close(); 00114 return NTP_DNS; 00115 } 00116 INFO("outEndpoint: %s:%d", outEndpoint.get_address(), outEndpoint.get_port()); 00117 00118 //Set timeout, non-blocking and wait using select 00119 int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) ); 00120 if (ret < 0 ) { 00121 ERR("Could not send packet"); 00122 m_sock.close(); 00123 return NTP_CONN; 00124 } 00125 00126 //Read response 00127 Endpoint inEndpoint; 00128 INFO(" inEndpoint instantiated: %s.", inEndpoint.get_address()); 00129 00130 // Set the inEndpoint address property 00131 inEndpoint.set_address(outEndpoint.get_address(), 0); 00132 00133 INFO(" inEndpoint: %s", inEndpoint.get_address()); 00134 00135 INFO("Pong"); 00136 int loopLimit = 20; // semi-randomly selected so it doesn't hang forever here... 00137 do { 00138 ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); 00139 if(ret < 0) { 00140 ERR("Could not receive packet"); 00141 m_sock.close(); 00142 return NTP_CONN; 00143 } 00144 INFO("."); 00145 loopLimit--; 00146 } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 && loopLimit > 0); 00147 00148 if(ret < (int)sizeof(NTPPacket)) { //TODO: Accept chunks 00149 ERR("Receive packet size does not match"); 00150 m_sock.close(); 00151 return NTP_PRTCL; 00152 } 00153 00154 if( pkt.stratum == 0) { //Kiss of death message : Not good ! 00155 ERR("Kissed to death!"); 00156 m_sock.close(); 00157 return NTP_PRTCL; 00158 } 00159 00160 HexDump("NTP Info", (uint8_t *)&pkt, sizeof(NTPPacket)); 00161 00162 //Correct Endianness 00163 pkt.refTm_s = ntohl( pkt.refTm_s ); 00164 pkt.refTm_f = ntohl( pkt.refTm_f ); 00165 pkt.origTm_s = ntohl( pkt.origTm_s ); 00166 pkt.origTm_f = ntohl( pkt.origTm_f ); 00167 pkt.rxTm_s = ntohl( pkt.rxTm_s ); 00168 pkt.rxTm_f = ntohl( pkt.rxTm_f ); 00169 pkt.txTm_s = ntohl( pkt.txTm_s ); 00170 pkt.txTm_f = ntohl( pkt.txTm_f ); 00171 00172 //Compute offset, see RFC 4330 p.13 00173 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL)); 00174 INFO("destTm_s = %u", destTm_s); 00175 INFO("pkt.txTm_s = %u", pkt.txTm_s ); 00176 00177 // Modification by David Smart 00178 // The setTime function was computing the offset incorrectly as the value was promoted to 64-bit. 00179 // The side effect was that a negative offset ended up as a very large positive (e.g. jump from 00180 // 2016 to 2084). This change revises that computation. 00181 int64_t offset = ( ((int64_t)pkt.rxTm_s - pkt.origTm_s ) + ((int64_t) pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow 00182 00183 // delay is not needed, this was for diagnostic purposes only. 00184 //int64_t delay = ((int64_t) destTm_s - pkt.origTm_s) - ((int64_t) pkt.txTm_s - pkt.rxTm_s); 00185 INFO("txTm_s @%u", pkt.txTm_s); 00186 INFO("origTm_s @%u", pkt.origTm_s); 00187 INFO("rxTm_s @%u", pkt.rxTm_s); 00188 INFO("destTm_s @%u", destTm_s); 00189 INFO("Offset: %lld", offset); 00190 //INFO("Delay: %lld", delay); 00191 00192 INFO(" time: %u", time(NULL)); 00193 //Set time accordingly 00194 set_time( time(NULL) + offset ); 00195 00196 #ifdef __DEBUG__ 00197 ctTime = time(NULL); 00198 INFO("Time is now (UTC): %s", ctime(&ctTime)); 00199 #endif 00200 00201 m_sock.close(); 00202 00203 return NTP_OK; 00204 } 00205
Generated on Mon Jul 18 2022 07:51:57 by 1.7.2