NetServices Stack source
Dependents: HelloWorld ServoInterfaceBoardExample1 4180_Lab4
NTPClient.cpp
00001 00002 /* 00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a copy 00006 of this software and associated documentation files (the "Software"), to deal 00007 in the Software without restriction, including without limitation the rights 00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00009 copies of the Software, and to permit persons to whom the Software is 00010 furnished to do so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in 00013 all 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 00021 THE SOFTWARE. 00022 */ 00023 00024 #include "NTPClient.h" 00025 00026 #include <stdio.h> 00027 00028 //#define __DEBUG 00029 #include "dbg/dbg.h" 00030 00031 #define NTP_PORT 123 00032 #define NTP_CLIENT_PORT 0//50420 //Random port 00033 #define NTP_REQUEST_TIMEOUT 15000 00034 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900) 00035 00036 #define htons( x ) ( (( x << 8 ) & 0xFF00) | (( x >> 8 ) & 0x00FF) ) 00037 #define ntohs( x ) (htons(x)) 00038 00039 #define htonl( x ) ( (( x << 24 ) & 0xFF000000) \ 00040 | (( x << 8 ) & 0x00FF0000) \ 00041 | (( x >> 8 ) & 0x0000FF00) \ 00042 | (( x >> 24 ) & 0x000000FF) ) 00043 #define ntohl( x ) (htonl(x)) 00044 00045 NTPClient::NTPClient() : NetService(false), m_state(NTP_PING), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL), 00046 m_watchdog(), m_timeout(0), m_closed(true), m_host(), m_pDnsReq(NULL), m_blockingResult(NTP_PROCESSING) 00047 { 00048 setTimeout(NTP_REQUEST_TIMEOUT); 00049 DBG("\r\nNew NTPClient %p\r\n",this); 00050 } 00051 00052 NTPClient::~NTPClient() 00053 { 00054 close(); 00055 } 00056 00057 //High level setup functions 00058 NTPResult NTPClient::setTime(const Host& host) //Blocking 00059 { 00060 doSetTime(host); 00061 return blockingProcess(); 00062 } 00063 00064 NTPResult NTPClient::setTime(const Host& host, void (*pMethod)(NTPResult)) //Non blocking 00065 { 00066 setOnResult(pMethod); 00067 doSetTime(host); 00068 return NTP_PROCESSING; 00069 } 00070 00071 #if 0 //For doc only 00072 template<class T> 00073 NTPResult NTPClient::setTime(const Host& host, T* pItem, void (T::*pMethod)(NTPResult)) //Non blocking 00074 { 00075 setOnResult(pItem, pMethod); 00076 doSetTime(host); 00077 return NTP_PROCESSING; 00078 } 00079 #endif 00080 00081 void NTPClient::doSetTime(const Host& host) 00082 { 00083 init(); 00084 resetTimeout(); 00085 m_host = host; 00086 if(!m_host.getPort()) 00087 { 00088 m_host.setPort(NTP_PORT); 00089 } 00090 if(m_host.getIp().isNull()) 00091 { 00092 //DNS query required 00093 m_pDnsReq = new DNSRequest(); 00094 DBG("\r\nNTPClient : DNSRequest %p\r\n", m_pDnsReq); 00095 m_pDnsReq->setOnReply(this, &NTPClient::onDNSReply); 00096 m_pDnsReq->resolve(&m_host); 00097 return; 00098 } 00099 open(); 00100 } 00101 00102 void NTPClient::setOnResult( void (*pMethod)(NTPResult) ) 00103 { 00104 m_pCb = pMethod; 00105 } 00106 00107 void NTPClient::close() 00108 { 00109 if(m_closed) 00110 return; 00111 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else 00112 m_watchdog.stop(); 00113 m_pUDPSocket->resetOnEvent(); 00114 m_pUDPSocket->close(); 00115 delete m_pUDPSocket; 00116 if( m_pDnsReq ) 00117 { 00118 m_pDnsReq->close(); 00119 delete m_pDnsReq; 00120 m_pDnsReq = NULL; 00121 } 00122 } 00123 00124 void NTPClient::poll() //Called by NetServices 00125 { 00126 if( (!m_closed) && (m_watchdog.read_ms() >= m_timeout) ) 00127 { 00128 onTimeout(); 00129 } 00130 } 00131 00132 void NTPClient::init() //Create and setup socket if needed 00133 { 00134 if(!m_closed) //Already opened 00135 return; 00136 m_state = NTP_PING; 00137 m_pUDPSocket = new UDPSocket; 00138 m_pUDPSocket->setOnEvent(this, &NTPClient::onUDPSocketEvent); 00139 m_closed = false; 00140 DBG("NTPClient: Init OK\n"); 00141 } 00142 00143 void NTPClient::open() 00144 { 00145 resetTimeout(); 00146 DBG("Opening connection\n"); 00147 m_state = NTP_PING; 00148 Host localhost(IpAddr(), NTP_CLIENT_PORT, "localhost"); //Any local address 00149 m_pUDPSocket->bind(localhost); 00150 set_time( 1280000000 ); //End of July 2010... just there to limit offset range 00151 process(); 00152 } 00153 00154 #define MIN(a,b) ((a)<(b))?(a):(b) 00155 void NTPClient::process() //Main state-machine 00156 { 00157 int len; 00158 Host host; 00159 00160 switch(m_state) 00161 { 00162 case NTP_PING: 00163 DBG("\r\nPing\r\n"); 00164 //Prepare NTP Packet: 00165 m_pkt.li = 0; //Leap Indicator : No warning 00166 m_pkt.vn = 4; //Version Number : 4 00167 m_pkt.mode = 3; //Client mode 00168 m_pkt.stratum = 0; //Not relevant here 00169 m_pkt.poll = 0; //Not significant as well 00170 m_pkt.precision = 0; //Neither this one is 00171 00172 m_pkt.rootDelay = 0; //Or this one 00173 m_pkt.rootDispersion = 0; //Or that one 00174 m_pkt.refId = 0; //... 00175 00176 m_pkt.refTm_s = 0; 00177 m_pkt.origTm_s = 0; 00178 m_pkt.rxTm_s = 0; 00179 m_pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE 00180 00181 m_pkt.refTm_f = m_pkt.origTm_f = m_pkt.rxTm_f = m_pkt.txTm_f = 0; 00182 00183 #ifdef __DEBUG 00184 //Hex Dump: 00185 DBG("\r\nDump Tx:\r\n"); 00186 for(int i = 0; i< sizeof(NTPPacket); i++) 00187 { 00188 DBG("%02x ", *((char*)&m_pkt + i)); 00189 } 00190 DBG("\r\n\r\n"); 00191 #endif 00192 00193 len = m_pUDPSocket->sendto( (char*)&m_pkt, sizeof(NTPPacket), &m_host ); 00194 if(len < sizeof(NTPPacket)) 00195 { onResult(NTP_PRTCL); close(); return; } 00196 00197 m_state = NTP_PONG; 00198 00199 break; 00200 00201 case NTP_PONG: 00202 DBG("\r\nPong\r\n"); 00203 while( len = m_pUDPSocket->recvfrom( (char*)&m_pkt, sizeof(NTPPacket), &host ) ) 00204 { 00205 if( len <= 0 ) 00206 break; 00207 if( !host.getIp().isEq(m_host.getIp()) ) 00208 continue; //Not our packet 00209 if( len > 0 ) 00210 break; 00211 } 00212 00213 if(len == 0) 00214 return; //Wait for the next packet 00215 00216 if(len < 0) 00217 { onResult(NTP_PRTCL); close(); return; } 00218 00219 if(len < sizeof(NTPPacket)) //TODO: Accept chunks 00220 { onResult(NTP_PRTCL); close(); return; } 00221 00222 #ifdef __DEBUG 00223 //Hex Dump: 00224 DBG("\r\nDump Rx:\r\n"); 00225 for(int i = 0; i< sizeof(NTPPacket); i++) 00226 { 00227 DBG("%02x ", *((char*)&m_pkt + i)); 00228 } 00229 DBG("\r\n\r\n"); 00230 #endif 00231 00232 if( m_pkt.stratum == 0) //Kiss of death message : Not good ! 00233 { 00234 onResult(NTP_PRTCL); close(); return; 00235 } 00236 00237 //Correct Endianness 00238 m_pkt.refTm_s = ntohl( m_pkt.refTm_s ); 00239 m_pkt.refTm_f = ntohl( m_pkt.refTm_f ); 00240 m_pkt.origTm_s = ntohl( m_pkt.origTm_s ); 00241 m_pkt.origTm_f = ntohl( m_pkt.origTm_f ); 00242 m_pkt.rxTm_s = ntohl( m_pkt.rxTm_s ); 00243 m_pkt.rxTm_f = ntohl( m_pkt.rxTm_f ); 00244 m_pkt.txTm_s = ntohl( m_pkt.txTm_s ); 00245 m_pkt.txTm_f = ntohl( m_pkt.txTm_f ); 00246 00247 //Compute offset, see RFC 4330 p.13 00248 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL)); 00249 //int32_t origTm = (int32_t) ((uint64_t) m_pkt.origTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps 00250 //int32_t rxTm = (int32_t) ((uint64_t) m_pkt.rxTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps 00251 //int32_t txTm = (int32_t) ((uint64_t) m_pkt.txTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps 00252 // int64_t offset = ( ( ( m_pkt.rxTm_s - m_pkt.origTm_s ) + ( m_pkt.txTm_s - destTm_s ) ) << 32 + ( ( m_pkt.rxTm_f - m_pkt.origTm_f ) + ( m_pkt.txTm_f - 0 ) ) ) / 2; 00253 int64_t offset = ( (int64_t)( m_pkt.rxTm_s - m_pkt.origTm_s ) + (int64_t) ( m_pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow 00254 DBG("\r\nSent @%d\r\n", m_pkt.txTm_s); 00255 DBG("\r\nOffset: %d\r\n", offset); 00256 //Set time accordingly 00257 set_time( time(NULL) + (offset /*>> 32*/) ); 00258 00259 onResult(NTP_OK); 00260 close(); 00261 00262 break; 00263 } 00264 } 00265 00266 void NTPClient::setTimeout(int ms) 00267 { 00268 m_timeout = ms; 00269 } 00270 00271 void NTPClient::resetTimeout() 00272 { 00273 m_watchdog.reset(); 00274 m_watchdog.start(); 00275 } 00276 00277 void NTPClient::onTimeout() //Connection has timed out 00278 { 00279 close(); 00280 onResult(NTP_TIMEOUT); 00281 } 00282 00283 void NTPClient::onDNSReply(DNSReply r) 00284 { 00285 if(m_closed) 00286 { 00287 DBG("\r\nWARN: Discarded\r\n"); 00288 return; 00289 } 00290 00291 if( r != DNS_FOUND ) 00292 { 00293 DBG("\r\nCould not resolve hostname.\r\n"); 00294 onResult(NTP_DNS); 00295 close(); 00296 return; 00297 } 00298 DBG("\r\nDNS resolved.\r\n"); 00299 m_pDnsReq->close(); 00300 delete m_pDnsReq; 00301 m_pDnsReq=NULL; 00302 open(); 00303 } 00304 00305 void NTPClient::onUDPSocketEvent(UDPSocketEvent e) 00306 { 00307 resetTimeout(); 00308 switch(e) 00309 { 00310 case UDPSOCKET_READABLE: //The only event for now 00311 resetTimeout(); 00312 process(); 00313 break; 00314 } 00315 } 00316 00317 void NTPClient::onResult(NTPResult r) //Must be called by impl when the request completes 00318 { 00319 if(m_pCbItem && m_pCbMeth) 00320 (m_pCbItem->*m_pCbMeth)(r); 00321 else if(m_pCb) 00322 m_pCb(r); 00323 m_blockingResult = r; //Blocking mode 00324 } 00325 00326 NTPResult NTPClient::blockingProcess() //Called in blocking mode, calls Net::poll() until return code is available 00327 { 00328 m_blockingResult = NTP_PROCESSING; 00329 do 00330 { 00331 Net::poll(); 00332 } while(m_blockingResult == NTP_PROCESSING); 00333 Net::poll(); //Necessary for cleanup 00334 return m_blockingResult; 00335 }
Generated on Tue Jul 12 2022 11:52:58 by 1.7.2