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 /* 00003 Copyright (C) 2012 ARM Limited. 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a copy of 00006 this software and associated documentation files (the "Software"), to deal in 00007 the Software without restriction, including without limitation the rights to 00008 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 00009 of the Software, and to permit persons to whom the Software is furnished to do 00010 so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in all 00013 copies or substantial portions of the Software. 00014 00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00021 SOFTWARE. 00022 */ 00023 00024 #define __DEBUG__ 4 //Maximum verbosity 00025 #ifndef __MODULE__ 00026 #define __MODULE__ "NTPClient.cpp" 00027 #endif 00028 00029 #include "core/fwk.h" 00030 00031 #include "NTPClient.h" 00032 00033 #include "mbed.h" //time() and set_time() 00034 00035 #define NTP_PORT 123 00036 #define NTP_CLIENT_PORT 0 //Random port 00037 #define NTP_REQUEST_TIMEOUT 15000 00038 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900) 00039 00040 NTPClient::NTPClient() 00041 { 00042 00043 00044 } 00045 00046 int NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout) 00047 { 00048 struct sockaddr_in serverAddr; 00049 00050 std::memset(&serverAddr, 0, sizeof(struct sockaddr_in)); 00051 00052 #if __DEBUG__ >= 3 00053 time_t ctTime; 00054 ctTime = time(NULL); 00055 INFO("Time is set to (UTC): %s", ctime(&ctTime)); 00056 #endif 00057 00058 //Resolve DNS if needed 00059 if(serverAddr.sin_addr.s_addr == 0) 00060 { 00061 DBG("Resolving DNS address or populate hard-coded IP address"); 00062 struct hostent *server = socket::gethostbyname(host); 00063 if(server == NULL) 00064 { 00065 return NET_NOTFOUND; //Fail 00066 } 00067 memcpy((char*)&serverAddr.sin_addr.s_addr, (char*)server->h_addr_list[0], server->h_length); 00068 } 00069 00070 serverAddr.sin_family = AF_INET; 00071 serverAddr.sin_port = htons(port); 00072 00073 //Now create & bind socket 00074 DBG("Creating socket"); 00075 int sock = socket::socket(AF_INET, SOCK_DGRAM, 0); //UDP socket 00076 if (sock < 0) 00077 { 00078 ERR("Could not create socket"); 00079 return NET_OOM; 00080 } 00081 DBG("Handle is %d",sock); 00082 00083 //Create local address 00084 struct sockaddr_in localhostAddr; 00085 00086 std::memset(&localhostAddr, 0, sizeof(struct sockaddr_in)); 00087 00088 localhostAddr.sin_family = AF_INET; 00089 localhostAddr.sin_port = htons(NTP_CLIENT_PORT); //Random port 00090 localhostAddr.sin_addr.s_addr = htonl(INADDR_ANY); //Any local address 00091 00092 if ( socket::bind( sock, (struct sockaddr*)&localhostAddr, sizeof(localhostAddr)) < 0 ) //Listen on local port 00093 { 00094 ERR("Could not bind socket"); 00095 socket::close(sock); 00096 return NET_OOM; 00097 } 00098 00099 struct NTPPacket pkt; 00100 00101 //Now ping the server and wait for response 00102 DBG("Ping"); 00103 //Prepare NTP Packet: 00104 pkt.li = 0; //Leap Indicator : No warning 00105 pkt.vn = 4; //Version Number : 4 00106 pkt.mode = 3; //Client mode 00107 pkt.stratum = 0; //Not relevant here 00108 pkt.poll = 0; //Not significant as well 00109 pkt.precision = 0; //Neither this one is 00110 00111 pkt.rootDelay = 0; //Or this one 00112 pkt.rootDispersion = 0; //Or that one 00113 pkt.refId = 0; //... 00114 00115 pkt.refTm_s = 0; 00116 pkt.origTm_s = 0; 00117 pkt.rxTm_s = 0; 00118 pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE 00119 00120 pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0; 00121 00122 //Set timeout, non-blocking and wait using select 00123 if( socket::sendto( sock, (void*)&pkt, sizeof(NTPPacket), 0, (struct sockaddr*)&serverAddr, sizeof(serverAddr) ) < 0 ) 00124 { 00125 ERR("Could not send packet"); 00126 socket::close(sock); 00127 return NET_CONN; 00128 } 00129 00130 //Wait for socket to be readable 00131 //Creating FS set 00132 fd_set socksSet; 00133 FD_ZERO(&socksSet); 00134 FD_SET(sock, &socksSet); 00135 struct timeval t_val; 00136 t_val.tv_sec = timeout / 1000; 00137 t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000; 00138 int ret = socket::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val); 00139 if(ret <= 0 || !FD_ISSET(sock, &socksSet)) 00140 { 00141 ERR("Timeout while waiting for answer"); 00142 socket::close(sock); 00143 return NET_TIMEOUT; //Timeout 00144 } 00145 00146 //Read response 00147 DBG("Pong"); 00148 struct sockaddr_in respAddr; 00149 socklen_t respAddrLen = sizeof(respAddr); 00150 do 00151 { 00152 ret = socket::recvfrom( sock, (void*)&pkt, sizeof(NTPPacket), 0, (struct sockaddr*)&respAddr, &respAddrLen); 00153 if(ret < 0) 00154 { 00155 ERR("Could not receive packet"); 00156 socket::close(sock); 00157 return NET_CONN; 00158 } 00159 } while( respAddr.sin_addr.s_addr != serverAddr.sin_addr.s_addr); 00160 00161 if(ret < sizeof(NTPPacket)) //TODO: Accept chunks 00162 { 00163 ERR("Receive packet size does not match"); 00164 socket::close(sock); 00165 return NET_PROTOCOL; 00166 } 00167 00168 if( pkt.stratum == 0) //Kiss of death message : Not good ! 00169 { 00170 ERR("Kissed to death!"); 00171 socket::close(sock); 00172 return NTP_PORT; 00173 } 00174 00175 //Correct Endianness 00176 pkt.refTm_s = ntohl( pkt.refTm_s ); 00177 pkt.refTm_f = ntohl( pkt.refTm_f ); 00178 pkt.origTm_s = ntohl( pkt.origTm_s ); 00179 pkt.origTm_f = ntohl( pkt.origTm_f ); 00180 pkt.rxTm_s = ntohl( pkt.rxTm_s ); 00181 pkt.rxTm_f = ntohl( pkt.rxTm_f ); 00182 pkt.txTm_s = ntohl( pkt.txTm_s ); 00183 pkt.txTm_f = ntohl( pkt.txTm_f ); 00184 00185 //Compute offset, see RFC 4330 p.13 00186 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL)); 00187 int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow 00188 DBG("Sent @%ul", pkt.txTm_s); 00189 DBG("Offset: %ul", offset); 00190 //Set time accordingly 00191 set_time( time(NULL) + offset ); 00192 00193 #if __DEBUG__ >= 3 00194 ctTime = time(NULL); 00195 INFO("Time is now (UTC): %s", ctime(&ctTime)); 00196 #endif 00197 00198 socket::close(sock); 00199 00200 return OK; 00201 } 00202
Generated on Tue Jul 12 2022 22:20:40 by
1.7.2