Modified NTP library
Embed:
(wiki syntax)
Show/hide line numbers
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 00020 //Debug is disabled by default 00021 #if 0 00022 //Enable debug 00023 #define __DEBUG__ 00024 #include <cstdio> 00025 #define DBG(x, ...) std::printf("[NTPClient : DBG]"x"\r\n", ##__VA_ARGS__); 00026 #define WARN(x, ...) std::printf("[NTPClient : WARN]"x"\r\n", ##__VA_ARGS__); 00027 #define ERR(x, ...) std::printf("[NTPClient : ERR]"x"\r\n", ##__VA_ARGS__); 00028 00029 #else 00030 //Disable debug 00031 #define DBG(x, ...) 00032 #define WARN(x, ...) 00033 #define ERR(x, ...) 00034 00035 #endif 00036 00037 #include "NTPClient.h" 00038 00039 #include "UDPSocket.h" 00040 00041 #include "mbed.h" //time() and set_time() 00042 00043 #define NTP_PORT 123 00044 #define NTP_CLIENT_PORT 0 //Random port 00045 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900) 00046 00047 //uint32_t LastNtpResult = 0; 00048 00049 NTPClient::NTPClient() : m_sock() 00050 { 00051 00052 } 00053 00054 00055 00056 NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout) 00057 { 00058 #ifdef __DEBUG__ 00059 time_t ctTime; 00060 ctTime = time(NULL); 00061 DBG("Time is set to (UTC): %s", ctime(&ctTime)); 00062 #endif 00063 00064 //Create & bind socket 00065 DBG("Binding socket"); 00066 m_sock.bind(NTP_PORT); //Bind to a random port 00067 00068 m_sock.set_blocking(false, timeout); //Set not blocking 00069 00070 struct NTPPacket pkt; 00071 00072 //Now ping the server and wait for response 00073 DBG("Ping"); 00074 //Prepare NTP Packet: 00075 pkt.li = 0; //Leap Indicator : No warning 00076 pkt.vn = 4; //Version Number : 4 00077 pkt.mode = 3; //Client mode 00078 pkt.stratum = 0; //Not relevant here 00079 pkt.poll = 0; //Not significant as well 00080 pkt.precision = 0; //Neither this one is 00081 00082 pkt.rootDelay = 0; //Or this one 00083 pkt.rootDispersion = 0; //Or that one 00084 pkt.refId = 0; //... 00085 00086 pkt.refTm_s = 0; 00087 pkt.origTm_s = 0; 00088 pkt.rxTm_s = 0; 00089 pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE 00090 00091 pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0; 00092 00093 Endpoint outEndpoint; 00094 00095 if( outEndpoint.set_address(host, port) < 0) 00096 { 00097 m_sock.close(); 00098 return NTP_DNS; 00099 } 00100 00101 //Set timeout, non-blocking and wait using select 00102 int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) ); 00103 if (ret < 0 ) 00104 { 00105 ERR("Could not send packet"); 00106 m_sock.close(); 00107 return NTP_CONN; 00108 } 00109 00110 //Read response 00111 Endpoint inEndpoint; 00112 00113 DBG("Pong"); 00114 do 00115 { 00116 ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name 00117 if(ret < 0) 00118 { 00119 ERR("Could not receive packet"); 00120 m_sock.close(); 00121 return NTP_CONN; 00122 } 00123 } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 ); 00124 00125 if(ret < sizeof(NTPPacket)) //TODO: Accept chunks 00126 { 00127 ERR("Receive packet size does not match"); 00128 m_sock.close(); 00129 return NTP_PRTCL; 00130 } 00131 00132 if( pkt.stratum == 0) //Kiss of death message : Not good ! 00133 { 00134 ERR("Kissed to death!"); 00135 m_sock.close(); 00136 return NTP_PRTCL; 00137 } 00138 00139 //Correct Endianness 00140 pkt.refTm_s = ntohl( pkt.refTm_s ); 00141 pkt.refTm_f = ntohl( pkt.refTm_f ); 00142 pkt.origTm_s = ntohl( pkt.origTm_s ); 00143 pkt.origTm_f = ntohl( pkt.origTm_f ); 00144 pkt.rxTm_s = ntohl( pkt.rxTm_s ); 00145 pkt.rxTm_f = ntohl( pkt.rxTm_f ); 00146 pkt.txTm_s = ntohl( pkt.txTm_s ); 00147 pkt.txTm_f = ntohl( pkt.txTm_f ); 00148 00149 //Compute offset, see RFC 4330 p.13 00150 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL)); 00151 int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow 00152 NTPLastResult = offset; 00153 DBG("Sent @%ul", pkt.txTm_s); 00154 DBG("Offset: %lld", offset); 00155 //Set time accordingly 00156 set_time( time(NULL) + offset ); 00157 00158 #ifdef __DEBUG__ 00159 ctTime = time(NULL); 00160 DBG("Time is now (UTC): %s", ctime(&ctTime)); 00161 #endif 00162 00163 m_sock.close(); 00164 00165 return NTP_OK; 00166 } 00167
Generated on Thu Jul 14 2022 10:31:04 by 1.7.2