Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: http-webserver-example mbed-os-example-sockets
Fork of W5500Interface by
Diff: DNSClient/DNSClient.cpp
- Revision:
- 6:e2ab76b2be07
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/DNSClient/DNSClient.cpp Thu Aug 09 08:10:27 2018 +0000
@@ -0,0 +1,245 @@
+// DNSClient.cpp 2013/8/27
+#include "mbed.h"
+#include "mbed_debug.h"
+#include "DNSClient.h"
+#include "UDPSocket.h"
+#include "dnsname.h"
+#include "wiznet.h"
+
+#if DBG_DNS
+#define DBG2(...) do{debug("[DNS]%p %d %s ", this,__LINE__,__PRETTY_FUNCTION__); debug(__VA_ARGS__); } while(0);
+#else
+#define DBG2(...) while(0);
+#endif
+
+static SocketAddress theDnsServer;
+
+DNSClient::DNSClient() : m_state(MYNETDNS_START), m_udp(NULL) {
+ m_ns = NULL;
+
+ //default to google
+ theDnsServer.set_ip_address("8.8.8.8"); // DNS
+ theDnsServer.set_port(53); // DNS
+}
+
+DNSClient::DNSClient(NetworkStack *ns, const char* hostname) : m_state(MYNETDNS_START), m_udp(NULL) {
+ m_hostname = hostname;
+ m_ns = ns;
+
+ //default to google
+ theDnsServer.set_ip_address("8.8.8.8"); // DNS
+ theDnsServer.set_port(53); // DNS
+}
+
+DNSClient::DNSClient(NetworkStack *ns, SocketAddress* pHost) : m_state(MYNETDNS_START), m_udp(NULL) {
+ m_ns = ns;
+
+ //default to google
+ theDnsServer.set_ip_address("8.8.8.8"); // DNS
+ theDnsServer.set_port(53); // DNS
+}
+
+DNSClient::~DNSClient() {
+ if (m_udp) {
+ delete m_udp;
+ }
+}
+
+int DNSClient::setup(NetworkStack *ns) {
+ m_ns = ns;
+ return 0;
+}
+
+bool DNSClient::set_server(const char* serverip, int port) {
+ theDnsServer.set_ip_address(serverip);
+ theDnsServer.set_port(port);
+ return true;
+}
+
+void DNSClient::callback()
+{
+ uint8_t buf[512];
+ SocketAddress host;
+ int len = m_udp->recvfrom(&host, (char*)buf, sizeof(buf));
+ if (len < 0) {
+ return;
+ }
+ if (memcmp(buf+0, m_id, 2) != 0) { //verify
+ return;
+ }
+
+ int rcode = response(buf, len);
+ if (rcode == 0) {
+ m_state = MYNETDNS_OK;
+ } else {
+ m_state = MYNETDNS_NOTFOUND;
+ }
+}
+
+int DNSClient::response(uint8_t buf[], int size) {
+ int rcode = buf[3] & 0x0f;
+ if (rcode != 0) {
+ return rcode;
+ }
+ int qdcount = buf[4]<<8|buf[5];
+ int ancount = buf[6]<<8|buf[7];
+ int pos = 12;
+ while(qdcount-- > 0) {
+ dnsname qname(buf);
+ pos = qname.decode(pos); // qname
+ pos += 4; // qtype qclass
+ }
+ while(ancount-- > 0) {
+ dnsname name(buf);
+ pos = name.decode(pos); // name
+ int type = buf[pos]<<8|buf[pos+1];
+ pos += 8; // type class TTL
+ int rdlength = buf[pos]<<8|buf[pos+1]; pos += 2;
+ int rdata_pos = pos;
+ pos += rdlength;
+ if (type == 1) { // A record
+ m_ip = (buf[rdata_pos]<<24) | (buf[rdata_pos+1]<<16) | (buf[rdata_pos+2]<<8) | buf[rdata_pos+3];
+ sprintf(m_ipaddr, "%d.%d.%d.%d", buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]);
+ }
+#if DBG_DNS
+ printf("%s", name.str.c_str());
+ if (type == 1) {
+ printf(" A %d.%d.%d.%d\n",
+ buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]);
+ } else if (type == 5) {
+ dnsname rdname(buf);
+ rdname.decode(rdata_pos);
+ printf(" CNAME %s\n", rdname.str.c_str());
+ } else {
+ printf(" TYPE:%d", type);
+ printfBytes(" RDATA:", &buf[rdata_pos], rdlength);
+ }
+#endif
+ }
+ return rcode;
+}
+
+int DNSClient::query(uint8_t buf[], int size, const char* hostname) {
+ const uint8_t header[] = {
+ 0x00,0x00,0x01,0x00, // id=0x0000 QR=0 rd=1 opcode=0 rcode=0
+ 0x00,0x01,0x00,0x00, // qdcount=1 ancount=0
+ 0x00,0x00,0x00,0x00};// nscount=0 arcount=0
+ const uint8_t tail[] = {0x00,0x01,0x00,0x01}; // qtype=A qclass=IN
+ memcpy(buf, header, sizeof(header));
+ int t = rand();
+ m_id[0] = t>>8;
+ m_id[1] = t;
+ memcpy(buf, m_id, 2);
+ dnsname qname(buf);
+ int pos = qname.encode(sizeof(header), (char*)hostname);
+ memcpy(buf+pos, tail, sizeof(tail));
+ pos += sizeof(tail);
+ return pos;
+}
+
+void DNSClient::resolve(const char* hostname) {
+ if (m_udp == NULL) {
+ m_udp = new UDPSocket;
+ m_udp->open(m_ns);
+ }
+ m_udp->set_blocking(false);
+ m_udp->bind(rand()&0x7fff);
+ uint8_t buf[256];
+ int size = query(buf, sizeof(buf), hostname);
+#if DBG_DNS
+ printf("hostname:[%s]\n", hostname);
+ printHex(buf, size);
+#endif
+ m_udp->sendto(theDnsServer, (char*)buf, size);
+ m_interval.reset();
+ m_interval.start();
+}
+
+void DNSClient::poll() {
+#if DBG_DNS
+ printf("%p m_state: %d, m_udp: %p\n", this, m_state, m_udp);
+ wait_ms(400);
+#endif
+ switch(m_state) {
+ case MYNETDNS_START:
+ m_retry = 0;
+ resolve(m_hostname);
+ m_state = MYNETDNS_PROCESSING;
+ break;
+ case MYNETDNS_PROCESSING:
+ break;
+ case MYNETDNS_NOTFOUND:
+ break;
+ case MYNETDNS_ERROR:
+ break;
+ case MYNETDNS_OK:
+ DBG2("m_retry=%d, m_interval=%d\n", m_retry, m_interval.read_ms());
+ break;
+ }
+ if (m_interval.read_ms() > 1000) {
+ m_interval.stop();
+ DBG2("timeout m_retry=%d\n", m_retry);
+ if (++m_retry >= 2) {
+ m_state = MYNETDNS_ERROR;
+ } else {
+ resolve(m_hostname);
+ m_state = MYNETDNS_PROCESSING;
+ }
+ }
+}
+
+//tests for a valid IP address, returns 0 if invalid IP address format, returns ip address if valid
+static uint32_t
+isValidIP(const char* ip) {
+ int i1, i2, i3, i4;
+ int len = strlen(ip);
+
+ if (len < 7) return 0;
+
+ //count the number of dots, there must be 3
+ int dotcount = 0;
+ for (int i = 0; i < len; i++) {
+ if (ip[i] == '.' ) dotcount++;
+ }
+
+ //there must be exactly 3 dots
+ if (dotcount != 3) return 0;
+
+ sscanf((char*)ip, "%d.%d.%d.%d", &i1, &i2, &i3, &i4);
+
+ if (strlen(ip) <= 16 && (i1 >= 0 && i1 <= 255) && (i2 >= 0 && i2 <= 255) &&
+ (i3 >= 0 && i3 <= 255) && (i4 >= 0 && i4 <= 255)) {
+ return ((i1<<24) | (i2<<16) | (i3<<8) | i4);
+ }
+ return 0;
+}
+
+bool DNSClient::lookup(const char* hostname) {
+ m_hostname = hostname;
+
+ uint32_t ip = isValidIP(hostname);
+
+ //check if hostname is an IP address
+ if (ip > 0) {
+ //if it is already an IP address just return immediately
+ m_ip = ip;
+ strcpy(m_ipaddr, hostname);
+ m_state = MYNETDNS_OK;
+ return true;
+ }
+
+ m_state = MYNETDNS_START;
+ while(1) {
+ poll();
+ callback();
+ if (m_state != MYNETDNS_PROCESSING) {
+ break;
+ }
+ }
+
+ if (m_udp) {
+ delete m_udp;
+ m_udp = NULL;
+ }
+ return m_state == MYNETDNS_OK;
+}
