W5500 driver for mbed OS 5

Dependents:   http-webserver-example mbed-os-example-sockets

Fork of W5500Interface by Sergei G

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 #if DBG_DNS
00010 #define DBG2(...) do{debug("[DNS]%p %d %s ", this,__LINE__,__PRETTY_FUNCTION__); debug(__VA_ARGS__); } while(0);
00011 #else
00012 #define DBG2(...) while(0);
00013 #endif
00014 
00015 static SocketAddress theDnsServer;
00016 
00017 DNSClient::DNSClient() : m_state(MYNETDNS_START), m_udp(NULL) {
00018     m_ns = NULL;
00019 
00020     //default to google
00021     theDnsServer.set_ip_address("8.8.8.8"); // DNS
00022     theDnsServer.set_port(53); // DNS
00023 }
00024 
00025 DNSClient::DNSClient(NetworkStack *ns, const char* hostname) : m_state(MYNETDNS_START), m_udp(NULL) {
00026     m_hostname = hostname;
00027     m_ns       = ns;
00028     
00029     //default to google
00030     theDnsServer.set_ip_address("8.8.8.8"); // DNS
00031     theDnsServer.set_port(53); // DNS
00032 }
00033 
00034 DNSClient::DNSClient(NetworkStack *ns, SocketAddress* pHost) : m_state(MYNETDNS_START), m_udp(NULL) {
00035     m_ns = ns;
00036 
00037     //default to google
00038     theDnsServer.set_ip_address("8.8.8.8"); // DNS
00039     theDnsServer.set_port(53); // DNS
00040 }
00041 
00042 DNSClient::~DNSClient() {
00043     if (m_udp) {
00044         delete m_udp;
00045     }
00046 }
00047 
00048 int DNSClient::setup(NetworkStack *ns) {
00049     m_ns = ns;
00050     return 0;
00051 }
00052 
00053 bool DNSClient::set_server(const char* serverip, int port) {
00054     theDnsServer.set_ip_address(serverip); 
00055     theDnsServer.set_port(port);
00056     return true;
00057 }
00058 
00059 void DNSClient::callback()
00060 {
00061     uint8_t buf[512];
00062     SocketAddress host;
00063     int len = m_udp->recvfrom(&host, (char*)buf, sizeof(buf));
00064     if (len < 0) {
00065         return;
00066     }
00067     if (memcmp(buf+0, m_id, 2) != 0) { //verify
00068         return;
00069     }
00070     
00071     int rcode = response(buf, len);
00072     if (rcode == 0) {
00073         m_state = MYNETDNS_OK;
00074     } else {
00075         m_state = MYNETDNS_NOTFOUND;
00076     }
00077 }
00078 
00079 int DNSClient::response(uint8_t buf[], int size) {
00080     int rcode = buf[3] & 0x0f;
00081     if (rcode != 0) {
00082         return rcode;
00083     }
00084     int qdcount = buf[4]<<8|buf[5];
00085     int ancount = buf[6]<<8|buf[7];
00086     int pos = 12;
00087     while(qdcount-- > 0) {
00088         dnsname qname(buf);
00089         pos = qname.decode(pos); // qname
00090         pos += 4; // qtype qclass
00091     }
00092     while(ancount-- > 0) {
00093         dnsname name(buf);
00094         pos = name.decode(pos); // name
00095         int type = buf[pos]<<8|buf[pos+1];
00096         pos += 8; // type class TTL  
00097         int rdlength = buf[pos]<<8|buf[pos+1]; pos += 2;
00098         int rdata_pos = pos;
00099         pos += rdlength;
00100         if (type == 1) { // A record
00101             m_ip = (buf[rdata_pos]<<24) | (buf[rdata_pos+1]<<16) | (buf[rdata_pos+2]<<8) | buf[rdata_pos+3];
00102             sprintf(m_ipaddr, "%d.%d.%d.%d", buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]);
00103         }
00104 #if DBG_DNS
00105         printf("%s", name.str.c_str());
00106         if (type == 1) {
00107             printf(" A %d.%d.%d.%d\n", 
00108                 buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]);
00109         } else if (type == 5) {
00110             dnsname rdname(buf);
00111             rdname.decode(rdata_pos);
00112             printf(" CNAME %s\n", rdname.str.c_str());
00113         } else {
00114             printf(" TYPE:%d", type);
00115             printfBytes(" RDATA:", &buf[rdata_pos], rdlength);
00116         }
00117 #endif
00118     }
00119     return rcode;
00120 }
00121 
00122 int DNSClient::query(uint8_t buf[], int size, const char* hostname) {
00123     const uint8_t header[] = {
00124         0x00,0x00,0x01,0x00, // id=0x0000 QR=0 rd=1 opcode=0 rcode=0
00125         0x00,0x01,0x00,0x00, // qdcount=1 ancount=0
00126         0x00,0x00,0x00,0x00};// nscount=0 arcount=0 
00127     const uint8_t tail[] = {0x00,0x01,0x00,0x01}; // qtype=A qclass=IN
00128     memcpy(buf, header, sizeof(header));
00129     int t = rand();
00130     m_id[0] = t>>8;
00131     m_id[1] = t;
00132     memcpy(buf, m_id, 2); 
00133     dnsname qname(buf);
00134     int pos = qname.encode(sizeof(header), (char*)hostname);
00135     memcpy(buf+pos, tail, sizeof(tail));
00136     pos += sizeof(tail);
00137     return pos;
00138 }
00139 
00140 void DNSClient::resolve(const char* hostname) {
00141     if (m_udp == NULL) {
00142         m_udp = new UDPSocket;
00143         m_udp->open(m_ns);
00144     }
00145     m_udp->set_blocking(false);
00146     m_udp->bind(rand()&0x7fff);
00147     uint8_t buf[256];                
00148     int size = query(buf, sizeof(buf), hostname);
00149 #if DBG_DNS
00150     printf("hostname:[%s]\n", hostname);
00151     printHex(buf, size);
00152 #endif
00153     m_udp->sendto(theDnsServer, (char*)buf, size);
00154     m_interval.reset();
00155     m_interval.start();
00156 }
00157 
00158 void DNSClient::poll() {
00159 #if DBG_DNS
00160     printf("%p m_state: %d, m_udp: %p\n", this, m_state, m_udp);
00161     wait_ms(400);
00162 #endif
00163     switch(m_state) {
00164         case MYNETDNS_START:
00165             m_retry = 0;
00166             resolve(m_hostname);
00167             m_state = MYNETDNS_PROCESSING;
00168             break;
00169         case MYNETDNS_PROCESSING: 
00170             break;
00171         case MYNETDNS_NOTFOUND: 
00172             break;
00173         case MYNETDNS_ERROR: 
00174             break;
00175         case MYNETDNS_OK:
00176             DBG2("m_retry=%d, m_interval=%d\n", m_retry, m_interval.read_ms());
00177             break;
00178     }
00179     if (m_interval.read_ms() > 1000) {
00180         m_interval.stop();
00181         DBG2("timeout m_retry=%d\n", m_retry);
00182         if (++m_retry >= 2) {
00183             m_state = MYNETDNS_ERROR;
00184         } else {
00185             resolve(m_hostname);
00186             m_state = MYNETDNS_PROCESSING;
00187         }
00188     }
00189 }
00190 
00191 //tests for a valid IP address, returns 0 if invalid IP address format, returns ip address if valid
00192 static uint32_t
00193 isValidIP(const char* ip) {
00194     int i1, i2, i3, i4;
00195     int len = strlen(ip);
00196 
00197     if (len < 7) return 0;
00198 
00199     //count the number of dots, there must be 3
00200     int dotcount = 0;
00201     for (int i = 0; i < len; i++) {
00202         if (ip[i] == '.' ) dotcount++;
00203     }
00204 
00205     //there must be exactly 3 dots
00206     if (dotcount != 3) return 0;
00207 
00208     sscanf((char*)ip, "%d.%d.%d.%d", &i1, &i2, &i3, &i4);
00209 
00210     if (strlen(ip) <= 16 && (i1 >= 0 && i1 <= 255) && (i2 >= 0 && i2 <= 255) &&
00211             (i3 >= 0 && i3 <= 255) && (i4 >= 0 && i4 <= 255)) {
00212         return ((i1<<24) | (i2<<16) | (i3<<8) | i4);
00213     }
00214     return 0;
00215 }
00216 
00217 bool DNSClient::lookup(const char* hostname) {
00218     m_hostname = hostname;
00219     
00220     uint32_t ip = isValidIP(hostname);
00221 
00222     //check if hostname is an IP address
00223     if (ip > 0) {
00224         //if it is already an IP address just return immediately
00225         m_ip = ip;
00226         strcpy(m_ipaddr, hostname);
00227         m_state = MYNETDNS_OK;
00228         return true;
00229     }
00230     
00231     m_state = MYNETDNS_START;
00232     while(1) {
00233         poll();
00234         callback();
00235         if (m_state != MYNETDNS_PROCESSING) {
00236             break;
00237         } 
00238     }
00239     
00240     if (m_udp) {
00241         delete m_udp;
00242         m_udp = NULL;
00243     }
00244     return m_state == MYNETDNS_OK;
00245 }