This is WIZnet Ethernet Interface using Hardware TCP/IP chip, W5500, W5200 and W5100. One of them can be selected by enabling it in wiznet.h.

Dependents:   Embedded_web EmailButton EmailButton HTTPClient_Weather ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DNSClient.cpp Source File

DNSClient.cpp

00001 // DNSClient.cpp 2013/8/27
00002 #include "mbed.h"
00003 #include "mbed_debug.h"
00004 #include "DNSClient.h"
00005 #include "UDPSocket.h"
00006 #include "dnsname.h"
00007 #include "wiznet.h"
00008 
00009 #define DBG_DNS 0
00010 
00011 #if DBG_DNS
00012 #define DBG2(...) do{debug("[DNS]%p %d %s ", this,__LINE__,__PRETTY_FUNCTION__); debug(__VA_ARGS__); } while(0);
00013 #else
00014 #define DBG2(...) while(0);
00015 #endif
00016 
00017 DNSClient::DNSClient(const char* hostname) : m_state(MYNETDNS_START), m_udp(NULL) {
00018     m_hostname = hostname;
00019 }
00020 
00021 DNSClient::DNSClient(Endpoint* pHost) : m_state(MYNETDNS_START), m_udp(NULL) {
00022 }
00023 
00024 DNSClient::~DNSClient() {
00025     if (m_udp) {
00026         delete m_udp;
00027     }
00028 }
00029 
00030 void DNSClient::callback()
00031 {
00032     uint8_t buf[512];
00033     Endpoint host;
00034     int len = m_udp->receiveFrom(host, (char*)buf, sizeof(buf));
00035     if (len < 0) {
00036         return;
00037     }
00038     if (memcmp(buf+0, m_id, 2) != 0) { //verify
00039         return;
00040     }
00041     int rcode = response(buf, len);
00042     if (rcode == 0) {
00043         m_state = MYNETDNS_OK;
00044     } else {
00045         m_state = MYNETDNS_NOTFOUND;
00046     }
00047 }
00048 
00049 int DNSClient::response(uint8_t buf[], int size) {
00050     int rcode = buf[3] & 0x0f;
00051     if (rcode != 0) {
00052         return rcode;
00053     }
00054     int qdcount = buf[4]<<8|buf[5];
00055     int ancount = buf[6]<<8|buf[7];
00056     int pos = 12;
00057     while(qdcount-- > 0) {
00058         dnsname qname(buf);
00059         pos = qname.decode(pos); // qname
00060         pos += 4; // qtype qclass
00061     }
00062     while(ancount-- > 0) {
00063         dnsname name(buf);
00064         pos = name.decode(pos); // name
00065         int type = buf[pos]<<8|buf[pos+1];
00066         pos += 8; // type class TTL  
00067         int rdlength = buf[pos]<<8|buf[pos+1]; pos += 2;
00068         int rdata_pos = pos;
00069         pos += rdlength;
00070         if (type == 1) { // A record
00071             ip = (buf[rdata_pos]<<24) | (buf[rdata_pos+1]<<16) | (buf[rdata_pos+2]<<8) | buf[rdata_pos+3];
00072         }
00073 #if DBG_DNS
00074         printf("%s", name.str.c_str());
00075         if (type == 1) {
00076             printf(" A %d.%d.%d.%d\n", 
00077                 buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]);
00078         } else if (type == 5) {
00079             dnsname rdname(buf);
00080             rdname.decode(rdata_pos);
00081             printf(" CNAME %s\n", rdname.str.c_str());
00082         } else {
00083             printf(" TYPE:%d", type);
00084             printfBytes(" RDATA:", &buf[rdata_pos], rdlength);
00085         }
00086 #endif
00087     }
00088     return rcode;
00089 }
00090 
00091 int DNSClient::query(uint8_t buf[], int size, const char* hostname) {
00092     const uint8_t header[] = {
00093         0x00,0x00,0x01,0x00, // id=0x0000 QR=0 rd=1 opcode=0 rcode=0
00094         0x00,0x01,0x00,0x00, // qdcount=1 ancount=0
00095         0x00,0x00,0x00,0x00};// nscount=0 arcount=0 
00096     const uint8_t tail[] = {0x00,0x01,0x00,0x01}; // qtype=A qclass=IN
00097     memcpy(buf, header, sizeof(header));
00098     int t = rand();
00099     m_id[0] = t>>8;
00100     m_id[1] = t;
00101     memcpy(buf, m_id, 2); 
00102     dnsname qname(buf);
00103     int pos = qname.encode(sizeof(header), (char*)hostname);
00104     memcpy(buf+pos, tail, sizeof(tail));
00105     pos += sizeof(tail);
00106     return pos;
00107 }
00108 
00109 void DNSClient::resolve(const char* hostname) {
00110     if (m_udp == NULL) {
00111         m_udp = new UDPSocket;
00112     }
00113     m_udp->init();
00114     m_udp->set_blocking(false);
00115     Endpoint server;
00116     server.set_address("8.8.8.8", 53); // DNS
00117     m_udp->bind(rand()&0x7fff);
00118     uint8_t buf[256];                
00119     int size = query(buf, sizeof(buf), hostname);
00120 #if DBG_DNS
00121     printf("hostname:[%s]\n", hostname);
00122     printHex(buf, size);
00123 #endif
00124     m_udp->sendTo(server, (char*)buf, size);
00125     m_interval.reset();
00126     m_interval.start();
00127 }
00128 
00129 void DNSClient::poll() {
00130 #if DBG_DNS
00131     printf("%p m_state: %d, m_udp: %p\n", this, m_state, m_udp);
00132     wait_ms(400);
00133 #endif
00134     switch(m_state) {
00135         case MYNETDNS_START:
00136             m_retry = 0;
00137             resolve(m_hostname);
00138             m_state = MYNETDNS_PROCESSING;
00139             break;
00140         case MYNETDNS_PROCESSING: 
00141             break;
00142         case MYNETDNS_NOTFOUND: 
00143             break;
00144         case MYNETDNS_ERROR: 
00145             break;
00146         case MYNETDNS_OK:
00147             DBG2("m_retry=%d, m_interval=%d\n", m_retry, m_interval.read_ms());
00148             break;
00149     }
00150     if (m_interval.read_ms() > 1000) {
00151         m_interval.stop();
00152         DBG2("timeout m_retry=%d\n", m_retry);
00153         if (++m_retry >= 2) {
00154             m_state = MYNETDNS_ERROR;
00155         } else {
00156             resolve(m_hostname);
00157             m_state = MYNETDNS_PROCESSING;
00158         }
00159     }
00160 }
00161 
00162 bool DNSClient::lookup(const char* hostname) {
00163     m_hostname = hostname;
00164     m_state = MYNETDNS_START;
00165     while(1) {
00166         poll();
00167         callback();
00168         if (m_state != MYNETDNS_PROCESSING) {
00169             break;
00170         } 
00171     }
00172     return m_state == MYNETDNS_OK;
00173 }
00174