Darran Shepherd
/
Bonjour
First step: AutoIP compiled in and working
Revision 1:4218cacaf696, committed 2010-06-18
- Comitter:
- darran
- Date:
- Fri Jun 18 15:54:21 2010 +0000
- Parent:
- 0:55a05330f8cc
- Commit message:
Changed in this revision
diff -r 55a05330f8cc -r 4218cacaf696 api/DNSRequest.cpp --- a/api/DNSRequest.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/api/DNSRequest.cpp Fri Jun 18 15:54:21 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) ) {
diff -r 55a05330f8cc -r 4218cacaf696 api/TCPSocket.cpp --- a/api/TCPSocket.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/api/TCPSocket.cpp Fri Jun 18 15:54:21 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); }
diff -r 55a05330f8cc -r 4218cacaf696 api/UDPSocket.cpp --- a/api/UDPSocket.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/api/UDPSocket.cpp Fri Jun 18 15:54:21 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) { }
diff -r 55a05330f8cc -r 4218cacaf696 dbg/dbg.cpp --- a/dbg/dbg.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/dbg/dbg.cpp Fri Jun 18 15:54:21 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, ...) {
diff -r 55a05330f8cc -r 4218cacaf696 dbg/dbg.h --- a/dbg/dbg.h Fri Jun 18 09:11:35 2010 +0000 +++ b/dbg/dbg.h Fri Jun 18 15:54:21 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
diff -r 55a05330f8cc -r 4218cacaf696 drv/gprs/GPRSModem.cpp --- a/drv/gprs/GPRSModem.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/drv/gprs/GPRSModem.cpp Fri Jun 18 15:54:21 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.
diff -r 55a05330f8cc -r 4218cacaf696 drv/serial/usb/usbserialif.cpp --- a/drv/serial/usb/usbserialif.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/drv/serial/usb/usbserialif.cpp Fri Jun 18 15:54:21 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 {
diff -r 55a05330f8cc -r 4218cacaf696 if/eth/EthernetNetIf.cpp --- a/if/eth/EthernetNetIf.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/if/eth/EthernetNetIf.cpp Fri Jun 18 15:54:21 2010 +0000 @@ -25,6 +25,7 @@ #include "netif/etharp.h" #include "lwip/dhcp.h" #include "lwip/dns.h" +#include "ipv4/lwip/autoip.h" #include "drv/eth/eth_drv.h" #include "mbed.h" @@ -34,7 +35,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_autoIpTimer(), m_pNetIf(NULL), m_netmask(255,255,255,255), m_gateway(), m_hostname(NULL) { m_hostname = NULL; @@ -42,7 +43,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_autoIpTimer(), m_pNetIf(NULL), m_hostname(NULL) //W/o DHCP { m_hostname = NULL; m_netmask = netmask; @@ -67,11 +68,15 @@ EthernetErr EthernetNetIf::setup(int timeout_ms /*= 15000*/) { LwipNetIf::init(); - m_ethArpTicker.attach_us(ðarp_tmr, ARP_TMR_INTERVAL * 1000); // = 5s in etharp.h + //m_ethArpTicker.attach_us(ðarp_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_autoIpTimer.start(); } m_pNetIf->hwaddr_len = ETHARP_HWADDR_LEN; //6 eth_address((char *)m_pNetIf->hwaddr); @@ -79,8 +84,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 +105,24 @@ 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(); + } + if(m_autoIpTimer.read_ms()>=AUTOIP_TMR_INTERVAL) + { + m_autoIpTimer.reset(); + autoip_tmr(); + } + } poll(); if( timeout.read_ms() > timeout_ms ) { @@ -123,6 +145,11 @@ void EthernetNetIf::poll() { + if(m_ethArpTimer.read_ms()>=ARP_TMR_INTERVAL) + { + m_ethArpTimer.reset(); + etharp_tmr(); + } LwipNetIf::poll(); eth_poll(); }
diff -r 55a05330f8cc -r 4218cacaf696 if/eth/EthernetNetIf.h --- a/if/eth/EthernetNetIf.h Fri Jun 18 09:11:35 2010 +0000 +++ b/if/eth/EthernetNetIf.h Fri Jun 18 15:54:21 2010 +0000 @@ -26,7 +26,6 @@ struct netif; -//class Ticker; #include "mbed.h" #include "if/net/net.h" @@ -51,9 +50,10 @@ virtual void poll(); private: - Ticker m_ethArpTicker; - Ticker m_dhcpCoarseTicker; - Ticker m_dhcpFineTicker; + Timer m_ethArpTimer; + Timer m_dhcpCoarseTimer; + Timer m_dhcpFineTimer; + Timer m_autoIpTimer; bool m_useDhcp;
diff -r 55a05330f8cc -r 4218cacaf696 if/lwip/LwipNetIf.cpp --- a/if/lwip/LwipNetIf.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/if/lwip/LwipNetIf.cpp Fri Jun 18 15:54:21 2010 +0000 @@ -31,7 +31,7 @@ //See doc/rawapi.txt for details -LwipNetIf::LwipNetIf() : NetIf(), m_tcpTicker(), m_dnsTicker(), m_init(false) +LwipNetIf::LwipNetIf() : NetIf(), m_tcpTimer(), m_dnsTimer(), m_init(false) { } @@ -39,8 +39,7 @@ LwipNetIf::~LwipNetIf() { - m_tcpTicker.detach(); - m_dnsTicker.detach(); + } void LwipNetIf::init() @@ -51,8 +50,10 @@ 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_dnsTimer.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 +78,16 @@ void LwipNetIf::poll() { + if(m_init && m_tcpTimer.read_ms() >= TCP_TMR_INTERVAL) + { + m_tcpTimer.reset(); + tcp_tmr(); //Poll LwIP + } + if(m_init && m_dnsTimer.read_ms() >= DNS_TMR_INTERVAL) + { + m_dnsTimer.reset(); + dns_tmr(); + } //Do some stuff... }
diff -r 55a05330f8cc -r 4218cacaf696 if/lwip/LwipNetIf.h --- a/if/lwip/LwipNetIf.h Fri Jun 18 09:11:35 2010 +0000 +++ b/if/lwip/LwipNetIf.h Fri Jun 18 15:54:21 2010 +0000 @@ -49,8 +49,8 @@ virtual void poll(); private: - Ticker m_tcpTicker; - Ticker m_dnsTicker; + Timer m_tcpTimer; + Timer m_dnsTimer; bool m_init;
diff -r 55a05330f8cc -r 4218cacaf696 if/lwip/lwipNetDnsRequest.cpp --- a/if/lwip/lwipNetDnsRequest.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/if/lwip/lwipNetDnsRequest.cpp Fri Jun 18 15:54:21 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); } @@ -106,16 +106,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,6 +143,7 @@ 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 ); }
diff -r 55a05330f8cc -r 4218cacaf696 if/lwip/lwipNetDnsRequest.h --- a/if/lwip/lwipNetDnsRequest.h Fri Jun 18 09:11:35 2010 +0000 +++ b/if/lwip/lwipNetDnsRequest.h Fri Jun 18 15:54:21 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,8 @@ //Static callbacks : Transforms into a C++ callback static void sFoundCb(const char *name, ip_addr_t *ipaddr, void *arg); + + bool m_closing; }; #endif
diff -r 55a05330f8cc -r 4218cacaf696 if/lwip/lwipNetTcpSocket.cpp --- a/if/lwip/lwipNetTcpSocket.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/if/lwip/lwipNetTcpSocket.cpp Fri Jun 18 15:54:21 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) {
diff -r 55a05330f8cc -r 4218cacaf696 if/lwip/lwipNetUdpSocket.cpp --- a/if/lwip/lwipNetUdpSocket.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/if/lwip/lwipNetUdpSocket.cpp Fri Jun 18 15:54:21 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(); }
diff -r 55a05330f8cc -r 4218cacaf696 if/net/net.cpp --- a/if/net/net.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/if/net/net.cpp Fri Jun 18 15:54:21 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;
diff -r 55a05330f8cc -r 4218cacaf696 if/net/netservice.cpp --- a/if/net/netservice.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/if/net/netservice.cpp Fri Jun 18 15:54:21 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; }
diff -r 55a05330f8cc -r 4218cacaf696 if/net/netudpsocket.cpp --- a/if/net/netudpsocket.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/if/net/netudpsocket.cpp Fri Jun 18 15:54:21 2010 +0000 @@ -38,7 +38,7 @@ //Callbacks -#ifdef __LINKER_BUG_SOLVED__ +#if 0 //Just for info void NetUdpSocket::setOnEvent() { m_pCbItem = (CDummy*) pItem;
diff -r 55a05330f8cc -r 4218cacaf696 lwip/core/dns.c --- a/lwip/core/dns.c Fri Jun 18 09:11:35 2010 +0000 +++ b/lwip/core/dns.c Fri Jun 18 15:54:21 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 */
diff -r 55a05330f8cc -r 4218cacaf696 lwip/include/lwip/def.h --- a/lwip/include/lwip/def.h Fri Jun 18 09:11:35 2010 +0000 +++ b/lwip/include/lwip/def.h Fri Jun 18 15:54:21 2010 +0000 @@ -91,6 +91,8 @@ #endif /* BYTE_ORDER == BIG_ENDIAN */ +#define PP_HTONS htons + #ifdef __cplusplus } #endif
diff -r 55a05330f8cc -r 4218cacaf696 lwip/include/lwip/dns.h --- a/lwip/include/lwip/dns.h Fri Jun 18 09:11:35 2010 +0000 +++ b/lwip/include/lwip/dns.h Fri Jun 18 15:54:21 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__ */
diff -r 55a05330f8cc -r 4218cacaf696 lwip/lwipopts.h --- a/lwip/lwipopts.h Fri Jun 18 09:11:35 2010 +0000 +++ b/lwip/lwipopts.h Fri Jun 18 15:54:21 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 3000 //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//536//0x276 /* TCP sender buffer space (bytes). */ #define TCP_SND_BUF 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 (2 * 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 @@ -327,7 +331,9 @@ #define DHCP_DOES_ARP_CHECK (LWIP_DHCP) /* ---------- AUTOIP options ------- */ -#define LWIP_AUTOIP 0 +#define LWIP_AUTOIP (LWIP_DHCP) +#define LWIP_DHCP_AUTOIP_COOP (LWIP_AUTOIP) +#define LWIP_DHCP_AUTOIP_COOP_TRIES 3 /* ---------- SNMP options ---------- */ /** @todo SNMP is experimental for now
diff -r 55a05330f8cc -r 4218cacaf696 main.cpp --- a/main.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/main.cpp Fri Jun 18 15:54:21 2010 +0000 @@ -18,9 +18,5 @@ printf("Entering while loop Net::poll()ing\r\n"); while (1) { Net::poll(); - myled = 1; - wait(0.2); - myled = 0; - wait(0.2); } }
diff -r 55a05330f8cc -r 4218cacaf696 netCfg.h --- a/netCfg.h Fri Jun 18 09:11:35 2010 +0000 +++ b/netCfg.h Fri Jun 18 15:54:21 2010 +0000 @@ -1,12 +1,12 @@ #ifndef NET_CFG_H #define NET_TELIT_STACK 0 -#define NET_GPRS 1 -#define NET_PPP 1 +#define NET_GPRS 0 +#define NET_PPP 0 #define NET_ZG2100 0 #define NET_ETH 1 #define NET_USB_SERIAL 0 -#define NET_TELIT 1 -#define NET_CFG_H 1 -#define NET_USB 1 +#define NET_TELIT 0 +#define NET_CFG_H 0 +#define NET_USB 0 #define NET_LWIP_STACK 1 #endif
diff -r 55a05330f8cc -r 4218cacaf696 services/http/client/HTTPClient.cpp --- a/services/http/client/HTTPClient.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/services/http/client/HTTPClient.cpp Fri Jun 18 15:54:21 2010 +0000 @@ -144,7 +144,7 @@ void HTTPClient::setTimeout(int ms) { - m_timeout = 1000*ms; + m_timeout = ms; //resetTimeout(); } @@ -154,7 +154,7 @@ { return; } - if(m_watchdog.read_us()>m_timeout) + if(m_watchdog.read_ms()>m_timeout) { onTimeout(); } @@ -396,6 +396,9 @@ onResult(HTTP_CONN); return; } + + if(len>0) + resetTimeout(); if(m_state == HTTP_READ_DATA_INCOMPLETE) return;
diff -r 55a05330f8cc -r 4218cacaf696 services/http/server/HTTPRequestDispatcher.cpp --- a/services/http/server/HTTPRequestDispatcher.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/services/http/server/HTTPRequestDispatcher.cpp Fri Jun 18 15:54:21 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)
diff -r 55a05330f8cc -r 4218cacaf696 services/http/server/HTTPRequestDispatcher.h --- a/services/http/server/HTTPRequestDispatcher.h Fri Jun 18 09:11:35 2010 +0000 +++ b/services/http/server/HTTPRequestDispatcher.h Fri Jun 18 15:54:21 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;
diff -r 55a05330f8cc -r 4218cacaf696 services/http/server/HTTPRequestHandler.h --- a/services/http/server/HTTPRequestHandler.h Fri Jun 18 09:11:35 2010 +0000 +++ b/services/http/server/HTTPRequestHandler.h Fri Jun 18 15:54:21 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"
diff -r 55a05330f8cc -r 4218cacaf696 services/http/server/HTTPServer.cpp --- a/services/http/server/HTTPServer.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/services/http/server/HTTPServer.cpp Fri Jun 18 15:54:21 2010 +0000 @@ -49,6 +49,7 @@ void HTTPServer::addHandler(const char* path) { m_lpHandlers[path] = &T::inst; + } #endif
diff -r 55a05330f8cc -r 4218cacaf696 services/http/server/HTTPServer.h --- a/services/http/server/HTTPServer.h Fri Jun 18 09:11:35 2010 +0000 +++ b/services/http/server/HTTPServer.h Fri Jun 18 15:54:21 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; };
diff -r 55a05330f8cc -r 4218cacaf696 services/http/server/impl/FSHandler.cpp --- a/services/http/server/impl/FSHandler.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/services/http/server/impl/FSHandler.cpp Fri Jun 18 15:54:21 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; + } } }
diff -r 55a05330f8cc -r 4218cacaf696 services/ntp/NTPClient.cpp --- a/services/ntp/NTPClient.cpp Fri Jun 18 09:11:35 2010 +0000 +++ b/services/ntp/NTPClient.cpp Fri Jun 18 15:54:21 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
diff -r 55a05330f8cc -r 4218cacaf696 services/ntp/NTPClient.h --- a/services/ntp/NTPClient.h Fri Jun 18 09:11:35 2010 +0000 +++ b/services/ntp/NTPClient.h Fri Jun 18 15:54:21 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;