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:
Sat Sep 07 17:42:42 2019 +0000
Revision:
15:53715cc81c63
Parent:
9:a156d3de5647
Child:
16:269f652b4d0b
Timeout parameter added for the 'connect' function, SPI speed reduced from 20 to 10 Mb/s, debug messages fixed ...

Who changed what in which revision?

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