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.
Fork of mbed-os 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 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 NTPClient::NTPClient() : m_sock() 00048 { 00049 00050 00051 } 00052 00053 NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout) 00054 { 00055 #ifdef __DEBUG__ 00056 time_t ctTime; 00057 ctTime = time(NULL); 00058 DBG("Time is set to (UTC): %s", ctime(&ctTime)); 00059 #endif 00060 00061 //Create & bind socket 00062 DBG("Binding socket"); 00063 m_sock.bind(0); //Bind to a random port 00064 00065 m_sock.set_blocking(false, timeout); //Set not blocking 00066 00067 struct NTPPacket pkt; 00068 00069 //Now ping the server and wait for response 00070 DBG("Ping"); 00071 //Prepare NTP Packet: 00072 pkt.li = 0; //Leap Indicator : No warning 00073 pkt.vn = 4; //Version Number : 4 00074 pkt.mode = 3; //Client mode 00075 pkt.stratum = 0; //Not relevant here 00076 pkt.poll = 0; //Not significant as well 00077 pkt.precision = 0; //Neither this one is 00078 00079 pkt.rootDelay = 0; //Or this one 00080 pkt.rootDispersion = 0; //Or that one 00081 pkt.refId = 0; //... 00082 00083 pkt.refTm_s = 0; 00084 pkt.origTm_s = 0; 00085 pkt.rxTm_s = 0; 00086 pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE 00087 00088 pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0; 00089 00090 Endpoint outEndpoint; 00091 00092 if( outEndpoint.set_address(host, port) < 0) 00093 { 00094 m_sock.close(); 00095 return NTP_DNS; 00096 } 00097 00098 //Set timeout, non-blocking and wait using select 00099 int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) ); 00100 if (ret < 0 ) 00101 { 00102 ERR("Could not send packet"); 00103 m_sock.close(); 00104 return NTP_CONN; 00105 } 00106 00107 //Read response 00108 Endpoint inEndpoint; 00109 00110 DBG("Pong"); 00111 do 00112 { 00113 ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name 00114 if(ret < 0) 00115 { 00116 ERR("Could not receive packet"); 00117 m_sock.close(); 00118 return NTP_CONN; 00119 } 00120 } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 ); 00121 00122 if(ret < sizeof(NTPPacket)) //TODO: Accept chunks 00123 { 00124 ERR("Receive packet size does not match"); 00125 m_sock.close(); 00126 return NTP_PRTCL; 00127 } 00128 00129 if( pkt.stratum == 0) //Kiss of death message : Not good ! 00130 { 00131 ERR("Kissed to death!"); 00132 m_sock.close(); 00133 return NTP_PRTCL; 00134 } 00135 00136 //Correct Endianness 00137 pkt.refTm_s = ntohl( pkt.refTm_s ); 00138 pkt.refTm_f = ntohl( pkt.refTm_f ); 00139 pkt.origTm_s = ntohl( pkt.origTm_s ); 00140 pkt.origTm_f = ntohl( pkt.origTm_f ); 00141 pkt.rxTm_s = ntohl( pkt.rxTm_s ); 00142 pkt.rxTm_f = ntohl( pkt.rxTm_f ); 00143 pkt.txTm_s = ntohl( pkt.txTm_s ); 00144 pkt.txTm_f = ntohl( pkt.txTm_f ); 00145 00146 //Compute offset, see RFC 4330 p.13 00147 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL)); 00148 int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow 00149 DBG("Sent @%ul", pkt.txTm_s); 00150 DBG("Offset: %lld", offset); 00151 //Set time accordingly 00152 set_time( time(NULL) + offset ); 00153 00154 #ifdef __DEBUG__ 00155 ctTime = time(NULL); 00156 DBG("Time is now (UTC): %s", ctime(&ctTime)); 00157 #endif 00158 00159 m_sock.close(); 00160 00161 return NTP_OK; 00162 } 00163
Generated on Tue Jul 12 2022 13:16:02 by
1.7.2
