NetServices Stack source

Dependents:   HelloWorld ServoInterfaceBoardExample1 4180_Lab4

Files at this revision

API Documentation at this revision

Comitter:
donatien
Date:
Fri Jun 18 09:22:54 2010 +0000
Parent:
1:abb442332fa8
Child:
3:95e0bc00a1bb
Commit message:

Changed in this revision

api/DNSRequest.cpp Show annotated file Show diff for this revision Revisions of this file
api/TCPSocket.cpp Show annotated file Show diff for this revision Revisions of this file
api/UDPSocket.cpp Show annotated file Show diff for this revision Revisions of this file
dbg/dbg.cpp Show annotated file Show diff for this revision Revisions of this file
dbg/dbg.h Show annotated file Show diff for this revision Revisions of this file
drv/gprs/GPRSModem.cpp Show annotated file Show diff for this revision Revisions of this file
drv/serial/usb/usbserialif.cpp Show annotated file Show diff for this revision Revisions of this file
if/eth/EthernetNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/eth/EthernetNetIf.h Show annotated file Show diff for this revision Revisions of this file
if/lwip/LwipNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
if/lwip/LwipNetIf.h Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetDnsRequest.cpp Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetDnsRequest.h Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetTcpSocket.cpp Show annotated file Show diff for this revision Revisions of this file
if/lwip/lwipNetUdpSocket.cpp Show annotated file Show diff for this revision Revisions of this file
if/net/net.cpp Show annotated file Show diff for this revision Revisions of this file
if/net/netservice.cpp Show annotated file Show diff for this revision Revisions of this file
if/net/netudpsocket.cpp Show annotated file Show diff for this revision Revisions of this file
lwip/core/dns.c Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/def.h Show annotated file Show diff for this revision Revisions of this file
lwip/include/lwip/dns.h Show annotated file Show diff for this revision Revisions of this file
lwip/lwipopts.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPRequestDispatcher.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPRequestDispatcher.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPRequestHandler.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPServer.cpp Show annotated file Show diff for this revision Revisions of this file
services/http/server/HTTPServer.h Show annotated file Show diff for this revision Revisions of this file
services/http/server/impl/FSHandler.cpp Show annotated file Show diff for this revision Revisions of this file
services/ntp/NTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
services/ntp/NTPClient.h Show annotated file Show diff for this revision Revisions of this file
--- a/api/DNSRequest.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/api/DNSRequest.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -75,7 +75,7 @@
   m_pCb = pMethod;
 }
 
-#ifdef __LINKER_BUG_SOLVED__
+#if 0 //For doc only
 template<class T> 
 void DNSRequest::setOnReply( T* pItem, void (T::*pMethod)(DNSReply) )
 {
--- a/api/TCPSocket.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/api/TCPSocket.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -23,12 +23,12 @@
 
 #include "TCPSocket.h"
 
-TCPSocket::TCPSocket() : m_pNetTcpSocket(NULL)
+TCPSocket::TCPSocket() : m_pNetTcpSocket(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL)
 {
 
 }
 
-TCPSocket::TCPSocket(NetTcpSocket* pNetTcpSocket) : m_pNetTcpSocket(pNetTcpSocket)
+TCPSocket::TCPSocket(NetTcpSocket* pNetTcpSocket) : m_pNetTcpSocket(pNetTcpSocket), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL)
 {
   m_pNetTcpSocket->setOnEvent(this, &TCPSocket::onNetTcpSocketEvent);
 }
--- a/api/UDPSocket.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/api/UDPSocket.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -23,7 +23,7 @@
 
 #include "UDPSocket.h"
 
-UDPSocket::UDPSocket() : m_pNetUdpSocket(NULL)
+UDPSocket::UDPSocket() : m_pNetUdpSocket(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL)
 {
 
 }
--- a/dbg/dbg.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/dbg/dbg.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -54,6 +54,14 @@
   //fclose(m_fp);
 }
 
+void DebugStream::breakPoint(const char* file, int line)
+{
+  printf("\r\nBREAK in %s at line %d\r\n", file, line);
+  fflush(stdout);
+  getchar();
+  fflush(stdin);
+}
+
 /*
 int snprintf(char *str, int size, const char *format, ...)
 {
--- a/dbg/dbg.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/dbg/dbg.h	Fri Jun 18 09:22:54 2010 +0000
@@ -39,21 +39,26 @@
 public:
 static void debug(const char* format, ...);
 static void release();
+static void breakPoint(const char* file, int line);
 private:
 
 };
 
 #undef DBG
 #undef DBG_END
+#undef BREAK
 #define DBG DebugStream::debug
 #define DBG_END DebugStream::release
+#define BREAK() DebugStream::breakPoint(__FILE__, __LINE__)
 #endif
 
 #else
 #undef DBG
 #undef DBG_END
+#undef BREAK
 #define DBG(...)
 #define DBG_END()
+#define BREAK()
 #endif
 
 #ifdef __LWIP_DEBUG
--- a/drv/gprs/GPRSModem.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/drv/gprs/GPRSModem.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -24,7 +24,7 @@
 #include "GPRSModem.h"
 #include "mbed.h"
 
-#define __DEBUG
+//#define __DEBUG
 #include "dbg/dbg.h"
 
 #define WAIT_BTW_NETW_POLLS 3.
--- a/drv/serial/usb/usbserialif.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/drv/serial/usb/usbserialif.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -35,9 +35,15 @@
 UsbEndpoint* pEpIn;
 UsbEndpoint* pEpOut;
 
-USB_INT08U ser_int_found;
+#define DONGLE_STATE_UNKNOWN 0
+#define DONGLE_STATE_CDFS    1
+#define DONGLE_STATE_SERIAL  2
+
+USB_INT08U dongleState;
+
 USB_INT32S SerialInit()
 {
+  dongleState = DONGLE_STATE_UNKNOWN;
   Host_Init();               // Initialize the  host controller
   USB_INT32S rc = Host_EnumDev();       // Enumerate the device connected
   if (rc != OK)
@@ -50,7 +56,7 @@
 
 bool SerialHasToSwitch()
 {
-  return (ser_int_found == 3);
+  return (dongleState == DONGLE_STATE_CDFS);
 }
 
 uint16_t m_vid;
@@ -61,7 +67,7 @@
   bool scsi = false;
   //Size 31
   const unsigned char magicHuawei[] = { 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0,    0, 0, 0, 0,    0, 0,    0x11, 0x6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-  const unsigned char magicVoda[] = {   0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, 0x01, 0, 0, 0, 0x80, 0, 0x06, 0x01, 0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  const unsigned char magicVoda[]   = { 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, 0x01, 0, 0, 0, 0x80, 0, 0x06, 0x01, 0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   char* magic;
   USB_INT32S rc;
   if((m_vid == 0x12d1) && (m_pid == 0x1446))
@@ -86,20 +92,15 @@
    return -1;
   }
   
-  
   if(scsi)
   {
-    //rc = Host_ProcessTD(EDBulkOut, TD_OUT, (volatile USB_INT08U*)magic, 31);
     rc = pEpOut->transfer((volatile USB_INT08U*)magic, 31);
     while(rc == PROCESSING)
     {
-     // __WFI();
       rc = pEpOut->status();
-    }
-  
+    }  
   }
-  
-  
+    
   delete pEpOut;
   pEpOut = NULL;
   return rc;
@@ -125,25 +126,25 @@
       m_pid == 0x1446 )
   {
     PRINT_Log("\r\nHuawei device found in CDFS mode\r\n");
-    ser_int_found=3;
+    dongleState = DONGLE_STATE_CDFS;
   }
   else if(  m_vid == 0x12d1 &&//Huawei : Change
             m_pid == 0x1001 )
   {
     PRINT_Log("\r\nHuawei device found in Serial mode\r\n");
-    ser_int_found=1;
+    dongleState = DONGLE_STATE_SERIAL;
   }
   else if(  m_vid  == 0x0af0 &&//Voda?Qualcomm? : Change
             m_pid == 0x7501 )
   {
     PRINT_Log("\r\nVodafone K3760 found, checking mode...\r\n");
-    ser_int_found=3;
+    dongleState = DONGLE_STATE_UNKNOWN;
   }
   else if(  m_vid  == 0x12d1 &&//Voda?Qualcomm? : Change
             m_pid == 0x1003 )
   {
     PRINT_Log("\r\nHuawei device found, checking mode...\r\n");
-    ser_int_found=3;
+    dongleState = DONGLE_STATE_UNKNOWN;
   }
   else
   {
@@ -176,8 +177,13 @@
                  if (desc_ptr[5] == 0xFF &&             
                      desc_ptr[6] == 0xFF &&     
                      desc_ptr[7] == 0xFF ) {       
-                     //if(ser_int_found==1)
-                     ser_int_found=2;
+                   dongleState = DONGLE_STATE_SERIAL;
+                 }
+                 else 
+                 if (desc_ptr[5] == 0xFF &&             
+                     desc_ptr[6] == 0xFF &&     
+                     desc_ptr[7] == 0xFF ) {       
+                   dongleState = DONGLE_STATE_CDFS;
                  }
                  desc_ptr    += desc_ptr[0];                      /* Move to next descriptor start      */
                  break;
@@ -186,51 +192,13 @@
                  PRINT_Log("\r\nEp %02x of size %d.\r\n", desc_ptr[2], (ReadLE16U(&desc_ptr[4]) ));
                  if ( SerialHasToSwitch() )
                  {
-                   if( pEpOut == NULL /*desc_ptr[2] == 1*/) //EP 1
+                   if( (dongleState == DONGLE_STATE_CDFS) && (pEpOut == NULL) /*desc_ptr[2] == 1*/) //EP 1
                    {
-                   #if 0
-                         EDBulkOut->Control = 1                             |      /* USB address           */
-                                              ((desc_ptr[2] & 0x7F) << 7)   |      /* Endpoint address      */
-                                              (1 << 11)                     |      /* direction             */
-                                              (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size           */
-                   #endif
                      pEpOut = new UsbEndpoint((desc_ptr[2] & 0x7F), false, ReadLE16U(&desc_ptr[4]));
                    }
-                   desc_ptr += desc_ptr[0];                     /* Move to next descriptor start      */
+                                      /* Move to next descriptor start      */
                  }
-                 else if ((desc_ptr[3] & 0x03) == 0x02) {                  /* If it is Bulk endpoint             */
-                     if (desc_ptr[2] & 0x80) {                        /* If it is In endpoint               */
-                       if(epIn == 0)
-                       {
-                         PRINT_Log("\r\nEp %02x is in ep.\r\n", desc_ptr[2]);
-                       #if 0
-                         EDBulkIn->Control =  1                             |      /* USB address           */
-                                              ((desc_ptr[2] & 0x7F) << 7)   |      /* Endpoint address      */
-                                              (2 << 11)                     |      /* direction             */
-                                              (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size           */
-                       #endif
-                       // pEpIn = new UsbEndpoint((desc_ptr[2] & 0x7F), true, ReadLE16U(&desc_ptr[4]));
-                       }
-                       epIn++;
-                       desc_ptr += desc_ptr[0];                     /* Move to next descriptor start      */
-                     } else {                                         /* If it is Out endpoint              */
-                       if(epOut == 0)
-                       {
-                         PRINT_Log("\r\nEp %02x is out ep.\r\n", desc_ptr[2]);
-                       #if 0
-                         EDBulkOut->Control = 1                             |      /* USB address           */
-                                              ((desc_ptr[2] & 0x7F) << 7)   |      /* Endpoint address      */
-                                              (1 << 11)                     |      /* direction             */
-                                              (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size           */
-                       #endif
-                        // pEpOut = new UsbEndpoint((desc_ptr[2] & 0x7F), false, ReadLE16U(&desc_ptr[4]));
-                       }
-                       epOut++;
-                       desc_ptr += desc_ptr[0];                     /* Move to next descriptor start      */
-                     }
-                 } else {                                             /* If it is not bulk end point        */
-                     desc_ptr += desc_ptr[0];                         /* Move to next descriptor start      */
-                 }
+                 desc_ptr += desc_ptr[0];  
                  break;
 
             default:                                 /* If the descriptor is neither interface nor endpoint */
@@ -238,8 +206,8 @@
                  break;
         }
     }
-    if (ser_int_found==2) {
-        PRINT_Log("Virtual Serial Port device %04x:%04x connected, vid=%d, pid=%d, E220=%d\n", m_vid, m_pid, ( m_vid  == 0x12d1 ), ( m_pid == 0x1003 ), (( m_vid  == 0x12d1 ) && ( m_pid == 0x1003 )));
+    if (dongleState == DONGLE_STATE_SERIAL) {
+        PRINT_Log("Virtual Serial Port device %04x:%04x connected, vid=%d, pid=%d\n", m_vid, m_pid);
       if(m_vid==0x0af0) //Voda
       {
         pEpOut = new UsbEndpoint((0x0a & 0x7F), false, 64);
@@ -254,21 +222,6 @@
         pEpIn = new UsbEndpoint((0x82 & 0x7F), true, 64);
         PRINT_Log("Huawei E220\r\n");
       }
-      /*else
-      {
-        if(( m_vid  == 0x12d1 ))
-           PRINT_Log("VID OK\r\n");
-        else
-           PRINT_Log("VID NOK\r\n");
-        if(( m_pid  == 0x1003 ))
-           PRINT_Log("VID OK\r\n");
-        else
-           PRINT_Log("VID NOK\r\n");
-        PRINT_Log("\r\n....\r\n\r\n");
-        error("\r\n\r\n");
-      }*/
-      //} 
-      #if 1
       else /*if (  m_vid  == 0x12d1 &&
             m_pid == 0x1001 )*/
       {
@@ -276,12 +229,11 @@
         pEpIn = new UsbEndpoint((0x82 & 0x7F), true, 64); 
         PRINT_Log("Huawei E1550\r\n");
       }   
-      #endif
         
         PRINT_Log("Virtual Serial Port device %04x:%04x connected\n", m_vid, m_pid);
         return (OK);
     }
-    else if (ser_int_found==3) {
+    else if (dongleState == DONGLE_STATE_CDFS) {
         PRINT_Log("CDFS dongle connected, reset\n");
         return (OK);
     } else {
--- a/if/eth/EthernetNetIf.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/eth/EthernetNetIf.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -34,7 +34,7 @@
 #include "netCfg.h"
 #if NET_ETH
 
-EthernetNetIf::EthernetNetIf() : LwipNetIf(), m_ethArpTicker(), m_dhcpCoarseTicker(), m_dhcpFineTicker(), m_pNetIf(NULL),
+EthernetNetIf::EthernetNetIf() : LwipNetIf(), m_ethArpTimer(), m_dhcpCoarseTimer(), m_dhcpFineTimer(), m_pNetIf(NULL),
 m_netmask(255,255,255,255), m_gateway(), m_hostname(NULL)
 {
   m_hostname = NULL;
@@ -42,7 +42,7 @@
   m_useDhcp = true;
 }
 
-EthernetNetIf::EthernetNetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns) : LwipNetIf(), m_ethArpTicker(), m_dhcpCoarseTicker(), m_dhcpFineTicker(), m_pNetIf(NULL), m_hostname(NULL) //W/o DHCP
+EthernetNetIf::EthernetNetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns) : LwipNetIf(), m_ethArpTimer(), m_dhcpCoarseTimer(), m_dhcpFineTimer(), m_pNetIf(NULL), m_hostname(NULL) //W/o DHCP
 {
   m_hostname = NULL;
   m_netmask = netmask;
@@ -67,11 +67,14 @@
 EthernetErr EthernetNetIf::setup(int timeout_ms /*= 15000*/)
 {
   LwipNetIf::init();
-  m_ethArpTicker.attach_us(&etharp_tmr,  ARP_TMR_INTERVAL  * 1000); // = 5s in etharp.h
+  //m_ethArpTicker.attach_us(&etharp_tmr,  ARP_TMR_INTERVAL  * 1000); // = 5s in etharp.h
+  m_ethArpTimer.start();
   if(m_useDhcp)
   {
-    m_dhcpCoarseTicker.attach(&dhcp_coarse_tmr, DHCP_COARSE_TIMER_SECS); // = 60s in dhcp.h
-    m_dhcpFineTicker.attach_us(&dhcp_fine_tmr, DHCP_FINE_TIMER_MSECS * 1000); // = 500ms in dhcp.h
+    //m_dhcpCoarseTicker.attach(&dhcp_coarse_tmr, DHCP_COARSE_TIMER_SECS); // = 60s in dhcp.h
+    //m_dhcpFineTicker.attach_us(&dhcp_fine_tmr, DHCP_FINE_TIMER_MSECS * 1000); // = 500ms in dhcp.h
+    m_dhcpCoarseTimer.start();
+    m_dhcpFineTimer.start();
   }
   m_pNetIf->hwaddr_len = ETHARP_HWADDR_LEN; //6
   eth_address((char *)m_pNetIf->hwaddr);
@@ -79,8 +82,7 @@
   DBG("\r\nHW Addr is : %02x:%02x:%02x:%02x:%02x:%02x.\r\n", 
   m_pNetIf->hwaddr[0], m_pNetIf->hwaddr[1], m_pNetIf->hwaddr[2],
   m_pNetIf->hwaddr[3], m_pNetIf->hwaddr[4], m_pNetIf->hwaddr[5]);
-  DBG("\r\nIn Setup.\r\n");
-  
+
   m_pNetIf = netif_add(m_pNetIf, &(m_ip.getStruct()), &(m_netmask.getStruct()), &(m_gateway.getStruct()), NULL, eth_init, ip_input);//ethernet_input);// ip_input);
   //m_pNetIf->hostname = "mbedDG";//(char *)m_hostname; //Not used for now
   netif_set_default(m_pNetIf);
@@ -101,6 +103,19 @@
   timeout.start();
   while( !netif_is_up(m_pNetIf) ) //Wait until device is up
   {
+    if(m_useDhcp)
+    {
+      if(m_dhcpFineTimer.read_ms()>=DHCP_FINE_TIMER_MSECS)
+      {
+        m_dhcpFineTimer.reset();
+        dhcp_fine_tmr();
+      }
+      if(m_dhcpCoarseTimer.read()>=DHCP_COARSE_TIMER_SECS)
+      {
+        m_dhcpCoarseTimer.reset();
+        dhcp_coarse_tmr();
+      }
+    }
     poll();
     if( timeout.read_ms() > timeout_ms )
     {
@@ -123,6 +138,11 @@
 
 void EthernetNetIf::poll()
 {
+  if(m_ethArpTimer.read_ms()>=ARP_TMR_INTERVAL)
+  {
+    m_ethArpTimer.reset();
+    etharp_tmr();
+  }
   LwipNetIf::poll();
   eth_poll();
 }
--- a/if/eth/EthernetNetIf.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/eth/EthernetNetIf.h	Fri Jun 18 09:22:54 2010 +0000
@@ -26,7 +26,6 @@
 
 struct netif;
 
-//class Ticker;
 #include "mbed.h"
 
 #include "if/net/net.h"
@@ -51,9 +50,9 @@
   virtual void poll();
 
 private:
-  Ticker m_ethArpTicker;
-  Ticker m_dhcpCoarseTicker;
-  Ticker m_dhcpFineTicker;
+  Timer m_ethArpTimer;
+  Timer m_dhcpCoarseTimer;
+  Timer m_dhcpFineTimer;
     
   bool m_useDhcp;
 
--- a/if/lwip/LwipNetIf.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/lwip/LwipNetIf.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -31,16 +31,15 @@
 
 //See doc/rawapi.txt for details
 
-LwipNetIf::LwipNetIf() : NetIf(), m_tcpTicker(), m_dnsTicker(), m_init(false)
+LwipNetIf::LwipNetIf() : NetIf(), m_tcpTimer(), m_init(false)
 {  
-
+  m_tcpTimer.start();
 }
 
 
 LwipNetIf::~LwipNetIf()
 {
-  m_tcpTicker.detach();
-  m_dnsTicker.detach();
+
 }
 
 void LwipNetIf::init()
@@ -51,8 +50,9 @@
   lwip_init(); //init lwip, see init.c for details
   
   //Setup Clocks
-  m_tcpTicker.attach_us( tcp_tmr, TCP_TMR_INTERVAL * 1000 ); //TCP_TMR_INTERVAL = 250 ms in tcp_impl.h
-  m_dnsTicker.attach_us( dns_tmr, DNS_TMR_INTERVAL * 1000 ); //DNS_TMR_INTERVAL = 1000 ms in dns.h
+  m_tcpTimer.start();
+  //m_tcpTicker.attach_us( tcp_tmr, TCP_TMR_INTERVAL * 1000 ); //TCP_TMR_INTERVAL = 250 ms in tcp_impl.h
+  //m_dnsTicker.attach_us( dns_tmr, DNS_TMR_INTERVAL * 1000 ); //DNS_TMR_INTERVAL = 1000 ms in dns.h
 }
 
 NetTcpSocket* LwipNetIf::tcpSocket()  //Create a new tcp socket
@@ -77,6 +77,11 @@
 
 void LwipNetIf::poll()
 {
+  if(m_init && m_tcpTimer.read_ms()>=TCP_TMR_INTERVAL)
+  {
+    m_tcpTimer.reset();
+    tcp_tmr(); //Poll LwIP
+  }
   //Do some stuff...
 }
 
--- a/if/lwip/LwipNetIf.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/lwip/LwipNetIf.h	Fri Jun 18 09:22:54 2010 +0000
@@ -49,8 +49,7 @@
   virtual void poll();
 
 private:
-  Ticker m_tcpTicker;
-  Ticker m_dnsTicker;
+  Timer m_tcpTimer;
   
   bool m_init;
 
--- a/if/lwip/lwipNetDnsRequest.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/lwip/lwipNetDnsRequest.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -31,12 +31,12 @@
 //#define __DEBUG
 #include "dbg/dbg.h"
 
-LwipNetDnsRequest::LwipNetDnsRequest(const char* hostname) : NetDnsRequest(hostname), m_state(LWIPNETDNS_START), m_cbFired(false)
+LwipNetDnsRequest::LwipNetDnsRequest(const char* hostname) : NetDnsRequest(hostname), m_state(LWIPNETDNS_START), m_cbFired(false), m_closing(false)
 {
   DBG("New LwipNetDnsRequest %p\n", this);
 }
 
-LwipNetDnsRequest::LwipNetDnsRequest(Host* pHost) : NetDnsRequest(pHost), m_state(LWIPNETDNS_START), m_cbFired(false)
+LwipNetDnsRequest::LwipNetDnsRequest(Host* pHost) : NetDnsRequest(pHost), m_state(LWIPNETDNS_START), m_cbFired(false), m_closing(false)
 {
   DBG("New LwipNetDnsRequest %p\n", this);
 }
@@ -56,6 +56,7 @@
 void LwipNetDnsRequest::poll()
 {
   err_t  err;
+  dnsTick();
   switch(m_state)
   {
   case LWIPNETDNS_START: //First req, let's call dns_gethostbyname
@@ -106,16 +107,36 @@
     }  
     break; 
   }
-//  return m_state;
+  if(m_closing && (m_state!=LWIPNETDNS_PROCESSING)) //Check wether the closure has been reqd
+  {
+    DBG("LwipNetDnsRequest: Closing in poll()\n");
+    NetDnsRequest::close();
+  }
+}
+
+void LwipNetDnsRequest::close()
+{
+  DBG("LwipNetDnsRequest: Close req\n");
+  if(m_state!=LWIPNETDNS_PROCESSING)
+  {
+    DBG("LwipNetDnsRequest: Closing in close()\n");
+    NetDnsRequest::close();
+  }
+  else //Cannot close rightaway, waiting for callback from underlying layer
+  {
+    m_closing = true;
+  }
 }
 
 void LwipNetDnsRequest::foundCb(const char *name, ip_addr_t *ipaddr)
 {
   if( ipaddr == NULL )
   {
+    DBG("LwipNetDnsRequest: Callback: Name not found\n");
     m_state = LWIPNETDNS_NOTFOUND;
     return;
   }
+  DBG("LwipNetDnsRequest: Callback: Resolved\n");
   m_ip = IpAddr(ipaddr);
   m_state = LWIPNETDNS_OK;
 }
@@ -123,9 +144,26 @@
 
 void LwipNetDnsRequest::sFoundCb(const char *name, ip_addr_t *ipaddr, void *arg)
 {
+  DBG("LwipNetDnsRequest: Static callback\n");
   LwipNetDnsRequest* pMe = (LwipNetDnsRequest*) arg;
   return pMe->foundCb( name, ipaddr );
 }
 
+void LwipNetDnsRequest::dnsTick()
+{
+  static Timer* pTmr = NULL;
+  if(!pTmr)
+  {
+    pTmr = new Timer;
+    pTmr->start();
+  }
+  if(pTmr->read_ms() >= DNS_TMR_INTERVAL)
+  {
+    pTmr->reset();
+    dns_tmr();
+    DBG("DNS Tick\n");
+  }
+}
+
 #endif
 
--- a/if/lwip/lwipNetDnsRequest.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/lwip/lwipNetDnsRequest.h	Fri Jun 18 09:22:54 2010 +0000
@@ -39,6 +39,8 @@
 
   //Execute request & return OK if found, NOTFOUND or ERROR on error, or PROCESSING if the request has not completed yet
   virtual void poll();
+  
+  virtual void close();
 
 protected:
   void foundCb(const char *name, ip_addr_t *ipaddr);
@@ -58,6 +60,10 @@
   
   //Static callbacks : Transforms into a C++ callback
   static void sFoundCb(const char *name, ip_addr_t *ipaddr, void *arg);
+  
+  static void dnsTick();
+  
+  bool m_closing;
 };
 
 #endif
--- a/if/lwip/lwipNetTcpSocket.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/lwip/lwipNetTcpSocket.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -30,7 +30,7 @@
 #include "netCfg.h"
 #if NET_LWIP_STACK
 
-LwipNetTcpSocket::LwipNetTcpSocket(tcp_pcb* pPcb /*= NULL*/) : m_pPcb(pPcb), m_lpInNetTcpSocket(), //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
+LwipNetTcpSocket::LwipNetTcpSocket(tcp_pcb* pPcb /*= NULL*/) : NetTcpSocket(), m_pPcb(pPcb), m_lpInNetTcpSocket(), //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
 m_pReadPbuf(NULL)
 {
   DBG("\r\nNew NetTcpSocket %p\r\n", (void*)this);
@@ -163,8 +163,8 @@
   return NETTCPSOCKET_OK;
 }
 
-#define MAX(a,b) ((a>b)?a:b)
-#define MIN(a,b) ((a<b)?a:b)
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
 
 int /*if < 0 : NetTcpSocketErr*/ LwipNetTcpSocket::send(const char* buf, int len)
 {
--- a/if/lwip/lwipNetUdpSocket.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/lwip/lwipNetUdpSocket.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -30,16 +30,16 @@
 #include "netCfg.h"
 #if NET_LWIP_STACK
 
-LwipNetUdpSocket::LwipNetUdpSocket(udp_pcb* pPcb /*= NULL*/) : m_pPcb(pPcb), m_lInPkt() //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
+LwipNetUdpSocket::LwipNetUdpSocket(udp_pcb* pPcb /*= NULL*/) : NetUdpSocket(), m_pPcb(pPcb), m_lInPkt() //Passes a pcb if already created (by an accept req for instance), in that case transfers ownership
 {
-  DBG("\r\nNew NetUdpSocket %p\r\n", (void*)this);
+  DBG("\r\nNew LwipNetUdpSocket %p (pPCb=%p)\r\n", (void*)this, (void*) pPcb);
   if(!m_pPcb)
     m_pPcb = udp_new();
- /* if(m_pPcb)
+  if(m_pPcb)
   {
     //Setup callback
-   // udp_recv( (udp_pcb*) m_pPcb, LwipNetUdpSocket::sRecvCb, (void*) this );
-  }*/
+    udp_recv( (udp_pcb*) m_pPcb, LwipNetUdpSocket::sRecvCb, (void*) this );
+  }
 }
 
 LwipNetUdpSocket::~LwipNetUdpSocket()
@@ -51,11 +51,11 @@
 {
   if(!m_pPcb)
     return NETUDPSOCKET_MEM; //NetUdpSocket was not properly initialised, should destroy it & retry
-    
+
   err_t err = udp_bind( (udp_pcb*) m_pPcb, IP_ADDR_ANY, me.getPort()); //IP_ADDR_ANY : Bind the connection to all local addresses
   if(err)
     return NETUDPSOCKET_INUSE;
-    
+
   //Setup callback
   udp_recv( (udp_pcb*) m_pPcb, LwipNetUdpSocket::sRecvCb, (void*) this );
     
@@ -69,12 +69,18 @@
 {
   if( !m_pPcb ) //Pcb doesn't exist (anymore)
     return NETUDPSOCKET_MEM;
-  pbuf* p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
+  pbuf* p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_POOL);
   if( !p )
     return NETUDPSOCKET_MEM;
-  memcpy (p->payload, (void*)buf, len);  
-  //udp_connect( (udp_pcb*) m_pPcb, &(pHost->getIp().getStruct()), pHost->getPort() );
-  //err_t err = udp_send( (udp_pcb*) m_pPcb, p);
+  char* pBuf = (char*) buf;
+  pbuf* q = p; 
+  do
+  {
+    memcpy (q->payload, (void*)pBuf, q->len);  
+    pBuf += q->len;
+    q = q->next;
+  } while(q != NULL);
+
   err_t err = udp_sendto( (udp_pcb*) m_pPcb, p, &(pHost->getIp().getStruct()), pHost->getPort() );
   pbuf_free( p );
   if(err)
@@ -151,7 +157,7 @@
 
 NetUdpSocketErr LwipNetUdpSocket::close()
 {
-  //DBG("\r\nLwipNetUdpSocket::close() : Closing...\r\n");
+  DBG("\r\nLwipNetUdpSocket::close() : Closing...\r\n");
 
   if(m_closed)
     return NETUDPSOCKET_OK; //Already being closed
@@ -160,11 +166,14 @@
   if( !m_pPcb ) //Pcb doesn't exist (anymore)
     return NETUDPSOCKET_MEM;
     
+  DBG("\r\nLwipNetUdpSocket::close() : Cleanup...\r\n");
+    
   //Cleanup incoming data
   cleanUp();
  
+  DBG("\r\nLwipNetUdpSocket::close() : removing m_pPcb...\r\n");
   udp_remove( (udp_pcb*) m_pPcb);
-  
+    
   m_pPcb = NULL;
   return NETUDPSOCKET_OK;
 }
@@ -186,7 +195,7 @@
     if( ip_addr_cmp((&((*it).addr)), addr) && ((*it).port == port) )
     {
       //Let's tail this packet to the previous one
-      pbuf_cat((pbuf*)(*it).pBuf, p);
+      pbuf_cat((pbuf*)((*it).pBuf), p);
       //No need to queue an event in that case since the read buf has not been processed yet
       return;
     }
@@ -204,13 +213,18 @@
 
 void LwipNetUdpSocket::cleanUp() //Flush input buffer
 {
+  //Ensure that further error won't be followed to this inst (which can be destroyed)
+  if( m_pPcb )
+  {
+    udp_recv( (udp_pcb*) m_pPcb, NULL, (void*) NULL );
+  }
+  
   list<InPacket>::iterator it;
   for ( it = m_lInPkt.begin(); it != m_lInPkt.end(); it++ )
   {
     //Free buf
-    pbuf_free((pbuf*)(*it).pBuf);
+    pbuf_free((pbuf*)((*it).pBuf));
   } 
-  recvfrom(NULL, 0, NULL);
   m_lInPkt.clear();
 }
 
--- a/if/net/net.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/net/net.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -39,9 +39,12 @@
 
 void Net::poll()
 {
+  //DBG("\r\nNet : Services polling\r\n");
 
   //Poll Services
-  NetService::servicesPoll();     
+  NetService::servicesPoll();  
+  
+  //DBG("\r\nNet : Interfaces polling\r\n");   
       
   //Poll Interfaces
   list<NetIf*>::iterator pIfIt;
@@ -51,6 +54,8 @@
     (*pIfIt)->poll();
   }
   
+  //DBG("\r\nNet : Sockets polling\r\n");
+  
   //Poll Tcp Sockets
   list<NetTcpSocket*>::iterator pNetTcpSocketIt;
 
--- a/if/net/netservice.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/net/netservice.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -54,19 +54,21 @@
 void NetService::servicesPoll() //Poll all registered services & destroy closed ones
 {
   list<NetService*>::iterator it;
-  
+  DBG("\r\nServices polling over %d services\r\n", lpServices().size());
   for( it = lpServices().begin(); it != lpServices().end();  )
   {
     if( (*it)->m_owned && (*it)->m_closed  )
     {
-      DBG("\r\nService %p is flagged as closed\r\n", &(*it));
+      DBG("\r\nService %p is flagged as closed\r\n", (*it));
       (*it)->m_removed = true;
       delete (*it);
       it = lpServices().erase(it);
     }
     else
     {
+      //DBG("Service %p polling start\n", (*it));
       (*it)->poll();
+      //DBG("Service %p polling end\n", (*it));
       it++;
     }
   }
@@ -75,7 +77,7 @@
 
 void NetService::close()
 {
-  DBG("\r\nService %p to be closed\r\n", this);
+  DBG("\r\nService %p to be closed (owned = %d)\r\n", this, m_owned);
   m_closed = true;
 }
 
--- a/if/net/netudpsocket.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/if/net/netudpsocket.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -38,7 +38,7 @@
   
    
 //Callbacks
-#ifdef __LINKER_BUG_SOLVED__
+#if 0 //Just for info
 void NetUdpSocket::setOnEvent()
 {
   m_pCbItem = (CDummy*) pItem;
--- a/lwip/core/dns.c	Mon Jun 14 10:33:54 2010 +0000
+++ b/lwip/core/dns.c	Fri Jun 18 09:22:54 2010 +0000
@@ -1,968 +1,970 @@
-/**
- * @file
- * DNS - host name to IP address resolver.
- *
- */
-
-/**
-
- * This file implements a DNS host name to IP address resolver.
-
- * Port to lwIP from uIP
- * by Jim Pettinato April 2007
-
- * uIP version Copyright (c) 2002-2003, Adam Dunkels.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * DNS.C
- *
- * The lwIP DNS resolver functions are used to lookup a host name and
- * map it to a numerical IP address. It maintains a list of resolved
- * hostnames that can be queried with the dns_lookup() function.
- * New hostnames can be resolved using the dns_query() function.
- *
- * The lwIP version of the resolver also adds a non-blocking version of
- * gethostbyname() that will work with a raw API application. This function
- * checks for an IP address string first and converts it if it is valid.
- * gethostbyname() then does a dns_lookup() to see if the name is 
- * already in the table. If so, the IP is returned. If not, a query is 
- * issued and the function returns with a ERR_INPROGRESS status. The app
- * using the dns client must then go into a waiting state.
- *
- * Once a hostname has been resolved (or found to be non-existent),
- * the resolver code calls a specified callback function (which 
- * must be implemented by the module that uses the resolver).
- */
-
-/*-----------------------------------------------------------------------------
- * RFC 1035 - Domain names - implementation and specification
- * RFC 2181 - Clarifications to the DNS Specification
- *----------------------------------------------------------------------------*/
-
-/** @todo: define good default values (rfc compliance) */
-/** @todo: improve answer parsing, more checkings... */
-/** @todo: check RFC1035 - 7.3. Processing responses */
-
-/*-----------------------------------------------------------------------------
- * Includes
- *----------------------------------------------------------------------------*/
-
-#include "lwip/opt.h"
-
-#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/udp.h"
-#include "lwip/mem.h"
-#include "lwip/dns.h"
-
-#include <string.h>
-
-/** DNS server IP address */
-#ifndef DNS_SERVER_ADDRESS
-#define DNS_SERVER_ADDRESS(ipaddr)        (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
-#endif
-
-/** DNS server port address */
-#ifndef DNS_SERVER_PORT
-#define DNS_SERVER_PORT           53
-#endif
-
-/** DNS maximum number of retries when asking for a name, before "timeout". */
-#ifndef DNS_MAX_RETRIES
-#define DNS_MAX_RETRIES           4
-#endif
-
-/** DNS resource record max. TTL (one week as default) */
-#ifndef DNS_MAX_TTL
-#define DNS_MAX_TTL               604800
-#endif
-
-/* DNS protocol flags */
-#define DNS_FLAG1_RESPONSE        0x80
-#define DNS_FLAG1_OPCODE_STATUS   0x10
-#define DNS_FLAG1_OPCODE_INVERSE  0x08
-#define DNS_FLAG1_OPCODE_STANDARD 0x00
-#define DNS_FLAG1_AUTHORATIVE     0x04
-#define DNS_FLAG1_TRUNC           0x02
-#define DNS_FLAG1_RD              0x01
-#define DNS_FLAG2_RA              0x80
-#define DNS_FLAG2_ERR_MASK        0x0f
-#define DNS_FLAG2_ERR_NONE        0x00
-#define DNS_FLAG2_ERR_NAME        0x03
-
-/* DNS protocol states */
-#define DNS_STATE_UNUSED          0
-#define DNS_STATE_NEW             1
-#define DNS_STATE_ASKING          2
-#define DNS_STATE_DONE            3
-
-#ifdef PACK_STRUCT_USE_INCLUDES
-#  include "arch/bpstruct.h"
-#endif
-PACK_STRUCT_BEGIN
-/** DNS message header */
-struct dns_hdr {
-  PACK_STRUCT_FIELD(u16_t id);
-  PACK_STRUCT_FIELD(u8_t flags1);
-  PACK_STRUCT_FIELD(u8_t flags2);
-  PACK_STRUCT_FIELD(u16_t numquestions);
-  PACK_STRUCT_FIELD(u16_t numanswers);
-  PACK_STRUCT_FIELD(u16_t numauthrr);
-  PACK_STRUCT_FIELD(u16_t numextrarr);
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#ifdef PACK_STRUCT_USE_INCLUDES
-#  include "arch/epstruct.h"
-#endif
-#define SIZEOF_DNS_HDR 12
-
-/** DNS query message structure.
-    No packing needed: only used locally on the stack. */
-PACK_STRUCT_BEGIN
-struct dns_query {
-  /* DNS query record starts with either a domain name or a pointer
-     to a name already present somewhere in the packet. */
-  u16_t type;
-  u16_t cls;
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#define SIZEOF_DNS_QUERY 4
-
-/** DNS answer message structure.
-    No packing needed: only used locally on the stack. */
-PACK_STRUCT_BEGIN
-struct dns_answer {
-  /* DNS answer record starts with either a domain name or a pointer
-     to a name already present somewhere in the packet. */
-  u16_t type;
-  u16_t cls;
-  u32_t ttl;
-  u16_t len;
-} PACK_STRUCT_STRUCT;
-PACK_STRUCT_END
-#define SIZEOF_DNS_ANSWER 10
-
-/** DNS table entry */
-struct dns_table_entry {
-  u8_t  state;
-  u8_t  numdns;
-  u8_t  tmr;
-  u8_t  retries;
-  u8_t  seqno;
-  u8_t  err;
-  u32_t ttl;
-  char name[DNS_MAX_NAME_LENGTH];
-  ip_addr_t ipaddr;
-  /* pointer to callback on DNS query done */
-  dns_found_callback found;
-  void *arg;
-};
-
-#if DNS_LOCAL_HOSTLIST
-/** struct used for local host-list */
-struct local_hostlist_entry {
-  /** static hostname */
-  const char *name;
-  /** static host address in network byteorder */
-  ip_addr_t addr;
-  struct local_hostlist_entry *next;
-};
-
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-/** Local host-list. For hostnames in this list, no
- *  external name resolution is performed */
-static struct local_hostlist_entry *local_hostlist_dynamic;
-#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-
-/** Defining this allows the local_hostlist_static to be placed in a different
- * linker section (e.g. FLASH) */
-#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
-#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
-#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
-/** Defining this allows the local_hostlist_static to be placed in a different
- * linker section (e.g. FLASH) */
-#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
-#define DNS_LOCAL_HOSTLIST_STORAGE_POST
-#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
-DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
-  DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
-
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-
-static void dns_init_local();
-#endif /* DNS_LOCAL_HOSTLIST */
-
-
-/* forward declarations */
-static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
-static void dns_check_entries(void);
-
-/*-----------------------------------------------------------------------------
- * Globales
- *----------------------------------------------------------------------------*/
-
-/* DNS variables */
-static struct udp_pcb        *dns_pcb;
-static u8_t                   dns_seqno;
-static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
-static ip_addr_t              dns_servers[DNS_MAX_SERVERS];
-/** Contiguous buffer for processing responses */
-static u8_t                   dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
-static u8_t*                  dns_payload;
-
-/**
- * Initialize the resolver: set up the UDP pcb and configure the default server
- * (DNS_SERVER_ADDRESS).
- */
-void
-dns_init()
-{
-  ip_addr_t dnsserver;
-
-  dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
-  
-  /* initialize default DNS server address */
-  DNS_SERVER_ADDRESS(&dnsserver);
-
-  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
-
-  /* if dns client not yet initialized... */
-  if (dns_pcb == NULL) {
-    dns_pcb = udp_new();
-
-    if (dns_pcb != NULL) {
-      /* initialize DNS table not needed (initialized to zero since it is a
-       * global variable) */
-      LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
-        DNS_STATE_UNUSED == 0);
-
-      /* initialize DNS client */
-      udp_bind(dns_pcb, IP_ADDR_ANY, 0);
-      udp_recv(dns_pcb, dns_recv, NULL);
-
-      /* initialize default DNS primary server */
-      dns_setserver(0, &dnsserver);
-    }
-  }
-#if DNS_LOCAL_HOSTLIST
-  dns_init_local();
-#endif
-}
-
-/**
- * Initialize one of the DNS servers.
- *
- * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
- * @param dnsserver IP address of the DNS server to set
- */
-void
-dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
-{
-  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
-      (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
-    dns_servers[numdns] = (*dnsserver);
-  }
-}
-
-/**
- * Obtain one of the currently configured DNS server.
- *
- * @param numdns the index of the DNS server
- * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
- *         server has not been configured.
- */
-ip_addr_t
-dns_getserver(u8_t numdns)
-{
-  if (numdns < DNS_MAX_SERVERS) {
-    return dns_servers[numdns];
-  } else {
-    return *IP_ADDR_ANY;
-  }
-}
-
-/**
- * The DNS resolver client timer - handle retries and timeouts and should
- * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
- */
-void
-dns_tmr(void)
-{
-  if (dns_pcb != NULL) {
-    LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
-    dns_check_entries();
-  }
-}
-
-#if DNS_LOCAL_HOSTLIST
-static void
-dns_init_local()
-{
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
-  int i;
-  struct local_hostlist_entry *entry;
-  /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
-  struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
-  size_t namelen;
-  for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
-    struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
-    LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
-    namelen = strlen(init_entry->name);
-    entry = mem_malloc((mem_size_t)(sizeof(struct local_hostlist_entry) + namelen + 1));
-    LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
-    if (entry != NULL) {
-      entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
-      MEMCPY((char*)entry->name, init_entry->name, namelen);
-      ((char*)entry->name)[namelen] = 0;
-      entry->addr = init_entry->addr;
-      entry->next = local_hostlist_dynamic;
-      local_hostlist_dynamic = entry;
-    }
-  }
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
-}
-
-/**
- * Scans the local host-list for a hostname.
- *
- * @param hostname Hostname to look for in the local host-list
- * @return The first IP address for the hostname in the local host-list or
- *         IPADDR_NONE if not found.
- */
-static u32_t
-dns_lookup_local(const char *hostname)
-{
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-  struct local_hostlist_entry *entry = local_hostlist_dynamic;
-  while(entry != NULL) {
-    if(strcmp(entry->name, hostname) == 0) {
-      return ip4_addr_get_u32(&entry->addr);
-    }
-    entry = entry->next;
-  }
-#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-  int i;
-  for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
-    if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
-      return ip4_addr_get_u32(&local_hostlist_static[i].addr);
-    }
-  }
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-  return IPADDR_NONE;
-}
-
-#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-/** Remove all entries from the local host-list for a specific hostname
- * and/or IP addess
- *
- * @param hostname hostname for which entries shall be removed from the local
- *                 host-list
- * @param addr address for which entries shall be removed from the local host-list
- * @return the number of removed entries
- */
-int
-dns_local_removehost(const char *hostname, const ip_addr_t *addr)
-{
-  int removed = 0;
-  struct local_hostlist_entry *entry = local_hostlist_dynamic;
-  struct local_hostlist_entry *last_entry = NULL;
-  while (entry != NULL) {
-    if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
-        ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
-      struct local_hostlist_entry *free_entry;
-      if (last_entry != NULL) {
-        last_entry->next = entry->next;
-      } else {
-        local_hostlist_dynamic = entry->next;
-      }
-      free_entry = entry;
-      entry = entry->next;
-      mem_free(free_entry);
-      removed++;
-    } else {
-      last_entry = entry;
-      entry = entry->next;
-    }
-  }
-  return removed;
-}
-
-/**
- * Add a hostname/IP address pair to the local host-list.
- * Duplicates are not checked.
- *
- * @param hostname hostname of the new entry
- * @param addr IP address of the new entry
- * @return ERR_OK if succeeded or ERR_MEM on memory error
- */
-err_t
-dns_local_addhost(const char *hostname, const ip_addr_t *addr)
-{
-  struct local_hostlist_entry *entry;
-  size_t namelen;
-  LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
-  namelen = strlen(hostname);
-  entry = mem_malloc((mem_size_t)(sizeof(struct local_hostlist_entry) + namelen + 1));
-  if (entry == NULL) {
-    return ERR_MEM;
-  }
-  entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
-  MEMCPY((char*)entry->name, hostname, namelen);
-  ((char*)entry->name)[namelen] = 0;
-  ip_addr_copy(entry->addr, *addr);
-  entry->next = local_hostlist_dynamic;
-  local_hostlist_dynamic = entry;
-  return ERR_OK;
-}
-#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
-#endif /* DNS_LOCAL_HOSTLIST */
-
-/**
- * Look up a hostname in the array of known hostnames.
- *
- * @note This function only looks in the internal array of known
- * hostnames, it does not send out a query for the hostname if none
- * was found. The function dns_enqueue() can be used to send a query
- * for a hostname.
- *
- * @param name the hostname to look up
- * @return the hostname's IP address, as u32_t (instead of ip_addr_t to
- *         better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
- *         was not found in the cached dns_table.
- */
-static u32_t
-dns_lookup(const char *name)
-{
-  u8_t i;
-#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
-  u32_t addr;
-#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
-#if DNS_LOCAL_HOSTLIST
-  if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
-    return addr;
-  }
-#endif /* DNS_LOCAL_HOSTLIST */
-#ifdef DNS_LOOKUP_LOCAL_EXTERN
-  if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
-    return addr;
-  }
-#endif /* DNS_LOOKUP_LOCAL_EXTERN */
-
-  /* Walk through name list, return entry if found. If not, return NULL. */
-  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
-    if ((dns_table[i].state == DNS_STATE_DONE) &&
-        (strcmp(name, dns_table[i].name) == 0)) {
-      LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
-      ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
-      LWIP_DEBUGF(DNS_DEBUG, ("\n"));
-      return ip4_addr_get_u32(&dns_table[i].ipaddr);
-    }
-  }
-
-  return IPADDR_NONE;
-}
-
-#if DNS_DOES_NAME_CHECK
-/**
- * Compare the "dotted" name "query" with the encoded name "response"
- * to make sure an answer from the DNS server matches the current dns_table
- * entry (otherwise, answers might arrive late for hostname not on the list
- * any more).
- *
- * @param query hostname (not encoded) from the dns_table
- * @param response encoded hostname in the DNS response
- * @return 0: names equal; 1: names differ
- */
-static u8_t
-dns_compare_name(unsigned char *query, unsigned char *response)
-{
-  unsigned char n;
-
-  do {
-    n = *response++;
-    /** @see RFC 1035 - 4.1.4. Message compression */
-    if ((n & 0xc0) == 0xc0) {
-      /* Compressed name */
-      break;
-    } else {
-      /* Not compressed name */
-      while (n > 0) {
-        if ((*query) != (*response)) {
-          return 1;
-        }
-        ++response;
-        ++query;
-        --n;
-      };
-      ++query;
-    }
-  } while (*response != 0);
-
-  return 0;
-}
-#endif /* DNS_DOES_NAME_CHECK */
-
-/**
- * Walk through a compact encoded DNS name and return the end of the name.
- *
- * @param query encoded DNS name in the DNS server response
- * @return end of the name
- */
-static unsigned char *
-dns_parse_name(unsigned char *query)
-{
-  unsigned char n;
-
-  do {
-    n = *query++;
-    /** @see RFC 1035 - 4.1.4. Message compression */
-    if ((n & 0xc0) == 0xc0) {
-      /* Compressed name */
-      break;
-    } else {
-      /* Not compressed name */
-      while (n > 0) {
-        ++query;
-        --n;
-      };
-    }
-  } while (*query != 0);
-
-  return query + 1;
-}
-
-/**
- * Send a DNS query packet.
- *
- * @param numdns index of the DNS server in the dns_servers table
- * @param name hostname to query
- * @param id index of the hostname in dns_table, used as transaction ID in the
- *        DNS query packet
- * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
- */
-static err_t
-dns_send(u8_t numdns, const char* name, u8_t id)
-{
-  err_t err;
-  struct dns_hdr *hdr;
-  struct dns_query qry;
-  struct pbuf *p;
-  char *query, *nptr;
-  const char *pHostname;
-  u8_t n;
-
-  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
-              (u16_t)(numdns), name));
-  LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
-  LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
-
-  /* if here, we have either a new query or a retry on a previous query to process */
-  p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
-                 SIZEOF_DNS_QUERY, PBUF_RAM);
-  if (p != NULL) {
-    LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
-    /* fill dns header */
-    hdr = (struct dns_hdr*)p->payload;
-    memset(hdr, 0, SIZEOF_DNS_HDR);
-    hdr->id = htons(id);
-    hdr->flags1 = DNS_FLAG1_RD;
-    hdr->numquestions = htons(1);
-    query = (char*)hdr + SIZEOF_DNS_HDR;
-    pHostname = name;
-    --pHostname;
-
-    /* convert hostname into suitable query format. */
-    do {
-      ++pHostname;
-      nptr = query;
-      ++query;
-      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
-        *query = *pHostname;
-        ++query;
-        ++n;
-      }
-      *nptr = n;
-    } while(*pHostname != 0);
-    *query++='\0';
-
-    /* fill dns query */
-    qry.type = htons(DNS_RRTYPE_A);
-    qry.cls = htons(DNS_RRCLASS_IN);
-    SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
-
-    /* resize pbuf to the exact dns query */
-    pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
-
-    /* connect to the server for faster receiving */
-    udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
-    /* send dns packet */
-    err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
-
-    /* free pbuf */
-    pbuf_free(p);
-  } else {
-    err = ERR_MEM;
-  }
-
-  return err;
-}
-
-/**
- * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
- * Check an entry in the dns_table:
- * - send out query for new entries
- * - retry old pending entries on timeout (also with different servers)
- * - remove completed entries from the table if their TTL has expired
- *
- * @param i index of the dns_table entry to check
- */
-static void
-dns_check_entry(u8_t i)
-{
-  struct dns_table_entry *pEntry = &dns_table[i];
-
-  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
-
-  switch(pEntry->state) {
-
-    case DNS_STATE_NEW: {
-      /* initialize new entry */
-      pEntry->state   = DNS_STATE_ASKING;
-      pEntry->numdns  = 0;
-      pEntry->tmr     = 1;
-      pEntry->retries = 0;
-      
-      /* send DNS packet for this entry */
-      dns_send(pEntry->numdns, pEntry->name, i);
-      break;
-    }
-
-    case DNS_STATE_ASKING: {
-      if (--pEntry->tmr == 0) {
-        if (++pEntry->retries == DNS_MAX_RETRIES) {
-          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
-            /* change of server */
-            pEntry->numdns++;
-            pEntry->tmr     = 1;
-            pEntry->retries = 0;
-            break;
-          } else {
-            LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
-            /* call specified callback function if provided */
-            if (pEntry->found)
-              (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
-            /* flush this entry */
-            pEntry->state   = DNS_STATE_UNUSED;
-            pEntry->found   = NULL;
-            break;
-          }
-        }
-
-        /* wait longer for the next retry */
-        pEntry->tmr = pEntry->retries;
-
-        /* send DNS packet for this entry */
-        dns_send(pEntry->numdns, pEntry->name, i);
-      }
-      break;
-    }
-
-    case DNS_STATE_DONE: {
-      /* if the time to live is nul */
-      if (--pEntry->ttl == 0) {
-        LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
-        /* flush this entry */
-        pEntry->state = DNS_STATE_UNUSED;
-        pEntry->found = NULL;
-      }
-      break;
-    }
-    case DNS_STATE_UNUSED:
-      /* nothing to do */
-      break;
-    default:
-      LWIP_ASSERT("unknown dns_table entry state:", 0);
-      break;
-  }
-}
-
-/**
- * Call dns_check_entry for each entry in dns_table - check all entries.
- */
-static void
-dns_check_entries(void)
-{
-  u8_t i;
-
-  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
-    dns_check_entry(i);
-  }
-}
-
-/**
- * Receive input function for DNS response packets arriving for the dns UDP pcb.
- *
- * @params see udp.h
- */
-static void
-dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
-{
-  u16_t i;
-  char *pHostname;
-  struct dns_hdr *hdr;
-  struct dns_answer ans;
-  struct dns_table_entry *pEntry;
-  u16_t nquestions, nanswers;
-
-  LWIP_UNUSED_ARG(arg);
-  LWIP_UNUSED_ARG(pcb);
-  LWIP_UNUSED_ARG(addr);
-  LWIP_UNUSED_ARG(port);
-
-  /* is the dns message too big ? */
-  if (p->tot_len > DNS_MSG_SIZE) {
-    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
-    /* free pbuf and return */
-    goto memerr;
-  }
-
-  /* is the dns message big enough ? */
-  if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
-    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
-    /* free pbuf and return */
-    goto memerr;
-  }
-
-  /* copy dns payload inside static buffer for processing */ 
-  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
-    /* The ID in the DNS header should be our entry into the name table. */
-    hdr = (struct dns_hdr*)dns_payload;
-    i = htons(hdr->id);
-    if (i < DNS_TABLE_SIZE) {
-      pEntry = &dns_table[i];
-      if(pEntry->state == DNS_STATE_ASKING) {
-        /* This entry is now completed. */
-        pEntry->state = DNS_STATE_DONE;
-        pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;
-
-        /* We only care about the question(s) and the answers. The authrr
-           and the extrarr are simply discarded. */
-        nquestions = htons(hdr->numquestions);
-        nanswers   = htons(hdr->numanswers);
-
-        /* Check for error. If so, call callback to inform. */
-        if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
-          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
-          /* call callback to indicate error, clean up memory and return */
-          goto responseerr;
-        }
-
-#if DNS_DOES_NAME_CHECK
-        /* Check if the name in the "question" part match with the name in the entry. */
-        if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
-          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
-          /* call callback to indicate error, clean up memory and return */
-          goto responseerr;
-        }
-#endif /* DNS_DOES_NAME_CHECK */
-
-        /* Skip the name in the "question" part */
-        pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
-
-        while (nanswers > 0) {
-          /* skip answer resource record's host name */
-          pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
-
-          /* Check for IP address type and Internet class. Others are discarded. */
-          SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
-          if((ans.type == htons(DNS_RRTYPE_A)) && (ans.cls == htons(DNS_RRCLASS_IN)) &&
-             (ans.len == htons(sizeof(ip_addr_t))) ) {
-            /* read the answer resource record's TTL, and maximize it if needed */
-            pEntry->ttl = ntohl(ans.ttl);
-            if (pEntry->ttl > DNS_MAX_TTL) {
-              pEntry->ttl = DNS_MAX_TTL;
-            }
-            /* read the IP address after answer resource record's header */
-            SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
-            LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
-            ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
-            LWIP_DEBUGF(DNS_DEBUG, ("\n"));
-            /* call specified callback function if provided */
-            if (pEntry->found) {
-              (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
-            }
-            /* deallocate memory and return */
-            goto memerr;
-          } else {
-            pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
-          }
-          --nanswers;
-        }
-        LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
-        /* call callback to indicate error, clean up memory and return */
-        goto responseerr;
-      }
-    }
-  }
-
-  /* deallocate memory and return */
-  goto memerr;
-
-responseerr:
-  /* ERROR: call specified callback function with NULL as name to indicate an error */
-  if (pEntry->found) {
-    (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
-  }
-  /* flush this entry */
-  pEntry->state = DNS_STATE_UNUSED;
-  pEntry->found = NULL;
-
-memerr:
-  /* free pbuf */
-  pbuf_free(p);
-  return;
-}
-
-/**
- * Queues a new hostname to resolve and sends out a DNS query for that hostname
- *
- * @param name the hostname that is to be queried
- * @param found a callback founction to be called on success, failure or timeout
- * @param callback_arg argument to pass to the callback function
- * @return @return a err_t return code.
- */
-static err_t
-dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
-{
-  u8_t i;
-  u8_t lseq, lseqi;
-  struct dns_table_entry *pEntry = NULL;
-  size_t namelen;
-
-  /* search an unused entry, or the oldest one */
-  lseq = lseqi = 0;
-  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
-    pEntry = &dns_table[i];
-    /* is it an unused entry ? */
-    if (pEntry->state == DNS_STATE_UNUSED)
-      break;
-
-    /* check if this is the oldest completed entry */
-    if (pEntry->state == DNS_STATE_DONE) {
-      if ((dns_seqno - pEntry->seqno) > lseq) {
-        lseq = dns_seqno - pEntry->seqno;
-        lseqi = i;
-      }
-    }
-  }
-
-  /* if we don't have found an unused entry, use the oldest completed one */
-  if (i == DNS_TABLE_SIZE) {
-    if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
-      /* no entry can't be used now, table is full */
-      LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
-      return ERR_MEM;
-    } else {
-      /* use the oldest completed one */
-      i = lseqi;
-      pEntry = &dns_table[i];
-    }
-  }
-
-  /* use this entry */
-  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
-
-  /* fill the entry */
-  pEntry->state = DNS_STATE_NEW;
-  pEntry->seqno = dns_seqno++;
-  pEntry->found = found;
-  pEntry->arg   = callback_arg;
-  namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
-  MEMCPY(pEntry->name, name, namelen);
-  pEntry->name[namelen] = 0;
-
-  /* force to send query without waiting timer */
-  dns_check_entry(i);
-
-  /* dns query is enqueued */
-  return ERR_INPROGRESS;
-}
-
-/**
- * Resolve a hostname (string) into an IP address.
- * NON-BLOCKING callback version for use with raw API!!!
- *
- * Returns immediately with one of err_t return codes:
- * - ERR_OK if hostname is a valid IP address string or the host
- *   name is already in the local names table.
- * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
- *   for resolution if no errors are present.
- *
- * @param hostname the hostname that is to be queried
- * @param addr pointer to a ip_addr_t where to store the address if it is already
- *             cached in the dns_table (only valid if ERR_OK is returned!)
- * @param found a callback function to be called on success, failure or timeout (only if
- *              ERR_INPROGRESS is returned!)
- * @param callback_arg argument to pass to the callback function
- * @return a err_t return code.
- */
-err_t
-dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
-                  void *callback_arg)
-{
-  u32_t ipaddr;
-  /* not initialized or no valid server yet, or invalid addr pointer
-   * or invalid hostname or invalid hostname length */
-  if ((dns_pcb == NULL) || (addr == NULL) ||
-      (!hostname) || (!hostname[0]) ||
-      (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
-    return ERR_VAL;
-  }
-
-#if LWIP_HAVE_LOOPIF
-  if (strcmp(hostname, "localhost")==0) {
-    ip_addr_set_loopback(addr);
-    return ERR_OK;
-  }
-#endif /* LWIP_HAVE_LOOPIF */
-
-  /* host name already in octet notation? set ip addr and return ERR_OK */
-  ipaddr = ipaddr_addr(hostname);
-  if (ipaddr == IPADDR_NONE) {
-    /* already have this address cached? */
-    ipaddr = dns_lookup(hostname);
-  }
-  if (ipaddr != IPADDR_NONE) {
-    ip4_addr_set_u32(addr, ipaddr);
-    return ERR_OK;
-  }
-
-  /* queue query with specified callback */
-  return dns_enqueue(hostname, found, callback_arg);
-}
-#endif /* LWIP_DNS */
+/**
+ * @file
+ * DNS - host name to IP address resolver.
+ *
+ */
+
+/**
+
+ * This file implements a DNS host name to IP address resolver.
+
+ * Port to lwIP from uIP
+ * by Jim Pettinato April 2007
+
+ * uIP version Copyright (c) 2002-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * DNS.C
+ *
+ * The lwIP DNS resolver functions are used to lookup a host name and
+ * map it to a numerical IP address. It maintains a list of resolved
+ * hostnames that can be queried with the dns_lookup() function.
+ * New hostnames can be resolved using the dns_query() function.
+ *
+ * The lwIP version of the resolver also adds a non-blocking version of
+ * gethostbyname() that will work with a raw API application. This function
+ * checks for an IP address string first and converts it if it is valid.
+ * gethostbyname() then does a dns_lookup() to see if the name is 
+ * already in the table. If so, the IP is returned. If not, a query is 
+ * issued and the function returns with a ERR_INPROGRESS status. The app
+ * using the dns client must then go into a waiting state.
+ *
+ * Once a hostname has been resolved (or found to be non-existent),
+ * the resolver code calls a specified callback function (which 
+ * must be implemented by the module that uses the resolver).
+ */
+
+/*-----------------------------------------------------------------------------
+ * RFC 1035 - Domain names - implementation and specification
+ * RFC 2181 - Clarifications to the DNS Specification
+ *----------------------------------------------------------------------------*/
+
+/** @todo: define good default values (rfc compliance) */
+/** @todo: improve answer parsing, more checkings... */
+/** @todo: check RFC1035 - 7.3. Processing responses */
+
+/*-----------------------------------------------------------------------------
+ * Includes
+ *----------------------------------------------------------------------------*/
+
+#include "lwip/opt.h"
+
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/udp.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/dns.h"
+#include "lwip/debug.h"
+
+#include <string.h>
+
+/** DNS server IP address */
+#ifndef DNS_SERVER_ADDRESS
+#define DNS_SERVER_ADDRESS(ipaddr)        (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
+#endif
+
+/** DNS server port address */
+#ifndef DNS_SERVER_PORT
+#define DNS_SERVER_PORT           53
+#endif
+
+/** DNS maximum number of retries when asking for a name, before "timeout". */
+#ifndef DNS_MAX_RETRIES
+#define DNS_MAX_RETRIES           4
+#endif
+
+/** DNS resource record max. TTL (one week as default) */
+#ifndef DNS_MAX_TTL
+#define DNS_MAX_TTL               604800
+#endif
+
+/* DNS protocol flags */
+#define DNS_FLAG1_RESPONSE        0x80
+#define DNS_FLAG1_OPCODE_STATUS   0x10
+#define DNS_FLAG1_OPCODE_INVERSE  0x08
+#define DNS_FLAG1_OPCODE_STANDARD 0x00
+#define DNS_FLAG1_AUTHORATIVE     0x04
+#define DNS_FLAG1_TRUNC           0x02
+#define DNS_FLAG1_RD              0x01
+#define DNS_FLAG2_RA              0x80
+#define DNS_FLAG2_ERR_MASK        0x0f
+#define DNS_FLAG2_ERR_NONE        0x00
+#define DNS_FLAG2_ERR_NAME        0x03
+
+/* DNS protocol states */
+#define DNS_STATE_UNUSED          0
+#define DNS_STATE_NEW             1
+#define DNS_STATE_ASKING          2
+#define DNS_STATE_DONE            3
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+/** DNS message header */
+struct dns_hdr {
+  PACK_STRUCT_FIELD(u16_t id);
+  PACK_STRUCT_FIELD(u8_t flags1);
+  PACK_STRUCT_FIELD(u8_t flags2);
+  PACK_STRUCT_FIELD(u16_t numquestions);
+  PACK_STRUCT_FIELD(u16_t numanswers);
+  PACK_STRUCT_FIELD(u16_t numauthrr);
+  PACK_STRUCT_FIELD(u16_t numextrarr);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+#define SIZEOF_DNS_HDR 12
+
+/** DNS query message structure.
+    No packing needed: only used locally on the stack. */
+struct dns_query {
+  /* DNS query record starts with either a domain name or a pointer
+     to a name already present somewhere in the packet. */
+  u16_t type;
+  u16_t cls;
+};
+#define SIZEOF_DNS_QUERY 4
+
+/** DNS answer message structure.
+    No packing needed: only used locally on the stack. */
+struct dns_answer {
+  /* DNS answer record starts with either a domain name or a pointer
+     to a name already present somewhere in the packet. */
+  u16_t type;
+  u16_t cls;
+  u32_t ttl;
+  u16_t len;
+};
+#define SIZEOF_DNS_ANSWER 10
+
+/** DNS table entry */
+struct dns_table_entry {
+  u8_t  state;
+  u8_t  numdns;
+  u8_t  tmr;
+  u8_t  retries;
+  u8_t  seqno;
+  u8_t  err;
+  u32_t ttl;
+  char name[DNS_MAX_NAME_LENGTH];
+  ip_addr_t ipaddr;
+  /* pointer to callback on DNS query done */
+  dns_found_callback found;
+  void *arg;
+};
+
+#if DNS_LOCAL_HOSTLIST
+
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+/** Local host-list. For hostnames in this list, no
+ *  external name resolution is performed */
+static struct local_hostlist_entry *local_hostlist_dynamic;
+#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+/** Defining this allows the local_hostlist_static to be placed in a different
+ * linker section (e.g. FLASH) */
+#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
+#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
+#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
+/** Defining this allows the local_hostlist_static to be placed in a different
+ * linker section (e.g. FLASH) */
+#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
+#define DNS_LOCAL_HOSTLIST_STORAGE_POST
+#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
+DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
+  DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
+
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+static void dns_init_local();
+#endif /* DNS_LOCAL_HOSTLIST */
+
+
+/* forward declarations */
+static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
+static void dns_check_entries(void);
+
+/*-----------------------------------------------------------------------------
+ * Globales
+ *----------------------------------------------------------------------------*/
+
+/* DNS variables */
+static struct udp_pcb        *dns_pcb;
+static u8_t                   dns_seqno;
+static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
+static ip_addr_t              dns_servers[DNS_MAX_SERVERS];
+/** Contiguous buffer for processing responses */
+static u8_t                   dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
+static u8_t*                  dns_payload;
+
+/**
+ * Initialize the resolver: set up the UDP pcb and configure the default server
+ * (DNS_SERVER_ADDRESS).
+ */
+void
+dns_init()
+{
+  ip_addr_t dnsserver;
+
+  dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
+  
+  /* initialize default DNS server address */
+  DNS_SERVER_ADDRESS(&dnsserver);
+
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
+
+  /* if dns client not yet initialized... */
+  if (dns_pcb == NULL) {
+    dns_pcb = udp_new();
+
+    if (dns_pcb != NULL) {
+      /* initialize DNS table not needed (initialized to zero since it is a
+       * global variable) */
+      LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
+        DNS_STATE_UNUSED == 0);
+
+      /* initialize DNS client */
+      udp_bind(dns_pcb, IP_ADDR_ANY, 0);
+      udp_recv(dns_pcb, dns_recv, NULL);
+
+      /* initialize default DNS primary server */
+      dns_setserver(0, &dnsserver);
+    }
+  }
+#if DNS_LOCAL_HOSTLIST
+  dns_init_local();
+#endif
+}
+
+/**
+ * Initialize one of the DNS servers.
+ *
+ * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
+ * @param dnsserver IP address of the DNS server to set
+ */
+void
+dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
+{
+  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
+      (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
+    dns_servers[numdns] = (*dnsserver);
+  }
+}
+
+/**
+ * Obtain one of the currently configured DNS server.
+ *
+ * @param numdns the index of the DNS server
+ * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
+ *         server has not been configured.
+ */
+ip_addr_t
+dns_getserver(u8_t numdns)
+{
+  if (numdns < DNS_MAX_SERVERS) {
+    return dns_servers[numdns];
+  } else {
+    return *IP_ADDR_ANY;
+  }
+}
+
+/**
+ * The DNS resolver client timer - handle retries and timeouts and should
+ * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
+ */
+void
+dns_tmr(void)
+{
+  if (dns_pcb != NULL) {
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
+    dns_check_entries();
+  }
+}
+
+#if DNS_LOCAL_HOSTLIST
+static void
+dns_init_local()
+{
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
+  int i;
+  struct local_hostlist_entry *entry;
+  /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
+  struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
+  size_t namelen;
+  for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
+    struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
+    LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
+    namelen = strlen(init_entry->name);
+    LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
+    entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
+    LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
+    if (entry != NULL) {
+      entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
+      MEMCPY((char*)entry->name, init_entry->name, namelen);
+      ((char*)entry->name)[namelen] = 0;
+      entry->addr = init_entry->addr;
+      entry->next = local_hostlist_dynamic;
+      local_hostlist_dynamic = entry;
+    }
+  }
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
+}
+
+/**
+ * Scans the local host-list for a hostname.
+ *
+ * @param hostname Hostname to look for in the local host-list
+ * @return The first IP address for the hostname in the local host-list or
+ *         IPADDR_NONE if not found.
+ */
+static u32_t
+dns_lookup_local(const char *hostname)
+{
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+  struct local_hostlist_entry *entry = local_hostlist_dynamic;
+  while(entry != NULL) {
+    if(strcmp(entry->name, hostname) == 0) {
+      return ip4_addr_get_u32(&entry->addr);
+    }
+    entry = entry->next;
+  }
+#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+  int i;
+  for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
+    if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
+      return ip4_addr_get_u32(&local_hostlist_static[i].addr);
+    }
+  }
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+  return IPADDR_NONE;
+}
+
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+/** Remove all entries from the local host-list for a specific hostname
+ * and/or IP addess
+ *
+ * @param hostname hostname for which entries shall be removed from the local
+ *                 host-list
+ * @param addr address for which entries shall be removed from the local host-list
+ * @return the number of removed entries
+ */
+int
+dns_local_removehost(const char *hostname, const ip_addr_t *addr)
+{
+  int removed = 0;
+  struct local_hostlist_entry *entry = local_hostlist_dynamic;
+  struct local_hostlist_entry *last_entry = NULL;
+  while (entry != NULL) {
+    if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
+        ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
+      struct local_hostlist_entry *free_entry;
+      if (last_entry != NULL) {
+        last_entry->next = entry->next;
+      } else {
+        local_hostlist_dynamic = entry->next;
+      }
+      free_entry = entry;
+      entry = entry->next;
+      memp_free(MEMP_LOCALHOSTLIST, free_entry);
+      removed++;
+    } else {
+      last_entry = entry;
+      entry = entry->next;
+    }
+  }
+  return removed;
+}
+
+/**
+ * Add a hostname/IP address pair to the local host-list.
+ * Duplicates are not checked.
+ *
+ * @param hostname hostname of the new entry
+ * @param addr IP address of the new entry
+ * @return ERR_OK if succeeded or ERR_MEM on memory error
+ */
+err_t
+dns_local_addhost(const char *hostname, const ip_addr_t *addr)
+{
+  struct local_hostlist_entry *entry;
+  size_t namelen;
+  LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
+  namelen = strlen(hostname);
+  LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
+  entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
+  if (entry == NULL) {
+    return ERR_MEM;
+  }
+  entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
+  MEMCPY((char*)entry->name, hostname, namelen);
+  ((char*)entry->name)[namelen] = 0;
+  ip_addr_copy(entry->addr, *addr);
+  entry->next = local_hostlist_dynamic;
+  local_hostlist_dynamic = entry;
+  return ERR_OK;
+}
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
+#endif /* DNS_LOCAL_HOSTLIST */
+
+/**
+ * Look up a hostname in the array of known hostnames.
+ *
+ * @note This function only looks in the internal array of known
+ * hostnames, it does not send out a query for the hostname if none
+ * was found. The function dns_enqueue() can be used to send a query
+ * for a hostname.
+ *
+ * @param name the hostname to look up
+ * @return the hostname's IP address, as u32_t (instead of ip_addr_t to
+ *         better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
+ *         was not found in the cached dns_table.
+ */
+static u32_t
+dns_lookup(const char *name)
+{
+  u8_t i;
+#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
+  u32_t addr;
+#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
+#if DNS_LOCAL_HOSTLIST
+  if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
+    return addr;
+  }
+#endif /* DNS_LOCAL_HOSTLIST */
+#ifdef DNS_LOOKUP_LOCAL_EXTERN
+  if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
+    return addr;
+  }
+#endif /* DNS_LOOKUP_LOCAL_EXTERN */
+
+  /* Walk through name list, return entry if found. If not, return NULL. */
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
+    if ((dns_table[i].state == DNS_STATE_DONE) &&
+        (strcmp(name, dns_table[i].name) == 0)) {
+      LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
+      ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
+      LWIP_DEBUGF(DNS_DEBUG, ("\n"));
+      return ip4_addr_get_u32(&dns_table[i].ipaddr);
+    }
+  }
+
+  return IPADDR_NONE;
+}
+
+#if DNS_DOES_NAME_CHECK
+/**
+ * Compare the "dotted" name "query" with the encoded name "response"
+ * to make sure an answer from the DNS server matches the current dns_table
+ * entry (otherwise, answers might arrive late for hostname not on the list
+ * any more).
+ *
+ * @param query hostname (not encoded) from the dns_table
+ * @param response encoded hostname in the DNS response
+ * @return 0: names equal; 1: names differ
+ */
+static u8_t
+dns_compare_name(unsigned char *query, unsigned char *response)
+{
+  unsigned char n;
+
+  do {
+    n = *response++;
+    /** @see RFC 1035 - 4.1.4. Message compression */
+    if ((n & 0xc0) == 0xc0) {
+      /* Compressed name */
+      break;
+    } else {
+      /* Not compressed name */
+      while (n > 0) {
+        if ((*query) != (*response)) {
+          return 1;
+        }
+        ++response;
+        ++query;
+        --n;
+      };
+      ++query;
+    }
+  } while (*response != 0);
+
+  return 0;
+}
+#endif /* DNS_DOES_NAME_CHECK */
+
+/**
+ * Walk through a compact encoded DNS name and return the end of the name.
+ *
+ * @param query encoded DNS name in the DNS server response
+ * @return end of the name
+ */
+static unsigned char *
+dns_parse_name(unsigned char *query)
+{
+  unsigned char n;
+
+  do {
+    n = *query++;
+    /** @see RFC 1035 - 4.1.4. Message compression */
+    if ((n & 0xc0) == 0xc0) {
+      /* Compressed name */
+      break;
+    } else {
+      /* Not compressed name */
+      while (n > 0) {
+        ++query;
+        --n;
+      };
+    }
+  } while (*query != 0);
+
+  return query + 1;
+}
+
+/**
+ * Send a DNS query packet.
+ *
+ * @param numdns index of the DNS server in the dns_servers table
+ * @param name hostname to query
+ * @param id index of the hostname in dns_table, used as transaction ID in the
+ *        DNS query packet
+ * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
+ */
+static err_t
+dns_send(u8_t numdns, const char* name, u8_t id)
+{
+  err_t err;
+  struct dns_hdr *hdr;
+  struct dns_query qry;
+  struct pbuf *p;
+  char *query, *nptr;
+  const char *pHostname;
+  u8_t n;
+
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
+              (u16_t)(numdns), name));
+  LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
+  LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
+
+  /* if here, we have either a new query or a retry on a previous query to process */
+  p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
+                 SIZEOF_DNS_QUERY, PBUF_RAM);
+  if (p != NULL) {
+    LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
+    /* fill dns header */
+    hdr = (struct dns_hdr*)p->payload;
+    memset(hdr, 0, SIZEOF_DNS_HDR);
+    hdr->id = htons(id);
+    hdr->flags1 = DNS_FLAG1_RD;
+    hdr->numquestions = PP_HTONS(1);
+    query = (char*)hdr + SIZEOF_DNS_HDR;
+    pHostname = name;
+    --pHostname;
+
+    /* convert hostname into suitable query format. */
+    do {
+      ++pHostname;
+      nptr = query;
+      ++query;
+      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
+        *query = *pHostname;
+        ++query;
+        ++n;
+      }
+      *nptr = n;
+    } while(*pHostname != 0);
+    *query++='\0';
+
+    /* fill dns query */
+    qry.type = PP_HTONS(DNS_RRTYPE_A);
+    qry.cls = PP_HTONS(DNS_RRCLASS_IN);
+    SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
+
+    /* resize pbuf to the exact dns query */
+    pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
+
+    /* connect to the server for faster receiving */
+    udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
+    /* send dns packet */
+    err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
+
+    /* free pbuf */
+    pbuf_free(p);
+  } else {
+    err = ERR_MEM;
+  }
+
+  return err;
+}
+
+/**
+ * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
+ * Check an entry in the dns_table:
+ * - send out query for new entries
+ * - retry old pending entries on timeout (also with different servers)
+ * - remove completed entries from the table if their TTL has expired
+ *
+ * @param i index of the dns_table entry to check
+ */
+static void
+dns_check_entry(u8_t i)
+{
+  err_t err;
+  struct dns_table_entry *pEntry = &dns_table[i];
+
+  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
+
+  switch(pEntry->state) {
+
+    case DNS_STATE_NEW: {
+      /* initialize new entry */
+      pEntry->state   = DNS_STATE_ASKING;
+      pEntry->numdns  = 0;
+      pEntry->tmr     = 1;
+      pEntry->retries = 0;
+      
+      /* send DNS packet for this entry */
+      err = dns_send(pEntry->numdns, pEntry->name, i);
+      if (err != ERR_OK) {
+        LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+                    ("dns_send returned error: %d\n", err));
+      }
+      break;
+    }
+
+    case DNS_STATE_ASKING: {
+      if (--pEntry->tmr == 0) {
+        if (++pEntry->retries == DNS_MAX_RETRIES) {
+          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
+            /* change of server */
+            pEntry->numdns++;
+            pEntry->tmr     = 1;
+            pEntry->retries = 0;
+            break;
+          } else {
+            LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
+            /* call specified callback function if provided */
+            if (pEntry->found)
+              (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
+            /* flush this entry */
+            pEntry->state   = DNS_STATE_UNUSED;
+            pEntry->found   = NULL;
+            break;
+          }
+        }
+
+        /* wait longer for the next retry */
+        pEntry->tmr = pEntry->retries;
+
+        /* send DNS packet for this entry */
+        err = dns_send(pEntry->numdns, pEntry->name, i);
+        if (err != ERR_OK) {
+          LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+                      ("dns_send returned error: %d\n", err));
+        }
+      }
+      break;
+    }
+
+    case DNS_STATE_DONE: {
+      /* if the time to live is nul */
+      if (--pEntry->ttl == 0) {
+        LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
+        /* flush this entry */
+        pEntry->state = DNS_STATE_UNUSED;
+        pEntry->found = NULL;
+      }
+      break;
+    }
+    case DNS_STATE_UNUSED:
+      /* nothing to do */
+      break;
+    default:
+      LWIP_ASSERT("unknown dns_table entry state:", 0);
+      break;
+  }
+}
+
+/**
+ * Call dns_check_entry for each entry in dns_table - check all entries.
+ */
+static void
+dns_check_entries(void)
+{
+  u8_t i;
+
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
+    dns_check_entry(i);
+  }
+}
+
+/**
+ * Receive input function for DNS response packets arriving for the dns UDP pcb.
+ *
+ * @params see udp.h
+ */
+static void
+dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+  u16_t i;
+  char *pHostname;
+  struct dns_hdr *hdr;
+  struct dns_answer ans;
+  struct dns_table_entry *pEntry;
+  u16_t nquestions, nanswers;
+
+  LWIP_UNUSED_ARG(arg);
+  LWIP_UNUSED_ARG(pcb);
+  LWIP_UNUSED_ARG(addr);
+  LWIP_UNUSED_ARG(port);
+
+  /* is the dns message too big ? */
+  if (p->tot_len > DNS_MSG_SIZE) {
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
+    /* free pbuf and return */
+    goto memerr;
+  }
+
+  /* is the dns message big enough ? */
+  if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
+    /* free pbuf and return */
+    goto memerr;
+  }
+
+  /* copy dns payload inside static buffer for processing */ 
+  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
+    /* The ID in the DNS header should be our entry into the name table. */
+    hdr = (struct dns_hdr*)dns_payload;
+    i = htons(hdr->id);
+    if (i < DNS_TABLE_SIZE) {
+      pEntry = &dns_table[i];
+      if(pEntry->state == DNS_STATE_ASKING) {
+        /* This entry is now completed. */
+        pEntry->state = DNS_STATE_DONE;
+        pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;
+
+        /* We only care about the question(s) and the answers. The authrr
+           and the extrarr are simply discarded. */
+        nquestions = htons(hdr->numquestions);
+        nanswers   = htons(hdr->numanswers);
+
+        /* Check for error. If so, call callback to inform. */
+        if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
+          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
+          /* call callback to indicate error, clean up memory and return */
+          goto responseerr;
+        }
+
+#if DNS_DOES_NAME_CHECK
+        /* Check if the name in the "question" part match with the name in the entry. */
+        if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
+          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
+          /* call callback to indicate error, clean up memory and return */
+          goto responseerr;
+        }
+#endif /* DNS_DOES_NAME_CHECK */
+
+        /* Skip the name in the "question" part */
+        pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
+
+        while (nanswers > 0) {
+          /* skip answer resource record's host name */
+          pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
+
+          /* Check for IP address type and Internet class. Others are discarded. */
+          SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
+          if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
+             (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
+            /* read the answer resource record's TTL, and maximize it if needed */
+            pEntry->ttl = ntohl(ans.ttl);
+            if (pEntry->ttl > DNS_MAX_TTL) {
+              pEntry->ttl = DNS_MAX_TTL;
+            }
+            /* read the IP address after answer resource record's header */
+            SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
+            LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
+            ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
+            LWIP_DEBUGF(DNS_DEBUG, ("\n"));
+            /* call specified callback function if provided */
+            if (pEntry->found) {
+              (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
+            }
+            /* deallocate memory and return */
+            goto memerr;
+          } else {
+            pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
+          }
+          --nanswers;
+        }
+        LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
+        /* call callback to indicate error, clean up memory and return */
+        goto responseerr;
+      }
+    }
+  }
+
+  /* deallocate memory and return */
+  goto memerr;
+
+responseerr:
+  /* ERROR: call specified callback function with NULL as name to indicate an error */
+  if (pEntry->found) {
+    (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
+  }
+  /* flush this entry */
+  pEntry->state = DNS_STATE_UNUSED;
+  pEntry->found = NULL;
+
+memerr:
+  /* free pbuf */
+  pbuf_free(p);
+  return;
+}
+
+/**
+ * Queues a new hostname to resolve and sends out a DNS query for that hostname
+ *
+ * @param name the hostname that is to be queried
+ * @param found a callback founction to be called on success, failure or timeout
+ * @param callback_arg argument to pass to the callback function
+ * @return @return a err_t return code.
+ */
+static err_t
+dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
+{
+  u8_t i;
+  u8_t lseq, lseqi;
+  struct dns_table_entry *pEntry = NULL;
+  size_t namelen;
+
+  /* search an unused entry, or the oldest one */
+  lseq = lseqi = 0;
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
+    pEntry = &dns_table[i];
+    /* is it an unused entry ? */
+    if (pEntry->state == DNS_STATE_UNUSED)
+      break;
+
+    /* check if this is the oldest completed entry */
+    if (pEntry->state == DNS_STATE_DONE) {
+      if ((dns_seqno - pEntry->seqno) > lseq) {
+        lseq = dns_seqno - pEntry->seqno;
+        lseqi = i;
+      }
+    }
+  }
+
+  /* if we don't have found an unused entry, use the oldest completed one */
+  if (i == DNS_TABLE_SIZE) {
+    if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
+      /* no entry can't be used now, table is full */
+      LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
+      return ERR_MEM;
+    } else {
+      /* use the oldest completed one */
+      i = lseqi;
+      pEntry = &dns_table[i];
+    }
+  }
+
+  /* use this entry */
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
+
+  /* fill the entry */
+  pEntry->state = DNS_STATE_NEW;
+  pEntry->seqno = dns_seqno++;
+  pEntry->found = found;
+  pEntry->arg   = callback_arg;
+  namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
+  MEMCPY(pEntry->name, name, namelen);
+  pEntry->name[namelen] = 0;
+
+  /* force to send query without waiting timer */
+  dns_check_entry(i);
+
+  /* dns query is enqueued */
+  return ERR_INPROGRESS;
+}
+
+/**
+ * Resolve a hostname (string) into an IP address.
+ * NON-BLOCKING callback version for use with raw API!!!
+ *
+ * Returns immediately with one of err_t return codes:
+ * - ERR_OK if hostname is a valid IP address string or the host
+ *   name is already in the local names table.
+ * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
+ *   for resolution if no errors are present.
+ *
+ * @param hostname the hostname that is to be queried
+ * @param addr pointer to a ip_addr_t where to store the address if it is already
+ *             cached in the dns_table (only valid if ERR_OK is returned!)
+ * @param found a callback function to be called on success, failure or timeout (only if
+ *              ERR_INPROGRESS is returned!)
+ * @param callback_arg argument to pass to the callback function
+ * @return a err_t return code.
+ */
+err_t
+dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
+                  void *callback_arg)
+{
+  u32_t ipaddr;
+  /* not initialized or no valid server yet, or invalid addr pointer
+   * or invalid hostname or invalid hostname length */
+  if ((dns_pcb == NULL) || (addr == NULL) ||
+      (!hostname) || (!hostname[0]) ||
+      (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
+    return ERR_VAL;
+  }
+
+#if LWIP_HAVE_LOOPIF
+  if (strcmp(hostname, "localhost")==0) {
+    ip_addr_set_loopback(addr);
+    return ERR_OK;
+  }
+#endif /* LWIP_HAVE_LOOPIF */
+
+  /* host name already in octet notation? set ip addr and return ERR_OK */
+  ipaddr = ipaddr_addr(hostname);
+  if (ipaddr == IPADDR_NONE) {
+    /* already have this address cached? */
+    ipaddr = dns_lookup(hostname);
+  }
+  if (ipaddr != IPADDR_NONE) {
+    ip4_addr_set_u32(addr, ipaddr);
+    return ERR_OK;
+  }
+
+  /* queue query with specified callback */
+  return dns_enqueue(hostname, found, callback_arg);
+}
+
+#endif /* LWIP_DNS */
--- a/lwip/include/lwip/def.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/lwip/include/lwip/def.h	Fri Jun 18 09:22:54 2010 +0000
@@ -91,6 +91,8 @@
 
 #endif /* BYTE_ORDER == BIG_ENDIAN */
 
+#define PP_HTONS htons
+
 #ifdef __cplusplus
 }
 #endif
--- a/lwip/include/lwip/dns.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/lwip/include/lwip/dns.h	Fri Jun 18 09:22:54 2010 +0000
@@ -1,99 +1,116 @@
-/**
- * lwip DNS resolver header file.
-
- * Author: Jim Pettinato 
- *   April 2007
-
- * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __LWIP_DNS_H__
-#define __LWIP_DNS_H__
-
-#include "lwip/opt.h"
-
-#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
-
-/** DNS timer period */
-#define DNS_TMR_INTERVAL          1000
-
-/** DNS field TYPE used for "Resource Records" */
-#define DNS_RRTYPE_A              1     /* a host address */
-#define DNS_RRTYPE_NS             2     /* an authoritative name server */
-#define DNS_RRTYPE_MD             3     /* a mail destination (Obsolete - use MX) */
-#define DNS_RRTYPE_MF             4     /* a mail forwarder (Obsolete - use MX) */
-#define DNS_RRTYPE_CNAME          5     /* the canonical name for an alias */
-#define DNS_RRTYPE_SOA            6     /* marks the start of a zone of authority */
-#define DNS_RRTYPE_MB             7     /* a mailbox domain name (EXPERIMENTAL) */
-#define DNS_RRTYPE_MG             8     /* a mail group member (EXPERIMENTAL) */
-#define DNS_RRTYPE_MR             9     /* a mail rename domain name (EXPERIMENTAL) */
-#define DNS_RRTYPE_NULL           10    /* a null RR (EXPERIMENTAL) */
-#define DNS_RRTYPE_WKS            11    /* a well known service description */
-#define DNS_RRTYPE_PTR            12    /* a domain name pointer */
-#define DNS_RRTYPE_HINFO          13    /* host information */
-#define DNS_RRTYPE_MINFO          14    /* mailbox or mail list information */
-#define DNS_RRTYPE_MX             15    /* mail exchange */
-#define DNS_RRTYPE_TXT            16    /* text strings */
-
-/** DNS field CLASS used for "Resource Records" */
-#define DNS_RRCLASS_IN            1     /* the Internet */
-#define DNS_RRCLASS_CS            2     /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
-#define DNS_RRCLASS_CH            3     /* the CHAOS class */
-#define DNS_RRCLASS_HS            4     /* Hesiod [Dyer 87] */
-#define DNS_RRCLASS_FLUSH         0x800 /* Flush bit */
-
-/* The size used for the next line is rather a hack, but it prevents including socket.h in all files
-   that include memp.h, and that would possibly break portability (since socket.h defines some types
-   and constants possibly already define by the OS).
-   Calculation rule:
-   sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */
-#define NETDB_ELEM_SIZE           (32 + 16 + DNS_MAX_NAME_LENGTH + 1)
-
-/** Callback which is invoked when a hostname is found.
- * A function of this type must be implemented by the application using the DNS resolver.
- * @param name pointer to the name that was looked up.
- * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
- *        or NULL if the name could not be found (or on any other error).
- * @param callback_arg a user-specified callback argument passed to dns_gethostbyname
-*/
-typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
-
-void           dns_init(void);
-void           dns_tmr(void);
-void           dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
-ip_addr_t      dns_getserver(u8_t numdns);
-err_t          dns_gethostbyname(const char *hostname, ip_addr_t *addr,
-                                 dns_found_callback found, void *callback_arg);
-
-#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
-int            dns_local_removehost(const char *hostname, const ip_addr_t *addr);
-err_t          dns_local_addhost(const char *hostname, const ip_addr_t *addr);
-#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
-
-#endif /* LWIP_DNS */
-
-#endif /* __LWIP_DNS_H__ */
+/**
+ * lwip DNS resolver header file.
+
+ * Author: Jim Pettinato 
+ *   April 2007
+
+ * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LWIP_DNS_H__
+#define __LWIP_DNS_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
+
+/** DNS timer period */
+#define DNS_TMR_INTERVAL          1000
+
+/** DNS field TYPE used for "Resource Records" */
+#define DNS_RRTYPE_A              1     /* a host address */
+#define DNS_RRTYPE_NS             2     /* an authoritative name server */
+#define DNS_RRTYPE_MD             3     /* a mail destination (Obsolete - use MX) */
+#define DNS_RRTYPE_MF             4     /* a mail forwarder (Obsolete - use MX) */
+#define DNS_RRTYPE_CNAME          5     /* the canonical name for an alias */
+#define DNS_RRTYPE_SOA            6     /* marks the start of a zone of authority */
+#define DNS_RRTYPE_MB             7     /* a mailbox domain name (EXPERIMENTAL) */
+#define DNS_RRTYPE_MG             8     /* a mail group member (EXPERIMENTAL) */
+#define DNS_RRTYPE_MR             9     /* a mail rename domain name (EXPERIMENTAL) */
+#define DNS_RRTYPE_NULL           10    /* a null RR (EXPERIMENTAL) */
+#define DNS_RRTYPE_WKS            11    /* a well known service description */
+#define DNS_RRTYPE_PTR            12    /* a domain name pointer */
+#define DNS_RRTYPE_HINFO          13    /* host information */
+#define DNS_RRTYPE_MINFO          14    /* mailbox or mail list information */
+#define DNS_RRTYPE_MX             15    /* mail exchange */
+#define DNS_RRTYPE_TXT            16    /* text strings */
+
+/** DNS field CLASS used for "Resource Records" */
+#define DNS_RRCLASS_IN            1     /* the Internet */
+#define DNS_RRCLASS_CS            2     /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
+#define DNS_RRCLASS_CH            3     /* the CHAOS class */
+#define DNS_RRCLASS_HS            4     /* Hesiod [Dyer 87] */
+#define DNS_RRCLASS_FLUSH         0x800 /* Flush bit */
+
+/* The size used for the next line is rather a hack, but it prevents including socket.h in all files
+   that include memp.h, and that would possibly break portability (since socket.h defines some types
+   and constants possibly already define by the OS).
+   Calculation rule:
+   sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */
+#define NETDB_ELEM_SIZE           (32 + 16 + DNS_MAX_NAME_LENGTH + 1)
+
+#if DNS_LOCAL_HOSTLIST
+/** struct used for local host-list */
+struct local_hostlist_entry {
+  /** static hostname */
+  const char *name;
+  /** static host address in network byteorder */
+  ip_addr_t addr;
+  struct local_hostlist_entry *next;
+};
+#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN
+#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN  DNS_MAX_NAME_LENGTH
+#endif
+#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))
+#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+#endif /* DNS_LOCAL_HOSTLIST */
+
+/** Callback which is invoked when a hostname is found.
+ * A function of this type must be implemented by the application using the DNS resolver.
+ * @param name pointer to the name that was looked up.
+ * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
+ *        or NULL if the name could not be found (or on any other error).
+ * @param callback_arg a user-specified callback argument passed to dns_gethostbyname
+*/
+typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
+
+void           dns_init(void);
+void           dns_tmr(void);
+void           dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
+ip_addr_t      dns_getserver(u8_t numdns);
+err_t          dns_gethostbyname(const char *hostname, ip_addr_t *addr,
+                                 dns_found_callback found, void *callback_arg);
+
+#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
+int            dns_local_removehost(const char *hostname, const ip_addr_t *addr);
+err_t          dns_local_addhost(const char *hostname, const ip_addr_t *addr);
+#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
+
+#endif /* LWIP_DNS */
+
+#endif /* __LWIP_DNS_H__ */
--- a/lwip/lwipopts.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/lwip/lwipopts.h	Fri Jun 18 09:22:54 2010 +0000
@@ -57,16 +57,16 @@
 #define TCPDUMP_DEBUG LWIP_DBG_OFF
 
 #define PPP_DEBUG        LWIP_DBG_OFF
-#define MEM_DEBUG        LWIP_DBG_OFF
-#define MEMP_DEBUG       LWIP_DBG_OFF
-#define PBUF_DEBUG       LWIP_DBG_OFF
+#define MEM_DEBUG        LWIP_DBG_ON
+#define MEMP_DEBUG       LWIP_DBG_ON
+#define PBUF_DEBUG       LWIP_DBG_ON
 #define API_LIB_DEBUG    LWIP_DBG_OFF
 #define API_MSG_DEBUG    LWIP_DBG_OFF
-#define TCPIP_DEBUG      LWIP_DBG_ON
+#define TCPIP_DEBUG      LWIP_DBG_OFF
 #define NETIF_DEBUG      LWIP_DBG_OFF
 #define SOCKETS_DEBUG    LWIP_DBG_OFF
 #define DEMO_DEBUG       LWIP_DBG_OFF
-#define IP_DEBUG         LWIP_DBG_ON
+#define IP_DEBUG         LWIP_DBG_OFF
 #define IP_REASS_DEBUG   LWIP_DBG_OFF
 #define RAW_DEBUG        LWIP_DBG_OFF
 #define ICMP_DEBUG       LWIP_DBG_OFF
@@ -81,6 +81,7 @@
 #define TCP_QLEN_DEBUG   LWIP_DBG_OFF
 #define TCP_RST_DEBUG    LWIP_DBG_OFF
 #define ETHARP_DEBUG     LWIP_DBG_OFF
+#define DNS_DEBUG        LWIP_DBG_OFF
 
 #endif
 
@@ -108,10 +109,13 @@
 /* MEM_SIZE: the size of the heap memory. If the application will send
 a lot of data that needs to be copied, this should be set high. */
 //#define MEM_SIZE               10240 
-#define MEM_SIZE               2000//5000 
+
+#if TARGET_LPC1768
+
+
+#define MEM_SIZE               5000 //2000
 
 ///
-#if TARGET_LPC1768
 
 #define MEM_POSITION __attribute((section("AHBSRAM0")))
 
@@ -155,7 +159,7 @@
 #define PBUF_POOL_SIZE          8//16//100
 
 /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
-#define PBUF_POOL_BUFSIZE       128
+//#define PBUF_POOL_BUFSIZE       128
 
 /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
    link level header. */
@@ -178,14 +182,14 @@
 
 /* TCP Maximum segment size. */
 //#define TCP_MSS                 1024
-#define TCP_MSS                   0x276//536//0x276
+#define TCP_MSS                   1024//0x276//536//0x276
 
 /* TCP sender buffer space (bytes). */
-#define TCP_SND_BUF             2048
+#define TCP_SND_BUF             2048//2048
 
 /* TCP sender buffer space (pbufs). This must be at least = 2 *
    TCP_SND_BUF/TCP_MSS for things to work. */
-#define TCP_SND_QUEUELEN        (3 * TCP_SND_BUF/TCP_MSS)//(4 * TCP_SND_BUF/TCP_MSS)
+#define TCP_SND_QUEUELEN        (8 * TCP_SND_BUF/TCP_MSS)//(4 * TCP_SND_BUF/TCP_MSS)
 
 /* TCP writable space (bytes). This must be less than or equal
    to TCP_SND_BUF. It is the amount of space which must be
@@ -203,7 +207,7 @@
 
 #elif TARGET_LPC2368
 
-#define MEM_POSITION
+#define MEM_POSITION __attribute((section("AHBSRAM1")))
 
 /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
    sends a lot of data out of ROM (or other static memory), this
@@ -220,7 +224,7 @@
 #define MEMP_NUM_TCP_PCB        2
 /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
    connections. */
-#define MEMP_NUM_TCP_PCB_LISTEN 1//4
+#define MEMP_NUM_TCP_PCB_LISTEN 2//4
 /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
    segments. */
 #define MEMP_NUM_TCP_SEG        8
@@ -242,10 +246,10 @@
 
 /* ---------- Pbuf options ---------- */
 /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
-#define PBUF_POOL_SIZE          4//16//100
+#define PBUF_POOL_SIZE          8//16//100
 
 /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
-#define PBUF_POOL_BUFSIZE       128
+//#define PBUF_POOL_BUFSIZE       128
 
 /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
    link level header. */
@@ -268,14 +272,14 @@
 
 /* TCP Maximum segment size. */
 //#define TCP_MSS                 1024
-#define TCP_MSS                   0x276//536//0x276
+#define TCP_MSS                   512//0x276//536//0x276
 
 /* TCP sender buffer space (bytes). */
-#define TCP_SND_BUF             1024
+#define TCP_SND_BUF             1024//2048
 
 /* TCP sender buffer space (pbufs). This must be at least = 2 *
    TCP_SND_BUF/TCP_MSS for things to work. */
-#define TCP_SND_QUEUELEN        (3 * TCP_SND_BUF/TCP_MSS)//(4 * TCP_SND_BUF/TCP_MSS)
+#define TCP_SND_QUEUELEN        (4 * TCP_SND_BUF/TCP_MSS)//(4 * TCP_SND_BUF/TCP_MSS)
 
 /* TCP writable space (bytes). This must be less than or equal
    to TCP_SND_BUF. It is the amount of space which must be
@@ -283,7 +287,7 @@
 #define TCP_SNDLOWAT        (TCP_SND_BUF/2)
 
 /* TCP receive window. */
-#define TCP_WND        1024         //8096
+#define TCP_WND        512         //8096
 
 /* Maximum number of retransmissions of data segments. */
 //#define TCP_MAXRTX              12
--- a/services/http/server/HTTPRequestDispatcher.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/services/http/server/HTTPRequestDispatcher.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -41,14 +41,13 @@
 
 void HTTPRequestDispatcher::dispatchRequest()
 {
-  string rootPath;
-  string subPath;
+  string path;
   string meth;
   HTTP_METH methCode;
   
-  DBG("\r\nDispatching req\r\n");
+  DBG("Dispatching req\r\n");
   
-  if( !getRequest(&rootPath, &subPath, &meth ) )
+  if( !getRequest(&path, &meth ) )
   {
     close();
     return; //Invalid request
@@ -72,23 +71,47 @@
     return;
   }
   
-  DBG("\r\nLooking for a handler\r\n");
+  DBG("Looking for a handler\r\n");
   
   map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*) >::iterator it;
-  it = m_pSvr->m_lpHandlers.find(rootPath); //We are friends so we can do that
-  if(it == m_pSvr->m_lpHandlers.end())
+//  it = m_pSvr->m_lpHandlers.find(rootPath); //We are friends so we can do that
+// NEW CODE START: 
+  int root_len = 0;
+  for (it = m_pSvr->m_lpHandlers.begin(); it != m_pSvr->m_lpHandlers.end(); it++)
   {
-    it = m_pSvr->m_lpHandlers.find(""); //Use default handler if it exists
+    DBG("Checking %s...\n", (*it).first.c_str());
+    root_len = (*it).first.length();
+    if ( root_len &&
+      !path.compare( 0, root_len, (*it).first ) && 
+      (path[root_len] == '/' || path[root_len] == '\0'))
+    {
+      DBG("Found (%s)\n", (*it).first.c_str());
+	    // Found!
+	    break;	// for
+	  }
+  }
+// NEW CODE END
+  if((it == m_pSvr->m_lpHandlers.end()) && !(m_pSvr->m_lpHandlers.empty()))
+  {
+    DBG("Using default handler\n");
+    it = m_pSvr->m_lpHandlers.end();
+    it--; //Get the last element
+    if( ! (((*it).first.length() == 0) || (*it).first.compare("/")) ) //This is not the default handler
+      it = m_pSvr->m_lpHandlers.end();
+    root_len = 0;
   }
   if(it == m_pSvr->m_lpHandlers.end())
   {    
+    DBG("No handler found\n");
     close(); //No handler found
     return;
   }
   
-  DBG("\r\nHandler found.\r\n");
+  DBG("Handler found.\r\n");
   
-  HTTPRequestHandler* pHdlr = (*it).second(rootPath.c_str(), subPath.c_str(), m_pTCPSocket);
+//HTTPRequestHandler* pHdlr = (*it).second(rootPath.c_str(), subPath.c_str(), m_pTCPSocket);
+//NEW CODE 1 LINE:
+  HTTPRequestHandler* pHdlr = (*it).second((*it).first.c_str(), path.c_str() + root_len, m_pTCPSocket);
   m_pTCPSocket = NULL; //We don't own it anymore
   
   switch(methCode)
@@ -104,7 +127,7 @@
     break;
   }
   
-  DBG("\r\nReq handled (or being handled)\r\n");
+  DBG("Req handled (or being handled)\r\n");
   close();
 }
 
@@ -129,7 +152,7 @@
   close();
 }
 
-bool HTTPRequestDispatcher::getRequest(string* rootPath, string* subPath, string* meth)
+bool HTTPRequestDispatcher::getRequest(string* path, string* meth)
 {
   char req[128];
   char c_path[128];
@@ -162,40 +185,18 @@
   }
   *p = 0;
   
-  DBG("\r\nParsing request : %s\r\n", req);
+  DBG("Parsing request : %s\r\n", req);
   
   ret = sscanf(req, "%s %s HTTP/%*d.%*d", c_meth, c_path);
   if(ret !=2)
     return false;
     
   *meth = string(c_meth);
-  *subPath = string(c_path);
-  
-  c_path[0]= '/';
-  if(!strchr(c_path+1, '/'))
-  {
-    //Not found, so this is the root path
-    c_path[1]=0;
-    *rootPath = string(c_path); 
-  } 
-  else
-  {
-    ret = sscanf(req, "%*s /%[^/ ]/%*s HTTP/%*d.%*d", c_path+1);
-    if(ret !=1)
-    {
-      //This is the root path
-      DBG("Default path\n");
-    }
-    *rootPath = string(c_path); 
-    subPath->erase(0,rootPath->length());
-  }
-  
-  
-  DBG("\r\nParse OK :\r\nRoot Path: %s\r\nSub Path: %s\r\nMethod: %s\r\n", rootPath->c_str(), subPath->c_str(), meth->c_str());
-  
+// NEW CODE (old code removed):
+   *path = string(c_path);
   return true;
+}
 
-}
 
 
 void HTTPRequestDispatcher::onTCPSocketEvent(TCPSocketEvent e)
--- a/services/http/server/HTTPRequestDispatcher.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/services/http/server/HTTPRequestDispatcher.h	Fri Jun 18 09:22:54 2010 +0000
@@ -26,7 +26,6 @@
 
 class HTTPServer;
 
-#include "if/net/net.h"
 #include "api/TCPSocket.h"
 #include "HTTPServer.h"
 
@@ -60,7 +59,7 @@
   
   void onTimeout(); //Connection has timed out
 
-  bool getRequest(string* rootPath, string* subPath, string* meth);
+  bool getRequest(string* path, string* meth);
   
   HTTPServer* m_pSvr;
   TCPSocket* m_pTCPSocket;
--- a/services/http/server/HTTPRequestHandler.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/services/http/server/HTTPRequestHandler.h	Fri Jun 18 09:22:54 2010 +0000
@@ -24,7 +24,6 @@
 #ifndef HTTP_REQUEST_HANDLER_H
 #define HTTP_REQUEST_HANDLER_H
 
-#include "if/net/net.h"
 #include "api/TCPSocket.h"
 //#include "HTTPServer.h"
 
--- a/services/http/server/HTTPServer.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/services/http/server/HTTPServer.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -49,6 +49,7 @@
 void HTTPServer::addHandler(const char* path)
 {
   m_lpHandlers[path] = &T::inst;
+  
 }
 #endif
   
--- a/services/http/server/HTTPServer.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/services/http/server/HTTPServer.h	Fri Jun 18 09:22:54 2010 +0000
@@ -42,6 +42,20 @@
 public:
   HTTPServer();
   ~HTTPServer();
+  
+  struct handlersComp //Used to order handlers in the right way
+  {
+    bool operator() (const string& handler1, const string& handler2) const
+    {
+      //The first handler is longer than the second one
+      if (handler1.length() > handler2.length())
+        return true; //Returns true if handler1 is to appear before handler2
+      else if (handler1.length() < handler2.length())
+        return false;
+      else //To avoid the == case, sort now by address
+        return ((&handler1)>(&handler2));
+    }
+  };
 
   template<typename T>
   void addHandler(const char* path) //Template decl in header
@@ -55,7 +69,7 @@
   void onTCPSocketEvent(TCPSocketEvent e);
   
   TCPSocket* m_pTCPSocket;
-  map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*) > m_lpHandlers;
+  map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*), handlersComp > m_lpHandlers;
 
 };
 
--- a/services/http/server/impl/FSHandler.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/services/http/server/impl/FSHandler.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -26,7 +26,9 @@
 //#define __DEBUG
 #include "dbg/dbg.h"
 
-#define CHUNK_SIZE 512//128
+#define CHUNK_SIZE 128
+
+#define DEFAULT_PAGE "/index.htm"
 
 FSHandler::FSHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath, path, pTCPSocket), m_err404(false)
 {}
@@ -48,9 +50,23 @@
 
 void FSHandler::doGet()
 {
-  DBG("\r\nIn FSHandler::doGet()\r\n");
+  DBG("\r\nIn FSHandler::doGet() - rootPath=%s, path=%s\r\n", rootPath().c_str(), path().c_str());
   //FIXME: Translate path to local/path
-  string filePath = m_lFsPath[rootPath()] + path();
+  string checkedRootPath = rootPath();
+  if(checkedRootPath.empty())
+    checkedRootPath="/";
+  string filePath = m_lFsPath[checkedRootPath];
+  if (path().size() > 1)
+  {
+    filePath += path();
+  }
+  else
+  {
+    filePath += DEFAULT_PAGE;
+  }
+  
+  DBG("Trying to open %s\n", filePath.c_str());
+
   m_fp = fopen(filePath.c_str(), "r"); //FIXME: if null, error 404
   
   if(!m_fp)
@@ -62,7 +78,7 @@
     respHeaders()["Content-Type"] = "text/html";
     respHeaders()["Connection"] = "close";
     writeData(msg,strlen(msg)); //Only send header
-    DBG("\r\nExit SimpleHandler::doGet() w Error 404\r\n");
+    DBG("\r\nExit FSHandler::doGet() w Error 404\r\n");
     return;
   }
     
@@ -102,14 +118,38 @@
   }
   
   static char rBuf[CHUNK_SIZE];
-  int len = fread(rBuf, 1, CHUNK_SIZE, m_fp);
-  if(len>0)
+  while(true)
   {
-    writeData(rBuf, len);
-  }
-  else
-  {
-    close(); //Data written, we can close the connection
+    int len = fread(rBuf, 1, CHUNK_SIZE, m_fp);
+    if(len>0)
+    {
+      int writtenLen = writeData(rBuf, len);
+      if(writtenLen < 0) //Socket error
+      {
+        DBG("FSHandler: Socket error %d\n", writtenLen);
+        if(writtenLen == TCPSOCKET_MEM)
+        {
+          fseek(m_fp, -len, SEEK_CUR);
+          return; //Wait for the queued TCP segments to be transmitted
+        }
+        else
+        {
+          //This is a critical error
+          close();
+          return; 
+        }
+      }
+      else if(writtenLen < len) //Short write, socket's buffer is full
+      {
+        fseek(m_fp, writtenLen - len, SEEK_CUR);
+        return;
+      }
+    }
+    else
+    {
+      close(); //Data written, we can close the connection
+      return;
+    }
   }
 }
 
--- a/services/ntp/NTPClient.cpp	Mon Jun 14 10:33:54 2010 +0000
+++ b/services/ntp/NTPClient.cpp	Fri Jun 18 09:22:54 2010 +0000
@@ -29,7 +29,7 @@
 #include "dbg/dbg.h"
 
 #define NTP_PORT 123
-#define NTP_CLIENT_PORT 50420
+#define NTP_CLIENT_PORT 0//50420 //Random port
 #define NTP_REQUEST_TIMEOUT 15000
 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900)
 
@@ -42,7 +42,7 @@
                    | (( x >> 24 ) & 0x000000FF)  )
 #define ntohl( x ) (htonl(x))
 
-NTPClient::NTPClient() : m_state(NTP_PING), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL),
+NTPClient::NTPClient() : NetService(false), m_state(NTP_PING), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL),
 m_watchdog(), m_timeout(0), m_closed(true), m_host(), m_pDnsReq(NULL), m_blockingResult(NTP_PROCESSING)
 {
   setTimeout(NTP_REQUEST_TIMEOUT);
@@ -68,7 +68,7 @@
   return NTP_PROCESSING;
 }
 
-#ifdef __LINKER_BUG_SOLVED__
+#if 0 //For doc only
 template<class T> 
 NTPResult NTPClient::setTime(const Host& host, T* pItem, void (T::*pMethod)(NTPResult)) //Non blocking
 {
@@ -81,7 +81,12 @@
 void NTPClient::doSetTime(const Host& host)
 {
   init();
+  resetTimeout();
   m_host = host;
+  if(!m_host.getPort())
+  {
+    m_host.setPort(NTP_PORT);
+  }
   if(m_host.getIp().isNull())
   {
     //DNS query required
@@ -91,16 +96,7 @@
     m_pDnsReq->resolve(&m_host);
     return;
   }
-  if(!m_host.getPort())
-  {
-    m_host.setPort(NTP_PORT);
-  }
-  
-  m_state = NTP_PING;
-  Host localhost(IpAddr(127,0,0,1), NTP_CLIENT_PORT, "localhost");
-  m_pUDPSocket->bind(localhost);
-  set_time( 1280000000 ); //End of July 2010... just there to limit offset range
-  process();
+  open();
 }
 
 void NTPClient::setOnResult( void (*pMethod)(NTPResult) )
@@ -108,22 +104,12 @@
   m_pCb = pMethod;
 }
 
-void NTPClient::init() //Create and setup socket if needed
-{
-  if(!m_closed) //Already opened
-    return;
-  m_state = NTP_PING;
-  m_pUDPSocket = new UDPSocket;
-  m_pUDPSocket->setOnEvent(this, &NTPClient::onUDPSocketEvent);
-  m_closed = false;
-}
-
 void NTPClient::close()
 {
   if(m_closed)
     return;
   m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
-  m_watchdog.detach();
+  m_watchdog.stop();
   m_pUDPSocket->resetOnEvent();
   m_pUDPSocket->close();
   delete m_pUDPSocket;
@@ -135,45 +121,74 @@
   }
 }
 
+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
+    return;
+  m_state = NTP_PING;
+  m_pUDPSocket = new UDPSocket;
+  m_pUDPSocket->setOnEvent(this, &NTPClient::onUDPSocketEvent);
+  m_closed = false;
+  DBG("NTPClient: Init OK\n");
+}
+
+void NTPClient::open()
+{
+  resetTimeout();
+  DBG("Opening connection\n");
+  m_state = NTP_PING;
+  Host localhost(IpAddr(127,0,0,1), NTP_CLIENT_PORT, "localhost");
+  m_pUDPSocket->bind(localhost);
+  set_time( 1280000000 ); //End of July 2010... just there to limit offset range
+  process();
+}
+
 #define MIN(a,b) ((a)<(b))?(a):(b)
 void NTPClient::process() //Main state-machine
 {
-  NTPPacket pkt;
   int len;
   Host host;
-
+  
   switch(m_state)
   {
   case NTP_PING:
     DBG("\r\nPing\r\n");
     //Prepare NTP Packet:
-    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.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.rootDelay = 0; //Or this one
-    pkt.rootDispersion = 0; //Or that one
-    pkt.refId = 0; //...
+    m_pkt.rootDelay = 0; //Or this one
+    m_pkt.rootDispersion = 0; //Or that one
+    m_pkt.refId = 0; //...
     
-    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_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_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0;
+    m_pkt.refTm_f = m_pkt.origTm_f = m_pkt.rxTm_f = m_pkt.txTm_f = 0;
     
     //Hex Dump:
     DBG("\r\nDump Tx:\r\n");
     for(int i = 0; i< sizeof(NTPPacket); i++)
     {
-      DBG("%02x ", *((char*)&pkt + i));
+      DBG("%02x ", *((char*)&m_pkt + i));
     }
     DBG("\r\n\r\n");
     
-    len = m_pUDPSocket->sendto( (char*)&pkt, sizeof(NTPPacket), &m_host );
+    len = m_pUDPSocket->sendto( (char*)&m_pkt, sizeof(NTPPacket), &m_host );
     if(len < sizeof(NTPPacket))
       { onResult(NTP_PRTCL); close(); return; }
       
@@ -183,12 +198,11 @@
   
   case NTP_PONG:
     DBG("\r\nPong\r\n");
-    while( len = m_pUDPSocket->recvfrom( (char*)&pkt, sizeof(NTPPacket), &host ) )
+    while( len = m_pUDPSocket->recvfrom( (char*)&m_pkt, sizeof(NTPPacket), &host ) )
     {
       if( len <= 0 )
         break;
       if( !host.getIp().isEq(m_host.getIp()) )
-      //if( !ip_addr_cmp( &host.getIp().getStruct(), &m_host.getIp().getStruct() ) ) //Was working like that, trying nicer impl above
         continue; //Not our packet
       if( len > 0 )
         break;
@@ -207,33 +221,33 @@
     DBG("\r\nDump Rx:\r\n");
     for(int i = 0; i< sizeof(NTPPacket); i++)
     {
-      DBG("%02x ", *((char*)&pkt + i));
+      DBG("%02x ", *((char*)&m_pkt + i));
     }
     DBG("\r\n\r\n");
       
-    if( pkt.stratum == 0)  //Kiss of death message : Not good !
+    if( m_pkt.stratum == 0)  //Kiss of death message : Not good !
     {
       onResult(NTP_PRTCL); close(); return;
     }
     
     //Correct Endianness
-    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 );
+    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 );
     
     //Compute offset, see RFC 4330 p.13
     uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL));
-    //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.rxTm_s - pkt.origTm_s ) + ( pkt.txTm_s - destTm_s ) ) << 32 + ( ( pkt.rxTm_f - pkt.origTm_f ) + ( pkt.txTm_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("\r\nSent @%d\r\n", pkt.txTm_s);
+    //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("\r\nSent @%d\r\n", m_pkt.txTm_s);
     DBG("\r\nOffset: %d\r\n", offset);
     //Set time accordingly
     set_time( time(NULL) + (offset /*>> 32*/) );
@@ -247,14 +261,13 @@
 
 void NTPClient::setTimeout(int ms)
 {
-  m_timeout = 1000*ms;
-  resetTimeout();
+  m_timeout = ms;
 }
 
 void NTPClient::resetTimeout()
 {
-  m_watchdog.detach();
-  m_watchdog.attach_us<NTPClient>(this, &NTPClient::onTimeout, m_timeout);
+  m_watchdog.reset();
+  m_watchdog.start();
 }
 
 void NTPClient::onTimeout() //Connection has timed out
@@ -278,14 +291,16 @@
     close();
     return;
   }
+  DBG("\r\nDNS resolved.\r\n");
   m_pDnsReq->close();
   delete m_pDnsReq;
   m_pDnsReq=NULL;
-  doSetTime(m_host);
+  open();
 }
   
 void NTPClient::onUDPSocketEvent(UDPSocketEvent e)
 {
+  resetTimeout();
   switch(e)
   {
   case UDPSOCKET_READABLE: //The only event for now
--- a/services/ntp/NTPClient.h	Mon Jun 14 10:33:54 2010 +0000
+++ b/services/ntp/NTPClient.h	Fri Jun 18 09:22:54 2010 +0000
@@ -38,7 +38,7 @@
   NTP_DNS //Could not resolve DNS Addr
 };
 
-class NTPClient
+class NTPClient : protected NetService
 {
 public:
   NTPClient();
@@ -66,10 +66,15 @@
     m_pCbMeth = (void (CDummy::*)(NTPResult)) pMethod;
   }
   
-  void init();
   void close();
   
+protected:
+  virtual void poll(); //Called by NetServices
+  
 private:
+  void init();
+  void open();
+  
   __packed struct NTPPacket //See RFC 4330 for Simple NTP
   {
     //WARN: We are in LE! Network is BE!
@@ -119,12 +124,14 @@
   
   NTPStep m_state;
   
+  NTPPacket m_pkt;
+  
   CDummy* m_pCbItem;
   void (CDummy::*m_pCbMeth)(NTPResult);
   
   void (*m_pCb)(NTPResult);
   
-  Timeout m_watchdog;
+  Timer m_watchdog;
   int m_timeout;
   
   bool m_closed;