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

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;
 }