Revised to prevent DHCPClient::discover from hanging.

Fork of WIZ820ioInterface by ban4jp -

Committer:
rraab
Date:
Fri Aug 15 19:53:25 2014 +0000
Revision:
9:c1722862c13b
Parent:
5:fb15c35d1e28
Fixed DHCPClient::discover calling rand, which hangs in an infinite loop.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
va009039 5:fb15c35d1e28 1 // DNSClient.cpp 2013/8/27
va009039 5:fb15c35d1e28 2 #include "mbed.h"
va009039 5:fb15c35d1e28 3 #include "mbed_debug.h"
va009039 5:fb15c35d1e28 4 #include "DNSClient.h"
va009039 5:fb15c35d1e28 5 #include "UDPSocket.h"
va009039 5:fb15c35d1e28 6 #include "dnsname.h"
va009039 5:fb15c35d1e28 7 #include "WIZ820io.h"
va009039 5:fb15c35d1e28 8
va009039 5:fb15c35d1e28 9 #define DBG_DNS 0
va009039 5:fb15c35d1e28 10
va009039 5:fb15c35d1e28 11 #if DBG_DNS
va009039 5:fb15c35d1e28 12 #define DBG2(...) do{debug("[DNS]%p %d %s ", this,__LINE__,__PRETTY_FUNCTION__); debug(__VA_ARGS__); } while(0);
va009039 5:fb15c35d1e28 13 #else
va009039 5:fb15c35d1e28 14 #define DBG2(...) while(0);
va009039 5:fb15c35d1e28 15 #endif
va009039 5:fb15c35d1e28 16
va009039 5:fb15c35d1e28 17 DNSClient::DNSClient(const char* hostname) : m_state(MYNETDNS_START), m_udp(NULL) {
va009039 5:fb15c35d1e28 18 m_hostname = hostname;
va009039 5:fb15c35d1e28 19 }
va009039 5:fb15c35d1e28 20
va009039 5:fb15c35d1e28 21 DNSClient::DNSClient(Endpoint* pHost) : m_state(MYNETDNS_START), m_udp(NULL) {
va009039 5:fb15c35d1e28 22 }
va009039 5:fb15c35d1e28 23
va009039 5:fb15c35d1e28 24 DNSClient::~DNSClient() {
va009039 5:fb15c35d1e28 25 if (m_udp) {
va009039 5:fb15c35d1e28 26 delete m_udp;
va009039 5:fb15c35d1e28 27 }
va009039 5:fb15c35d1e28 28 }
va009039 5:fb15c35d1e28 29
va009039 5:fb15c35d1e28 30 void DNSClient::callback()
va009039 5:fb15c35d1e28 31 {
va009039 5:fb15c35d1e28 32 uint8_t buf[512];
va009039 5:fb15c35d1e28 33 Endpoint host;
va009039 5:fb15c35d1e28 34 int len = m_udp->receiveFrom(host, (char*)buf, sizeof(buf));
va009039 5:fb15c35d1e28 35 if (len < 0) {
va009039 5:fb15c35d1e28 36 return;
va009039 5:fb15c35d1e28 37 }
va009039 5:fb15c35d1e28 38 if (memcmp(buf+0, m_id, 2) != 0) { //verify
va009039 5:fb15c35d1e28 39 return;
va009039 5:fb15c35d1e28 40 }
va009039 5:fb15c35d1e28 41 int rcode = response(buf, len);
va009039 5:fb15c35d1e28 42 if (rcode == 0) {
va009039 5:fb15c35d1e28 43 m_state = MYNETDNS_OK;
va009039 5:fb15c35d1e28 44 } else {
va009039 5:fb15c35d1e28 45 m_state = MYNETDNS_NOTFOUND;
va009039 5:fb15c35d1e28 46 }
va009039 5:fb15c35d1e28 47 }
va009039 5:fb15c35d1e28 48
va009039 5:fb15c35d1e28 49 int DNSClient::response(uint8_t buf[], int size) {
va009039 5:fb15c35d1e28 50 int rcode = buf[3] & 0x0f;
va009039 5:fb15c35d1e28 51 if (rcode != 0) {
va009039 5:fb15c35d1e28 52 return rcode;
va009039 5:fb15c35d1e28 53 }
va009039 5:fb15c35d1e28 54 int qdcount = buf[4]<<8|buf[5];
va009039 5:fb15c35d1e28 55 int ancount = buf[6]<<8|buf[7];
va009039 5:fb15c35d1e28 56 int pos = 12;
va009039 5:fb15c35d1e28 57 while(qdcount-- > 0) {
va009039 5:fb15c35d1e28 58 dnsname qname(buf);
va009039 5:fb15c35d1e28 59 pos = qname.decode(pos); // qname
va009039 5:fb15c35d1e28 60 pos += 4; // qtype qclass
va009039 5:fb15c35d1e28 61 }
va009039 5:fb15c35d1e28 62 while(ancount-- > 0) {
va009039 5:fb15c35d1e28 63 dnsname name(buf);
va009039 5:fb15c35d1e28 64 pos = name.decode(pos); // name
va009039 5:fb15c35d1e28 65 int type = buf[pos]<<8|buf[pos+1];
va009039 5:fb15c35d1e28 66 pos += 8; // type class TTL
va009039 5:fb15c35d1e28 67 int rdlength = buf[pos]<<8|buf[pos+1]; pos += 2;
va009039 5:fb15c35d1e28 68 int rdata_pos = pos;
va009039 5:fb15c35d1e28 69 pos += rdlength;
va009039 5:fb15c35d1e28 70 if (type == 1) { // A record
va009039 5:fb15c35d1e28 71 ip = (buf[rdata_pos]<<24) | (buf[rdata_pos+1]<<16) | (buf[rdata_pos+2]<<8) | buf[rdata_pos+3];
va009039 5:fb15c35d1e28 72 }
va009039 5:fb15c35d1e28 73 #if DBG_DNS
va009039 5:fb15c35d1e28 74 printf("%s", name.str.c_str());
va009039 5:fb15c35d1e28 75 if (type == 1) {
va009039 5:fb15c35d1e28 76 printf(" A %d.%d.%d.%d\n",
va009039 5:fb15c35d1e28 77 buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]);
va009039 5:fb15c35d1e28 78 } else if (type == 5) {
va009039 5:fb15c35d1e28 79 dnsname rdname(buf);
va009039 5:fb15c35d1e28 80 rdname.decode(rdata_pos);
va009039 5:fb15c35d1e28 81 printf(" CNAME %s\n", rdname.str.c_str());
va009039 5:fb15c35d1e28 82 } else {
va009039 5:fb15c35d1e28 83 printf(" TYPE:%d", type);
va009039 5:fb15c35d1e28 84 printfBytes(" RDATA:", &buf[rdata_pos], rdlength);
va009039 5:fb15c35d1e28 85 }
va009039 5:fb15c35d1e28 86 #endif
va009039 5:fb15c35d1e28 87 }
va009039 5:fb15c35d1e28 88 return rcode;
va009039 5:fb15c35d1e28 89 }
va009039 5:fb15c35d1e28 90
va009039 5:fb15c35d1e28 91 int DNSClient::query(uint8_t buf[], int size, const char* hostname) {
va009039 5:fb15c35d1e28 92 const uint8_t header[] = {
va009039 5:fb15c35d1e28 93 0x00,0x00,0x01,0x00, // id=0x0000 QR=0 rd=1 opcode=0 rcode=0
va009039 5:fb15c35d1e28 94 0x00,0x01,0x00,0x00, // qdcount=1 ancount=0
va009039 5:fb15c35d1e28 95 0x00,0x00,0x00,0x00};// nscount=0 arcount=0
va009039 5:fb15c35d1e28 96 const uint8_t tail[] = {0x00,0x01,0x00,0x01}; // qtype=A qclass=IN
va009039 5:fb15c35d1e28 97 memcpy(buf, header, sizeof(header));
va009039 5:fb15c35d1e28 98 int t = rand();
va009039 5:fb15c35d1e28 99 m_id[0] = t>>8;
va009039 5:fb15c35d1e28 100 m_id[1] = t;
va009039 5:fb15c35d1e28 101 memcpy(buf, m_id, 2);
va009039 5:fb15c35d1e28 102 dnsname qname(buf);
va009039 5:fb15c35d1e28 103 int pos = qname.encode(sizeof(header), (char*)hostname);
va009039 5:fb15c35d1e28 104 memcpy(buf+pos, tail, sizeof(tail));
va009039 5:fb15c35d1e28 105 pos += sizeof(tail);
va009039 5:fb15c35d1e28 106 return pos;
va009039 5:fb15c35d1e28 107 }
va009039 5:fb15c35d1e28 108
va009039 5:fb15c35d1e28 109 void DNSClient::resolve(const char* hostname) {
va009039 5:fb15c35d1e28 110 if (m_udp == NULL) {
va009039 5:fb15c35d1e28 111 m_udp = new UDPSocket;
va009039 5:fb15c35d1e28 112 }
va009039 5:fb15c35d1e28 113 m_udp->init();
va009039 5:fb15c35d1e28 114 m_udp->set_blocking(false);
va009039 5:fb15c35d1e28 115 Endpoint server;
va009039 5:fb15c35d1e28 116 server.set_address("8.8.8.8", 53); // DNS
va009039 5:fb15c35d1e28 117 m_udp->bind(rand()&0x7fff);
va009039 5:fb15c35d1e28 118 uint8_t buf[256];
va009039 5:fb15c35d1e28 119 int size = query(buf, sizeof(buf), hostname);
va009039 5:fb15c35d1e28 120 #if DBG_DNS
va009039 5:fb15c35d1e28 121 printf("hostname:[%s]\n", hostname);
va009039 5:fb15c35d1e28 122 printHex(buf, size);
va009039 5:fb15c35d1e28 123 #endif
va009039 5:fb15c35d1e28 124 m_udp->sendTo(server, (char*)buf, size);
va009039 5:fb15c35d1e28 125 m_interval.reset();
va009039 5:fb15c35d1e28 126 m_interval.start();
va009039 5:fb15c35d1e28 127 }
va009039 5:fb15c35d1e28 128
va009039 5:fb15c35d1e28 129 void DNSClient::poll() {
va009039 5:fb15c35d1e28 130 #if DBG_DNS
va009039 5:fb15c35d1e28 131 printf("%p m_state: %d, m_udp: %p\n", this, m_state, m_udp);
va009039 5:fb15c35d1e28 132 wait_ms(400);
va009039 5:fb15c35d1e28 133 #endif
va009039 5:fb15c35d1e28 134 switch(m_state) {
va009039 5:fb15c35d1e28 135 case MYNETDNS_START:
va009039 5:fb15c35d1e28 136 m_retry = 0;
va009039 5:fb15c35d1e28 137 resolve(m_hostname);
va009039 5:fb15c35d1e28 138 m_state = MYNETDNS_PROCESSING;
va009039 5:fb15c35d1e28 139 break;
va009039 5:fb15c35d1e28 140 case MYNETDNS_PROCESSING:
va009039 5:fb15c35d1e28 141 break;
va009039 5:fb15c35d1e28 142 case MYNETDNS_NOTFOUND:
va009039 5:fb15c35d1e28 143 break;
va009039 5:fb15c35d1e28 144 case MYNETDNS_ERROR:
va009039 5:fb15c35d1e28 145 break;
va009039 5:fb15c35d1e28 146 case MYNETDNS_OK:
va009039 5:fb15c35d1e28 147 DBG2("m_retry=%d, m_interval=%d\n", m_retry, m_interval.read_ms());
va009039 5:fb15c35d1e28 148 break;
va009039 5:fb15c35d1e28 149 }
va009039 5:fb15c35d1e28 150 if (m_interval.read_ms() > 1000) {
va009039 5:fb15c35d1e28 151 m_interval.stop();
va009039 5:fb15c35d1e28 152 DBG2("timeout m_retry=%d\n", m_retry);
va009039 5:fb15c35d1e28 153 if (++m_retry >= 2) {
va009039 5:fb15c35d1e28 154 m_state = MYNETDNS_ERROR;
va009039 5:fb15c35d1e28 155 } else {
va009039 5:fb15c35d1e28 156 resolve(m_hostname);
va009039 5:fb15c35d1e28 157 m_state = MYNETDNS_PROCESSING;
va009039 5:fb15c35d1e28 158 }
va009039 5:fb15c35d1e28 159 }
va009039 5:fb15c35d1e28 160 }
va009039 5:fb15c35d1e28 161
va009039 5:fb15c35d1e28 162 bool DNSClient::lookup(const char* hostname) {
va009039 5:fb15c35d1e28 163 m_hostname = hostname;
va009039 5:fb15c35d1e28 164 m_state = MYNETDNS_START;
va009039 5:fb15c35d1e28 165 while(1) {
va009039 5:fb15c35d1e28 166 poll();
va009039 5:fb15c35d1e28 167 callback();
va009039 5:fb15c35d1e28 168 if (m_state != MYNETDNS_PROCESSING) {
va009039 5:fb15c35d1e28 169 break;
va009039 5:fb15c35d1e28 170 }
va009039 5:fb15c35d1e28 171 }
va009039 5:fb15c35d1e28 172 return m_state == MYNETDNS_OK;
va009039 5:fb15c35d1e28 173 }