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:
Thu Jul 23 15:30:54 2020 +0000
Revision:
18:8d5738a6646e
Parent:
16:269f652b4d0b
Mbed library for ENC28J60 Ethernet modules.

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