The extracted NTP client from Segundos NetServices library, for use with the [[http://mbed.org/users/hlipka/libraries/NetServicesMin|NetServicesMin]] library. The only fixed bug is the memory leak / OOM problem. Needs the [[http://mbed.org/users/hlipka/libraries/DNSResolver|DNSResolver]] library as well.
Dependents: SPIVFDclock LPC1768_AppBoard_Internet_LCD_Clock
Diff: NTPClient.cpp
- Revision:
- 1:63ded11b8fa2
- Parent:
- 0:ebea15f18f84
--- a/NTPClient.cpp Mon Jan 10 22:38:49 2011 +0000 +++ b/NTPClient.cpp Mon Jan 24 23:07:27 2011 +0000 @@ -22,6 +22,7 @@ */ #include "NTPClient.h" +#include "dnsresolve.h" #include <stdio.h> @@ -30,7 +31,7 @@ #define NTP_PORT 123 #define NTP_CLIENT_PORT 0//50420 //Random port -#define NTP_REQUEST_TIMEOUT 15000 +#define NTP_REQUEST_TIMEOUT 5000 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900) #define htons( x ) ( (( x << 8 ) & 0xFF00) | (( x >> 8 ) & 0x00FF) ) @@ -43,22 +44,20 @@ #define ntohl( x ) (htonl(x)) NTPClient::NTPClient() : - m_state(NTP_PING), -// m_watchdog(), - m_timeout(NTP_REQUEST_TIMEOUT), - m_closed(true), - m_host(), - m_pDnsReq(NULL), - m_blockingResult(NTP_PROCESSING) + _state(NTP_PING), + _timeout(NTP_REQUEST_TIMEOUT), + _closed(true), + _host(), + _blockingResult(NTP_PROCESSING) { - m_watchdog=new Timer(); + _watchdog=new Timer(); DBG("\r\nNew NTPClient %p\r\n",this); } NTPClient::~NTPClient() { close(); - delete m_watchdog; + delete _watchdog; } //High level setup functions @@ -72,57 +71,46 @@ { init(); resetTimeout(); - m_host = host; - if(!m_host.getPort()) + _host = host; + if(!_host.getPort()) { - m_host.setPort(NTP_PORT); + _host.setPort(NTP_PORT); } - if(m_host.getIp().isNull()) + if(_host.getIp().isNull()) { - //DNS query required - m_pDnsReq = new DNSRequest(); - DBG("\r\nNTPClient : DNSRequest %p\r\n", m_pDnsReq); - m_pDnsReq->setOnReply(this, &NTPClient::onDNSReply); - m_pDnsReq->resolve(&m_host); - return; + + DNSResolver *dr=new DNSResolver(); + IpAddr ad=dr->resolveName(host.getName()); + delete dr; + if (ad.isNull()) + { + onResult(NTP_DNS); + return; + } + _host.setIp(ad); } open(); } void NTPClient::close() { - if(m_closed) + if(_closed) return; - m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else - m_watchdog->stop(); - m_pUDPSocket->resetOnEvent(); - m_pUDPSocket->close(); - delete m_pUDPSocket; - if( m_pDnsReq ) - { - m_pDnsReq->close(); - delete m_pDnsReq; - m_pDnsReq = NULL; - } + _closed = true; //Prevent recursive calling or calling on an object being destructed by someone else + _watchdog->stop(); + _pUDPSocket->resetOnEvent(); + _pUDPSocket->close(); + delete _pUDPSocket; } -/* -void NTPClient::poll() //Called by NetServices -{ - if( (!m_closed) && (m_watchdog->read_ms() >= m_timeout) ) - { - onTimeout(); - } -} -*/ void NTPClient::init() //Create and setup socket if needed { - if(!m_closed) //Already opened + if(!_closed) //Already opened return; - m_state = NTP_PING; - m_pUDPSocket = new UDPSocket; - m_pUDPSocket->setOnEvent(this, &NTPClient::onUDPSocketEvent); - m_closed = false; + _state = NTP_PING; + _pUDPSocket = new UDPSocket; + _pUDPSocket->setOnEvent(this, &NTPClient::onUDPSocketEvent); + _closed = false; DBG("NTPClient: Init OK\n"); } @@ -130,9 +118,9 @@ { resetTimeout(); DBG("Opening connection\n"); - m_state = NTP_PING; + _state = NTP_PING; Host localhost(IpAddr(), NTP_CLIENT_PORT, "localhost"); //Any local address - m_pUDPSocket->bind(localhost); + _pUDPSocket->bind(localhost); if ((int)time(NULL) < 1280000000) set_time( 1280000000 ); //End of July 2010... just there to limit offset range process(); @@ -144,55 +132,54 @@ { int len; Host host; - - switch(m_state) + switch(_state) { case NTP_PING: DBG("Ping\r\n"); //Prepare NTP Packet: - m_pkt.li = 0; //Leap Indicator : No warning - m_pkt.vn = 4; //Version Number : 4 - m_pkt.mode = 3; //Client mode - m_pkt.stratum = 0; //Not relevant here - m_pkt.poll = 0; //Not significant as well - m_pkt.precision = 0; //Neither this one is + _pkt.li = 0; //Leap Indicator : No warning + _pkt.vn = 4; //Version Number : 4 + _pkt.mode = 3; //Client mode + _pkt.stratum = 0; //Not relevant here + _pkt.poll = 0; //Not significant as well + _pkt.precision = 0; //Neither this one is - m_pkt.rootDelay = 0; //Or this one - m_pkt.rootDispersion = 0; //Or that one - m_pkt.refId = 0; //... + _pkt.rootDelay = 0; //Or this one + _pkt.rootDispersion = 0; //Or that one + _pkt.refId = 0; //... - m_pkt.refTm_s = 0; - m_pkt.origTm_s = 0; - m_pkt.rxTm_s = 0; - m_pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE + _pkt.refTm_s = 0; + _pkt.origTm_s = 0; + _pkt.rxTm_s = 0; + _pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE - m_pkt.refTm_f = m_pkt.origTm_f = m_pkt.rxTm_f = m_pkt.txTm_f = 0; + _pkt.refTm_f = _pkt.origTm_f = _pkt.rxTm_f = _pkt.txTm_f = 0; #ifdef __DEBUG //Hex Dump: DBG("Dump Tx:\r\n"); for(int i = 0; i< sizeof(NTPPacket); i++) { - DBGL("%02x ", *((char*)&m_pkt + i)); + DBGL("%02x ", *((char*)&_pkt + i)); } DBGL("\r\n"); #endif - len = m_pUDPSocket->sendto( (char*)&m_pkt, sizeof(NTPPacket), &m_host ); + len = _pUDPSocket->sendto( (char*)&_pkt, sizeof(NTPPacket), &_host ); if(len < sizeof(NTPPacket)) { onResult(NTP_PRTCL); close(); return; } - m_state = NTP_PONG; + _state = NTP_PONG; break; case NTP_PONG: DBG("Pong\r\n"); - while( len = m_pUDPSocket->recvfrom( (char*)&m_pkt, sizeof(NTPPacket), &host ) ) + while( len = _pUDPSocket->recvfrom( (char*)&_pkt, sizeof(NTPPacket), &host ) ) { if( len <= 0 ) break; - if( !host.getIp().isEq(m_host.getIp()) ) + if( !host.getIp().isEq(_host.getIp()) ) continue; //Not our packet if( len > 0 ) break; @@ -212,34 +199,34 @@ DBG("Dump Rx:\r\n"); for(int i = 0; i< sizeof(NTPPacket); i++) { - DBGL("%02x ", *((char*)&m_pkt + i)); + DBGL("%02x ", *((char*)&_pkt + i)); } DBGL("\r\n"); #endif - if( m_pkt.stratum == 0) //Kiss of death message : Not good ! + if( _pkt.stratum == 0) //Kiss of death message : Not good ! { onResult(NTP_PRTCL); close(); return; } //Correct Endianness - m_pkt.refTm_s = ntohl( m_pkt.refTm_s ); - m_pkt.refTm_f = ntohl( m_pkt.refTm_f ); - m_pkt.origTm_s = ntohl( m_pkt.origTm_s ); - m_pkt.origTm_f = ntohl( m_pkt.origTm_f ); - m_pkt.rxTm_s = ntohl( m_pkt.rxTm_s ); - m_pkt.rxTm_f = ntohl( m_pkt.rxTm_f ); - m_pkt.txTm_s = ntohl( m_pkt.txTm_s ); - m_pkt.txTm_f = ntohl( m_pkt.txTm_f ); + _pkt.refTm_s = ntohl( _pkt.refTm_s ); + _pkt.refTm_f = ntohl( _pkt.refTm_f ); + _pkt.origTm_s = ntohl( _pkt.origTm_s ); + _pkt.origTm_f = ntohl( _pkt.origTm_f ); + _pkt.rxTm_s = ntohl( _pkt.rxTm_s ); + _pkt.rxTm_f = ntohl( _pkt.rxTm_f ); + _pkt.txTm_s = ntohl( _pkt.txTm_s ); + _pkt.txTm_f = ntohl( _pkt.txTm_f ); //Compute offset, see RFC 4330 p.13 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL)); - //int32_t origTm = (int32_t) ((uint64_t) m_pkt.origTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps - //int32_t rxTm = (int32_t) ((uint64_t) m_pkt.rxTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps - //int32_t txTm = (int32_t) ((uint64_t) m_pkt.txTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps - // 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; - int64_t offset = ( (int64_t)( m_pkt.rxTm_s - m_pkt.origTm_s ) + (int64_t) ( m_pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow - DBG("Sent @%d\r\n", m_pkt.txTm_s); + //int32_t origTm = (int32_t) ((uint64_t) _pkt.origTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps + //int32_t rxTm = (int32_t) ((uint64_t) _pkt.rxTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps + //int32_t txTm = (int32_t) ((uint64_t) _pkt.txTm - NTP_TIMESTAMP_DELTA); //Convert in local 32 bits timestamps + // int64_t offset = ( ( ( _pkt.rxT_s - m_pkt.origTm_s ) + ( m_pkt.txT_s - destTm_s ) ) << 32 + ( ( m_pkt.rxTm_f - m_pkt.origTm_f ) + ( m_pkt.txT_f - 0 ) ) ) / 2; + int64_t offset = ( (int64_t)( _pkt.rxTm_s - _pkt.origTm_s ) + (int64_t) ( _pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow + DBG("Sent @%d\r\n", _pkt.txTm_s); DBG("Offset: %d\r\n", offset); //Set time accordingly @@ -253,13 +240,13 @@ void NTPClient::setTimeout(int ms) { - m_timeout = ms; + _timeout = ms; } void NTPClient::resetTimeout() { - m_watchdog->reset(); - m_watchdog->start(); + _watchdog->reset(); + _watchdog->start(); } void NTPClient::onTimeout() //Connection has timed out @@ -268,36 +255,12 @@ onResult(NTP_TIMEOUT); } -void NTPClient::onDNSReply(DNSReply r) -{ - if(m_closed) - { - DBG("\r\nWARN: Discarded\r\n"); - return; - } - - if( r != DNS_FOUND ) - { - DBG("\r\nCould not resolve hostname.\r\n"); - onResult(NTP_DNS); - close(); - return; - } - DBG("\r\nDNS resolved.\r\n"); - m_pDnsReq->close(); - delete m_pDnsReq; - m_pDnsReq=NULL; - - open(); -} - void NTPClient::onUDPSocketEvent(UDPSocketEvent e) { resetTimeout(); switch(e) { case UDPSOCKET_READABLE: //The only event for now - resetTimeout(); process(); break; } @@ -305,18 +268,21 @@ void NTPClient::onResult(NTPResult r) //Must be called by impl when the request completes { - m_blockingResult = r; //Blocking mode + _blockingResult = r; //Blocking mode } NTPResult NTPClient::blockingProcess() //Called in blocking mode, calls Net::poll() until return code is available { - m_blockingResult = NTP_PROCESSING; + _blockingResult = NTP_PROCESSING; do { Net::poll(); - } while(m_blockingResult == NTP_PROCESSING); + wait_us(100); + if (_watchdog->read_ms()>_timeout) + return NTP_TIMEOUT; + } while(_blockingResult == NTP_PROCESSING); Net::poll(); //Necessary for cleanup - return m_blockingResult; + return _blockingResult; }