Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 1 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 00038 #include "cmsis.h" 00039 #define htons(x) __REV16(x) 00040 #define htonl(x) __REV(x) 00041 #define ntohl(x) __REV(x) 00042 00043 00044 #include "NTPClient.h" 00045 #include "SocketConnection.h" 00046 #include "mbed.h" //time() and set_time() 00047 00048 #define NTP_PORT 123 00049 #define NTP_CLIENT_PORT 0 //Random port 00050 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900) 00051 00052 NTPClient::NTPClient() : m_sock() 00053 { 00054 00055 00056 } 00057 00058 NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout) 00059 { 00060 #ifdef __DEBUG__ 00061 time_t ctTime; 00062 ctTime = time(NULL); 00063 DBG("Time is set to (UTC): %s", ctime(&ctTime)); 00064 #endif 00065 00066 //Create & bind socket 00067 DBG("Binding socket"); 00068 m_sock.connect("0.pool.ntp.org",123,"UDP"); //Bind to a random port 00069 00070 //m_sock.set_blocking(false, timeout); //Set not blocking 00071 00072 struct NTPPacket pkt; 00073 00074 //Now ping the server and wait for response 00075 DBG("Ping"); 00076 //Prepare NTP Packet: 00077 pkt.li = 0; //Leap Indicator : No warning 00078 pkt.vn = 4; //Version Number : 4 00079 pkt.mode = 3; //Client mode 00080 pkt.stratum = 0; //Not relevant here 00081 pkt.poll = 0; //Not significant as well 00082 pkt.precision = 0; //Neither this one is 00083 00084 pkt.rootDelay = 0; //Or this one 00085 pkt.rootDispersion = 0; //Or that one 00086 pkt.refId = 0; //... 00087 00088 pkt.refTm_s = 0; 00089 pkt.origTm_s = 0; 00090 pkt.rxTm_s = 0; 00091 pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE 00092 00093 pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0; 00094 00095 //Set timeout, non-blocking and wait using select 00096 int ret = m_sock.send((char*)&pkt, sizeof(NTPPacket) ); 00097 if (ret < 0 ) { 00098 ERR("Could not send packet"); 00099 m_sock.close(); 00100 return NTP_CONN; 00101 } 00102 00103 DBG("Pong"); 00104 ret = m_sock.receive((char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name 00105 if(ret < 0) { 00106 ERR("Could not receive packet"); 00107 m_sock.close(); 00108 return NTP_CONN; 00109 } 00110 00111 if(ret < sizeof(NTPPacket)) { //TODO: Accept chunks 00112 ERR("Receive packet size does not match"); 00113 m_sock.close(); 00114 return NTP_PRTCL; 00115 } 00116 00117 if( pkt.stratum == 0) { //Kiss of death message : Not good ! 00118 ERR("Kissed to death!"); 00119 m_sock.close(); 00120 return NTP_PRTCL; 00121 } 00122 00123 //Correct Endianness 00124 pkt.refTm_s = ntohl( pkt.refTm_s ); 00125 pkt.refTm_f = ntohl( pkt.refTm_f ); 00126 pkt.origTm_s = ntohl( pkt.origTm_s ); 00127 pkt.origTm_f = ntohl( pkt.origTm_f ); 00128 pkt.rxTm_s = ntohl( pkt.rxTm_s ); 00129 pkt.rxTm_f = ntohl( pkt.rxTm_f ); 00130 pkt.txTm_s = ntohl( pkt.txTm_s ); 00131 pkt.txTm_f = ntohl( pkt.txTm_f ); 00132 00133 00134 //Compute offset, see RFC 4330 p.13 00135 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL)); 00136 int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow 00137 DBG("Sent @%ul", pkt.txTm_s); 00138 DBG("Offset: %lld", offset); 00139 //Set time accordingly 00140 set_time( time(NULL) + offset ); 00141 00142 #ifdef __DEBUG__ 00143 ctTime = time(NULL); 00144 DBG("Time is now (UTC): %s", ctime(&ctTime)); 00145 #endif 00146 00147 m_sock.close(); 00148 00149 return NTP_OK; 00150 } 00151
Generated on Sun Jul 24 2022 01:23:31 by
1.7.2