Mbed library for ENC28J60 Ethernet modules. Full support for TCP/IP and UDP Server, Client and HTTP server (webserver). DHCP and DNS is included.

Dependents:   mBuino_ENC28_MQTT Nucleo_Web_ENC28J60 Nucleo_Web_ENC28J60_ADC Serial_over_Ethernet ... more

Library for ENC28J60 Ethernet modules.

/media/uploads/hudakz/enc28j60_module01.jpg

Ported to mbed from Norbert Truchsess's UIPEthernet library for Arduino. Thank you Norbert!

  • Full support for persistent (streaming) TCP/IP and UDP connections Client and Server each, ARP, ICMP, DHCP and DNS.
  • Works with both Mbed OS 2 and Mbed OS 5.

Usage:

  • Import the library into your project.
  • Add #include "UipEthernet.h" to main.cpp
  • Create one instance of the UipEthernet class initialized with the MAC address you'd like to use and SPI pins of the connected Mbed board.

Example programs:

Import programWebSwitch_ENC28J60

HTTP Server serving a simple webpage which enables to remotely turn a digital output on/off. Compile, download, run and type 'IP_address/secret/' (don't forget the last '/') into your web browser and hit ENTER.

Import programHTTPServer_Echo_ENC28J60

A simple HTTP server echoing received requests. Ethernet connection is over an ENC28J60 board. Usage: Type the server's IP address into you web browser and hit <ENTER>.

Import programTcpServer_ENC28J60

Simple TCP/IP Server using the UIPEthernet library for ENC28J60 Ethernet boards.

Import programTcpClient_ENC28J60

Simple TCP/IP Client using the UIPEthernet library for ENC28J60 Ethernet boards.

Import programUdpServer_ENC28J60

Simple UDP Server using the UIPEthernet library for ENC28J60 Ethernet boards.

Import programUdpClient_ENC28J60

Simple UDP Client using the UIPEthernet library for ENC28J60 Ethernet boards.

Import programMQTT_Hello_ENC28J60

MQTT Client example program. Ethernet connection is via an ENC28J60 module.

Committer:
hudakz
Date:
Sun Mar 08 20:26:56 2015 +0000
Revision:
4:d774541a34da
Parent:
2:049ce85163c5
Child:
7:1bc7e6120801
Version 1.09 (fixed leaking client-data caused by race-condition on remote close)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 4:d774541a34da 1 // Arduino DNS client for Enc28J60-based Ethernet shield
hudakz 0:5350a66d5279 2 // (c) Copyright 2009-2010 MCQN Ltd.
hudakz 0:5350a66d5279 3 // Released under Apache License, version 2.0
hudakz 4:d774541a34da 4 #include "Udp.h"
hudakz 4:d774541a34da 5 #include "utility/util.h"
hudakz 4:d774541a34da 6 #include "utility/millis.h"
hudakz 0:5350a66d5279 7
hudakz 0:5350a66d5279 8 #include "Dns.h"
hudakz 0:5350a66d5279 9 #include <string.h>
hudakz 0:5350a66d5279 10 //#include <stdlib.h>
hudakz 0:5350a66d5279 11
hudakz 4:d774541a34da 12 #include <mbed.h>
hudakz 0:5350a66d5279 13
hudakz 0:5350a66d5279 14 #define SOCKET_NONE 255
hudakz 0:5350a66d5279 15 // Various flags and header field values for a DNS message
hudakz 0:5350a66d5279 16
hudakz 0:5350a66d5279 17 #define UDP_HEADER_SIZE 8
hudakz 0:5350a66d5279 18 #define DNS_HEADER_SIZE 12
hudakz 0:5350a66d5279 19 #define TTL_SIZE 4
hudakz 0:5350a66d5279 20 #define QUERY_FLAG (0)
hudakz 0:5350a66d5279 21 #define RESPONSE_FLAG (1 << 15)
hudakz 0:5350a66d5279 22 #define QUERY_RESPONSE_MASK (1 << 15)
hudakz 0:5350a66d5279 23 #define OPCODE_STANDARD_QUERY (0)
hudakz 0:5350a66d5279 24 #define OPCODE_INVERSE_QUERY (1 << 11)
hudakz 0:5350a66d5279 25 #define OPCODE_STATUS_REQUEST (2 << 11)
hudakz 0:5350a66d5279 26 #define OPCODE_MASK (15 << 11)
hudakz 0:5350a66d5279 27 #define AUTHORITATIVE_FLAG (1 << 10)
hudakz 0:5350a66d5279 28 #define TRUNCATION_FLAG (1 << 9)
hudakz 0:5350a66d5279 29 #define RECURSION_DESIRED_FLAG (1 << 8)
hudakz 0:5350a66d5279 30 #define RECURSION_AVAILABLE_FLAG (1 << 7)
hudakz 0:5350a66d5279 31 #define RESP_NO_ERROR (0)
hudakz 0:5350a66d5279 32 #define RESP_FORMAT_ERROR (1)
hudakz 0:5350a66d5279 33 #define RESP_SERVER_FAILURE (2)
hudakz 0:5350a66d5279 34 #define RESP_NAME_ERROR (3)
hudakz 0:5350a66d5279 35 #define RESP_NOT_IMPLEMENTED (4)
hudakz 0:5350a66d5279 36 #define RESP_REFUSED (5)
hudakz 0:5350a66d5279 37 #define RESP_MASK (15)
hudakz 0:5350a66d5279 38 #define TYPE_A (0x0001)
hudakz 0:5350a66d5279 39 #define CLASS_IN (0x0001)
hudakz 0:5350a66d5279 40 #define LABEL_COMPRESSION_MASK (0xC0)
hudakz 0:5350a66d5279 41 // Port number that DNS servers listen on
hudakz 0:5350a66d5279 42
hudakz 0:5350a66d5279 43 #define DNS_PORT 53
hudakz 0:5350a66d5279 44
hudakz 0:5350a66d5279 45 // Possible return codes from ProcessResponse
hudakz 0:5350a66d5279 46
hudakz 4:d774541a34da 47 #define SUCCESS 1
hudakz 4:d774541a34da 48 #define TIMED_OUT -1
hudakz 4:d774541a34da 49 #define INVALID_SERVER -2
hudakz 4:d774541a34da 50 #define TRUNCATED -3
hudakz 4:d774541a34da 51 #define INVALID_RESPONSE -4
hudakz 0:5350a66d5279 52
hudakz 0:5350a66d5279 53 /**
hudakz 0:5350a66d5279 54 * @brief
hudakz 0:5350a66d5279 55 * @note
hudakz 0:5350a66d5279 56 * @param
hudakz 0:5350a66d5279 57 * @retval
hudakz 0:5350a66d5279 58 */
hudakz 4:d774541a34da 59
hudakz 0:5350a66d5279 60 void DNSClient::begin(const IPAddress& aDNSServer) {
hudakz 0:5350a66d5279 61 iDNSServer = aDNSServer;
hudakz 0:5350a66d5279 62 iRequestId = 0;
hudakz 0:5350a66d5279 63 }
hudakz 0:5350a66d5279 64
hudakz 0:5350a66d5279 65 /**
hudakz 0:5350a66d5279 66 * @brief
hudakz 0:5350a66d5279 67 * @note
hudakz 0:5350a66d5279 68 * @param
hudakz 0:5350a66d5279 69 * @retval
hudakz 0:5350a66d5279 70 */
hudakz 0:5350a66d5279 71 int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) {
hudakz 0:5350a66d5279 72
hudakz 0:5350a66d5279 73 // See if we've been given a valid IP address
hudakz 0:5350a66d5279 74 const char* p = aIPAddrString;
hudakz 0:5350a66d5279 75 while(*p && ((*p == '.') || (*p >= '0') || (*p <= '9'))) {
hudakz 0:5350a66d5279 76 p++;
hudakz 0:5350a66d5279 77 }
hudakz 0:5350a66d5279 78
hudakz 0:5350a66d5279 79 if(*p == '\0') {
hudakz 0:5350a66d5279 80
hudakz 0:5350a66d5279 81 // It's looking promising, we haven't found any invalid characters
hudakz 0:5350a66d5279 82 p = aIPAddrString;
hudakz 0:5350a66d5279 83
hudakz 0:5350a66d5279 84 int segment = 0;
hudakz 0:5350a66d5279 85 int segmentValue = 0;
hudakz 0:5350a66d5279 86 while(*p && (segment < 4)) {
hudakz 0:5350a66d5279 87 if(*p == '.') {
hudakz 0:5350a66d5279 88
hudakz 0:5350a66d5279 89 // We've reached the end of a segment
hudakz 0:5350a66d5279 90 if(segmentValue > 255) {
hudakz 0:5350a66d5279 91
hudakz 0:5350a66d5279 92 // You can't have IP address segments that don't fit in a byte
hudakz 0:5350a66d5279 93 return 0;
hudakz 0:5350a66d5279 94 }
hudakz 0:5350a66d5279 95 else {
hudakz 0:5350a66d5279 96 aResult[segment] = (uint8_t) segmentValue;
hudakz 0:5350a66d5279 97 segment++;
hudakz 0:5350a66d5279 98 segmentValue = 0;
hudakz 0:5350a66d5279 99 }
hudakz 0:5350a66d5279 100 }
hudakz 0:5350a66d5279 101 else {
hudakz 0:5350a66d5279 102
hudakz 0:5350a66d5279 103 // Next digit
hudakz 0:5350a66d5279 104 segmentValue = (segmentValue * 10) + (*p - '0');
hudakz 0:5350a66d5279 105 }
hudakz 0:5350a66d5279 106
hudakz 0:5350a66d5279 107 p++;
hudakz 0:5350a66d5279 108 }
hudakz 0:5350a66d5279 109
hudakz 0:5350a66d5279 110 // We've reached the end of address, but there'll still be the last
hudakz 0:5350a66d5279 111 // segment to deal with
hudakz 0:5350a66d5279 112 if((segmentValue > 255) || (segment > 3)) {
hudakz 0:5350a66d5279 113
hudakz 0:5350a66d5279 114 // You can't have IP address segments that don't fit in a byte,
hudakz 0:5350a66d5279 115 // or more than four segments
hudakz 0:5350a66d5279 116 return 0;
hudakz 0:5350a66d5279 117 }
hudakz 0:5350a66d5279 118 else {
hudakz 0:5350a66d5279 119 aResult[segment] = (uint8_t) segmentValue;
hudakz 0:5350a66d5279 120 return 1;
hudakz 0:5350a66d5279 121 }
hudakz 0:5350a66d5279 122 }
hudakz 0:5350a66d5279 123 else {
hudakz 0:5350a66d5279 124 return 0;
hudakz 0:5350a66d5279 125 }
hudakz 0:5350a66d5279 126 }
hudakz 0:5350a66d5279 127
hudakz 0:5350a66d5279 128 /**
hudakz 0:5350a66d5279 129 * @brief
hudakz 0:5350a66d5279 130 * @note
hudakz 0:5350a66d5279 131 * @param
hudakz 0:5350a66d5279 132 * @retval
hudakz 0:5350a66d5279 133 */
hudakz 0:5350a66d5279 134 int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) {
hudakz 0:5350a66d5279 135 int ret = 0;
hudakz 0:5350a66d5279 136
hudakz 0:5350a66d5279 137 // See if it's a numeric IP address
hudakz 0:5350a66d5279 138
hudakz 0:5350a66d5279 139 if(inet_aton(aHostname, aResult)) {
hudakz 0:5350a66d5279 140
hudakz 0:5350a66d5279 141 // It is, our work here is done
hudakz 0:5350a66d5279 142 return 1;
hudakz 0:5350a66d5279 143 }
hudakz 0:5350a66d5279 144
hudakz 0:5350a66d5279 145 // Check we've got a valid DNS server to use
hudakz 0:5350a66d5279 146 if(iDNSServer == INADDR_NONE) {
hudakz 0:5350a66d5279 147 return INVALID_SERVER;
hudakz 0:5350a66d5279 148 }
hudakz 0:5350a66d5279 149
hudakz 0:5350a66d5279 150 // Find a socket to use
hudakz 4:d774541a34da 151 if(iUdp.begin(1024 + (millis() & 0xF)) == 1) {
hudakz 0:5350a66d5279 152
hudakz 0:5350a66d5279 153 // Try up to three times
hudakz 0:5350a66d5279 154 int retries = 0;
hudakz 0:5350a66d5279 155 // while ((retries < 3) && (ret <= 0))
hudakz 0:5350a66d5279 156 {
hudakz 0:5350a66d5279 157 // Send DNS request
hudakz 0:5350a66d5279 158 ret = iUdp.beginPacket(iDNSServer, DNS_PORT);
hudakz 0:5350a66d5279 159 if(ret != 0) {
hudakz 0:5350a66d5279 160
hudakz 0:5350a66d5279 161 // Now output the request data
hudakz 0:5350a66d5279 162 ret = BuildRequest(aHostname);
hudakz 0:5350a66d5279 163 if(ret != 0) {
hudakz 0:5350a66d5279 164
hudakz 0:5350a66d5279 165 // And finally send the request
hudakz 0:5350a66d5279 166 ret = iUdp.endPacket();
hudakz 0:5350a66d5279 167 if(ret != 0) {
hudakz 0:5350a66d5279 168
hudakz 0:5350a66d5279 169 // Now wait for a response
hudakz 0:5350a66d5279 170 int wait_retries = 0;
hudakz 0:5350a66d5279 171 ret = TIMED_OUT;
hudakz 0:5350a66d5279 172 while((wait_retries < 3) && (ret == TIMED_OUT)) {
hudakz 0:5350a66d5279 173 ret = ProcessResponse(5000, aResult);
hudakz 0:5350a66d5279 174 wait_retries++;
hudakz 0:5350a66d5279 175 }
hudakz 0:5350a66d5279 176 }
hudakz 0:5350a66d5279 177 }
hudakz 0:5350a66d5279 178 }
hudakz 0:5350a66d5279 179
hudakz 0:5350a66d5279 180 retries++;
hudakz 0:5350a66d5279 181 }
hudakz 0:5350a66d5279 182
hudakz 0:5350a66d5279 183 // We're done with the socket now
hudakz 0:5350a66d5279 184 iUdp.stop();
hudakz 0:5350a66d5279 185 }
hudakz 0:5350a66d5279 186
hudakz 0:5350a66d5279 187 return ret;
hudakz 0:5350a66d5279 188 }
hudakz 0:5350a66d5279 189
hudakz 0:5350a66d5279 190 /**
hudakz 0:5350a66d5279 191 * @brief
hudakz 0:5350a66d5279 192 * @note
hudakz 0:5350a66d5279 193 * @param
hudakz 0:5350a66d5279 194 * @retval
hudakz 0:5350a66d5279 195 */
hudakz 0:5350a66d5279 196 uint16_t DNSClient::BuildRequest(const char* aName) {
hudakz 0:5350a66d5279 197
hudakz 0:5350a66d5279 198 // Build header
hudakz 0:5350a66d5279 199
hudakz 0:5350a66d5279 200 // 1 1 1 1 1 1
hudakz 0:5350a66d5279 201 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
hudakz 0:5350a66d5279 202 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
hudakz 0:5350a66d5279 203 // | ID |
hudakz 0:5350a66d5279 204 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
hudakz 0:5350a66d5279 205 // |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
hudakz 0:5350a66d5279 206 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
hudakz 0:5350a66d5279 207 // | QDCOUNT |
hudakz 0:5350a66d5279 208 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
hudakz 0:5350a66d5279 209 // | ANCOUNT |
hudakz 0:5350a66d5279 210 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
hudakz 0:5350a66d5279 211 // | NSCOUNT |
hudakz 0:5350a66d5279 212 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
hudakz 0:5350a66d5279 213 // | ARCOUNT |
hudakz 0:5350a66d5279 214 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
hudakz 0:5350a66d5279 215 // As we only support one request at a time at present, we can simplify
hudakz 0:5350a66d5279 216 // some of this header
hudakz 4:d774541a34da 217 iRequestId = millis(); // generate a random ID
hudakz 0:5350a66d5279 218 uint16_t twoByteBuffer;
hudakz 0:5350a66d5279 219
hudakz 0:5350a66d5279 220 // FIXME We should also check that there's enough space available to write to, rather
hudakz 0:5350a66d5279 221
hudakz 0:5350a66d5279 222 // FIXME than assume there's enough space (as the code does at present)
hudakz 0:5350a66d5279 223 iUdp.write((uint8_t*) &iRequestId, sizeof(iRequestId));
hudakz 0:5350a66d5279 224
hudakz 0:5350a66d5279 225 twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG);
hudakz 0:5350a66d5279 226 iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer));
hudakz 0:5350a66d5279 227
hudakz 0:5350a66d5279 228 twoByteBuffer = htons(1); // One question record
hudakz 0:5350a66d5279 229 iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer));
hudakz 0:5350a66d5279 230
hudakz 0:5350a66d5279 231 twoByteBuffer = 0; // Zero answer records
hudakz 0:5350a66d5279 232 iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer));
hudakz 0:5350a66d5279 233
hudakz 0:5350a66d5279 234 iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer));
hudakz 0:5350a66d5279 235
hudakz 0:5350a66d5279 236 // and zero additional records
hudakz 0:5350a66d5279 237 iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer));
hudakz 0:5350a66d5279 238
hudakz 0:5350a66d5279 239 // Build question
hudakz 0:5350a66d5279 240 const char* start = aName;
hudakz 0:5350a66d5279 241 const char* end = start;
hudakz 0:5350a66d5279 242 uint8_t len;
hudakz 0:5350a66d5279 243 // Run through the name being requested
hudakz 0:5350a66d5279 244
hudakz 0:5350a66d5279 245 while(*end) {
hudakz 0:5350a66d5279 246
hudakz 0:5350a66d5279 247 // Find out how long this section of the name is
hudakz 0:5350a66d5279 248 end = start;
hudakz 0:5350a66d5279 249 while(*end && (*end != '.')) {
hudakz 0:5350a66d5279 250 end++;
hudakz 0:5350a66d5279 251 }
hudakz 0:5350a66d5279 252
hudakz 0:5350a66d5279 253 if(end - start > 0) {
hudakz 0:5350a66d5279 254
hudakz 0:5350a66d5279 255 // Write out the size of this section
hudakz 0:5350a66d5279 256 len = end - start;
hudakz 0:5350a66d5279 257 iUdp.write(&len, sizeof(len));
hudakz 0:5350a66d5279 258
hudakz 0:5350a66d5279 259 // And then write out the section
hudakz 0:5350a66d5279 260 iUdp.write((uint8_t*)start, end - start);
hudakz 0:5350a66d5279 261 }
hudakz 0:5350a66d5279 262
hudakz 0:5350a66d5279 263 start = end + 1;
hudakz 0:5350a66d5279 264 }
hudakz 0:5350a66d5279 265
hudakz 0:5350a66d5279 266 // We've got to the end of the question name, so
hudakz 0:5350a66d5279 267 // terminate it with a zero-length section
hudakz 0:5350a66d5279 268 len = 0;
hudakz 0:5350a66d5279 269 iUdp.write(&len, sizeof(len));
hudakz 0:5350a66d5279 270
hudakz 0:5350a66d5279 271 // Finally the type and class of question
hudakz 0:5350a66d5279 272 twoByteBuffer = htons(TYPE_A);
hudakz 0:5350a66d5279 273 iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer));
hudakz 0:5350a66d5279 274
hudakz 0:5350a66d5279 275 twoByteBuffer = htons(CLASS_IN); // Internet class of question
hudakz 0:5350a66d5279 276 iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer));
hudakz 0:5350a66d5279 277
hudakz 0:5350a66d5279 278 // Success! Everything buffered okay
hudakz 0:5350a66d5279 279 return 1;
hudakz 0:5350a66d5279 280 }
hudakz 0:5350a66d5279 281
hudakz 0:5350a66d5279 282 /**
hudakz 0:5350a66d5279 283 * @brief
hudakz 0:5350a66d5279 284 * @note
hudakz 0:5350a66d5279 285 * @param
hudakz 0:5350a66d5279 286 * @retval
hudakz 0:5350a66d5279 287 */
hudakz 0:5350a66d5279 288 uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress) {
hudakz 4:d774541a34da 289 uint32_t startTime = millis();
hudakz 0:5350a66d5279 290
hudakz 0:5350a66d5279 291 // Wait for a response packet
hudakz 0:5350a66d5279 292
hudakz 0:5350a66d5279 293 while(iUdp.parsePacket() <= 0) {
hudakz 4:d774541a34da 294 if((millis() - startTime) > aTimeout)
hudakz 0:5350a66d5279 295 return TIMED_OUT;
hudakz 0:5350a66d5279 296 wait(0.050);
hudakz 0:5350a66d5279 297 }
hudakz 0:5350a66d5279 298
hudakz 0:5350a66d5279 299 // We've had a reply!
hudakz 0:5350a66d5279 300 // Read the UDP header
hudakz 0:5350a66d5279 301 uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header
hudakz 0:5350a66d5279 302
hudakz 0:5350a66d5279 303 // Check that it's a response from the right server and the right port
hudakz 0:5350a66d5279 304 if((iDNSServer != iUdp.remoteIP()) || (iUdp.remotePort() != DNS_PORT)) {
hudakz 0:5350a66d5279 305
hudakz 0:5350a66d5279 306 // It's not from who we expected
hudakz 0:5350a66d5279 307 return INVALID_SERVER;
hudakz 0:5350a66d5279 308 }
hudakz 0:5350a66d5279 309
hudakz 0:5350a66d5279 310 // Read through the rest of the response
hudakz 0:5350a66d5279 311 if(iUdp.available() < DNS_HEADER_SIZE) {
hudakz 0:5350a66d5279 312 return TRUNCATED;
hudakz 0:5350a66d5279 313 }
hudakz 0:5350a66d5279 314
hudakz 0:5350a66d5279 315 iUdp.read(header, DNS_HEADER_SIZE);
hudakz 0:5350a66d5279 316
hudakz 0:5350a66d5279 317 uint16_t header_flags = htons(*((uint16_t*) &header[2]));
hudakz 0:5350a66d5279 318 // Check that it's a response to this request
hudakz 0:5350a66d5279 319
hudakz 0:5350a66d5279 320 if
hudakz 0:5350a66d5279 321 (
hudakz 0:5350a66d5279 322 (iRequestId != (*((uint16_t*) &header[0])))
hudakz 0:5350a66d5279 323 || ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t) RESPONSE_FLAG)
hudakz 0:5350a66d5279 324 ) {
hudakz 0:5350a66d5279 325
hudakz 0:5350a66d5279 326 // Mark the entire packet as read
hudakz 0:5350a66d5279 327 iUdp.flush();
hudakz 0:5350a66d5279 328 return INVALID_RESPONSE;
hudakz 0:5350a66d5279 329 }
hudakz 0:5350a66d5279 330
hudakz 0:5350a66d5279 331 // Check for any errors in the response (or in our request)
hudakz 0:5350a66d5279 332 // although we don't do anything to get round these
hudakz 0:5350a66d5279 333 if((header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK)) {
hudakz 0:5350a66d5279 334
hudakz 0:5350a66d5279 335 // Mark the entire packet as read
hudakz 0:5350a66d5279 336 iUdp.flush();
hudakz 0:5350a66d5279 337 return -5; //INVALID_RESPONSE;
hudakz 0:5350a66d5279 338 }
hudakz 0:5350a66d5279 339
hudakz 0:5350a66d5279 340 // And make sure we've got (at least) one answer
hudakz 0:5350a66d5279 341 uint16_t answerCount = htons(*((uint16_t*) &header[6]));
hudakz 0:5350a66d5279 342 if(answerCount == 0) {
hudakz 0:5350a66d5279 343
hudakz 0:5350a66d5279 344 // Mark the entire packet as read
hudakz 0:5350a66d5279 345 iUdp.flush();
hudakz 0:5350a66d5279 346 return -6; //INVALID_RESPONSE;
hudakz 0:5350a66d5279 347 }
hudakz 0:5350a66d5279 348
hudakz 0:5350a66d5279 349 // Skip over any questions
hudakz 0:5350a66d5279 350 for(uint16_t i = 0; i < htons(*((uint16_t*) &header[4])); i++) {
hudakz 0:5350a66d5279 351
hudakz 0:5350a66d5279 352 // Skip over the name
hudakz 0:5350a66d5279 353 uint8_t len;
hudakz 0:5350a66d5279 354 do
hudakz 0:5350a66d5279 355 {
hudakz 0:5350a66d5279 356 iUdp.read(&len, sizeof(len));
hudakz 0:5350a66d5279 357 if(len > 0) {
hudakz 0:5350a66d5279 358
hudakz 0:5350a66d5279 359 // Don't need to actually read the data out for the string, just
hudakz 0:5350a66d5279 360 // advance ptr to beyond it
hudakz 0:5350a66d5279 361 while(len--) {
hudakz 0:5350a66d5279 362 iUdp.read(); // we don't care about the returned byte
hudakz 0:5350a66d5279 363 }
hudakz 0:5350a66d5279 364 }
hudakz 0:5350a66d5279 365 } while(len != 0);
hudakz 0:5350a66d5279 366
hudakz 0:5350a66d5279 367 // Now jump over the type and class
hudakz 0:5350a66d5279 368 for(int i = 0; i < 4; i++) {
hudakz 0:5350a66d5279 369 iUdp.read(); // we don't care about the returned byte
hudakz 0:5350a66d5279 370 }
hudakz 0:5350a66d5279 371 }
hudakz 0:5350a66d5279 372
hudakz 0:5350a66d5279 373 // Now we're up to the bit we're interested in, the answer
hudakz 0:5350a66d5279 374 // There might be more than one answer (although we'll just use the first
hudakz 0:5350a66d5279 375 // type A answer) and some authority and additional resource records but
hudakz 0:5350a66d5279 376 // we're going to ignore all of them.
hudakz 0:5350a66d5279 377 for(uint16_t i = 0; i < answerCount; i++) {
hudakz 0:5350a66d5279 378
hudakz 0:5350a66d5279 379 // Skip the name
hudakz 0:5350a66d5279 380 uint8_t len;
hudakz 0:5350a66d5279 381 do
hudakz 0:5350a66d5279 382 {
hudakz 0:5350a66d5279 383 iUdp.read(&len, sizeof(len));
hudakz 0:5350a66d5279 384 if((len & LABEL_COMPRESSION_MASK) == 0) {
hudakz 0:5350a66d5279 385
hudakz 0:5350a66d5279 386 // It's just a normal label
hudakz 0:5350a66d5279 387 if(len > 0) {
hudakz 0:5350a66d5279 388
hudakz 0:5350a66d5279 389 // And it's got a length
hudakz 0:5350a66d5279 390 // Don't need to actually read the data out for the string,
hudakz 0:5350a66d5279 391 // just advance ptr to beyond it
hudakz 0:5350a66d5279 392 while(len--) {
hudakz 0:5350a66d5279 393 iUdp.read(); // we don't care about the returned byte
hudakz 0:5350a66d5279 394 }
hudakz 0:5350a66d5279 395 }
hudakz 0:5350a66d5279 396 }
hudakz 0:5350a66d5279 397 else {
hudakz 0:5350a66d5279 398
hudakz 0:5350a66d5279 399 // This is a pointer to a somewhere else in the message for the
hudakz 0:5350a66d5279 400 // rest of the name. We don't care about the name, and RFC1035
hudakz 0:5350a66d5279 401 // says that a name is either a sequence of labels ended with a
hudakz 0:5350a66d5279 402 // 0 length octet or a pointer or a sequence of labels ending in
hudakz 0:5350a66d5279 403 // a pointer. Either way, when we get here we're at the end of
hudakz 0:5350a66d5279 404 // the name
hudakz 0:5350a66d5279 405 // Skip over the pointer
hudakz 0:5350a66d5279 406 iUdp.read(); // we don't care about the returned byte
hudakz 0:5350a66d5279 407
hudakz 0:5350a66d5279 408 // And set len so that we drop out of the name loop
hudakz 0:5350a66d5279 409 len = 0;
hudakz 0:5350a66d5279 410 }
hudakz 0:5350a66d5279 411 } while(len != 0);
hudakz 0:5350a66d5279 412
hudakz 0:5350a66d5279 413 // Check the type and class
hudakz 0:5350a66d5279 414 uint16_t answerType;
hudakz 0:5350a66d5279 415 uint16_t answerClass;
hudakz 0:5350a66d5279 416 iUdp.read((uint8_t*) &answerType, sizeof(answerType));
hudakz 0:5350a66d5279 417 iUdp.read((uint8_t*) &answerClass, sizeof(answerClass));
hudakz 0:5350a66d5279 418
hudakz 0:5350a66d5279 419 // Ignore the Time-To-Live as we don't do any caching
hudakz 0:5350a66d5279 420 for(int i = 0; i < TTL_SIZE; i++) {
hudakz 0:5350a66d5279 421 iUdp.read(); // we don't care about the returned byte
hudakz 0:5350a66d5279 422 }
hudakz 0:5350a66d5279 423
hudakz 0:5350a66d5279 424 // And read out the length of this answer
hudakz 0:5350a66d5279 425 // Don't need header_flags anymore, so we can reuse it here
hudakz 0:5350a66d5279 426 iUdp.read((uint8_t*) &header_flags, sizeof(header_flags));
hudakz 0:5350a66d5279 427
hudakz 0:5350a66d5279 428 if((htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN)) {
hudakz 0:5350a66d5279 429 if(htons(header_flags) != 4) {
hudakz 0:5350a66d5279 430
hudakz 0:5350a66d5279 431 // It's a weird size
hudakz 0:5350a66d5279 432 // Mark the entire packet as read
hudakz 0:5350a66d5279 433 iUdp.flush();
hudakz 0:5350a66d5279 434 return -9; //INVALID_RESPONSE;
hudakz 0:5350a66d5279 435 }
hudakz 0:5350a66d5279 436
hudakz 0:5350a66d5279 437 iUdp.read(aAddress.raw_address(), 4);
hudakz 0:5350a66d5279 438 return SUCCESS;
hudakz 0:5350a66d5279 439 }
hudakz 0:5350a66d5279 440 else {
hudakz 0:5350a66d5279 441
hudakz 0:5350a66d5279 442 // This isn't an answer type we're after, move onto the next one
hudakz 0:5350a66d5279 443 for(uint16_t i = 0; i < htons(header_flags); i++) {
hudakz 0:5350a66d5279 444 iUdp.read(); // we don't care about the returned byte
hudakz 0:5350a66d5279 445 }
hudakz 0:5350a66d5279 446 }
hudakz 0:5350a66d5279 447 }
hudakz 0:5350a66d5279 448
hudakz 0:5350a66d5279 449 // Mark the entire packet as read
hudakz 0:5350a66d5279 450 iUdp.flush();
hudakz 0:5350a66d5279 451
hudakz 0:5350a66d5279 452 // If we get here then we haven't found an answer
hudakz 0:5350a66d5279 453 return -10; //INVALID_RESPONSE;
hudakz 0:5350a66d5279 454 }