COSA
An Object-Oriented Platform for Arduino Programming
DNS.cpp
Go to the documentation of this file.
1 
21 #include "DNS.hh"
22 #include "Cosa/INET.hh"
23 #include "Cosa/Errno.h"
24 
25 bool
26 DNS::begin(Socket* sock, uint8_t server[4])
27 {
28  memcpy(m_server, server, sizeof(m_server));
29  m_sock = sock;
30  return (sock != NULL);
31 }
32 
33 bool
35 {
36  if (UNLIKELY(m_sock == NULL)) return (false);
37  m_sock->close();
38  m_sock = NULL;
39  return (true);
40 }
41 
42 int
43 DNS::gethostbyname(const char* hostname, uint8_t addr[4], bool progmem)
44 {
45  if (UNLIKELY(m_sock == NULL)) return (ENOTSOCK);
46 
47  // Check if we already have a network address (as a string)
48  if (INET::aton(hostname, addr, progmem) == 0) return (0);
49 
50  // Convert hostname to a path
51  char path[INET::PATH_MAX];
52  int len = INET::nametopath(hostname, path, progmem);
53  if (UNLIKELY(len <= 0)) return (EFAULT);
54 
55  // Construct request header
56  header_t request;
57  request.ID = hton((int16_t) ID);
58  request.FC = hton(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG);
59  request.QC = hton(1);
60  request.ANC = 0;
61  request.NSC = 0;
62  request.ARC = 0;
63 
64  // And query attributes
65  attr_t attr;
66  attr.TYPE = hton(TYPE_A);
67  attr.CLASS = hton(CLASS_IN);
68 
69  // Send request and wait for reply
70  for (int8_t retry = 0; retry < RETRY_MAX; retry++) {
71  m_sock->datagram(m_server, PORT);
72  m_sock->write(&request, sizeof(request));
73  m_sock->write(path, len);
74  m_sock->write(&attr, sizeof(attr));
75  m_sock->flush();
76 
77  // Wait for a reply
78  int res;
79  for (uint16_t i = 0; i < TIMEOUT; i += 32) {
80  if ((res = m_sock->available()) != 0) break;
81  delay(32);
82  }
83  if (res == 0) continue;
84 
85  // Receive the DNS response
86  uint8_t response[128];
87  uint8_t dest[4];
88  uint16_t port;
89  res = m_sock->recv(response, sizeof(response), dest, port);
90  if (UNLIKELY(res <= 0)) continue;
91 
92  // The response header
93  header_t* header = (header_t*) response;
94  ntoh((int16_t*) header, (int16_t*) header, sizeof(header_t) / 2);
95  if (header->ID != ID) continue;
96  uint8_t* ptr = &response[sizeof(header_t)];
97 
98  // The query; Path and attributes
99  uint8_t n;
100  while ((n = *ptr++) != 0) ptr += n;
101  ptr += sizeof(attr_t);
102 
103  // The answer; domain name, attributes and data (address)
104  for (uint16_t i = 0; i < header->ANC; i++) {
105  do {
106  n = *ptr++;
107  if ((n & LABEL_COMPRESSION_MASK) == 0) {
108  if ((n & 0x80) == 0) {
109  ptr += n;
110  }
111  }
112  else {
113  ptr += 1;
114  n = 0;
115  }
116  } while (n != 0);
117  rec_t* rec = (rec_t*) ptr;
118  ntoh((int16_t*) rec, (int16_t*) rec, sizeof(rec_t) / 2);
119  ptr += sizeof(rec_t);
120  ptr += rec->RDL;
121  if (rec->TYPE != TYPE_A) continue;
122  if (rec->CLASS != CLASS_IN) continue;
123  if (rec->RDL != INET::IP_MAX) continue;
124  memcpy(addr, rec->RD, INET::IP_MAX);
125  return (0);
126  }
127  }
128  return (EIO);
129 }
#define EIO
Definition: Errno.h:32
Definition: Socket.hh:31
virtual int recv(void *buf, size_t len)=0
virtual int write(const void *buf, size_t size)
Definition: Socket.hh:93
bool begin(Socket *sock, uint8_t server[4])
Definition: DNS.cpp:26
#define NULL
Definition: Types.h:101
static int aton(const char *addr, uint8_t ip[IP_MAX], bool progmem=false)
Definition: INET.cpp:42
#define ENOTSOCK
Definition: Errno.h:115
virtual int datagram(uint8_t addr[4], uint16_t port)=0
void(* delay)(uint32_t ms)
virtual int close()=0
virtual int flush()
static const uint8_t IP_MAX
Definition: INET.hh:69
static const uint16_t PORT
Definition: DNS.hh:34
virtual int available()
static const uint8_t PATH_MAX
Definition: INET.hh:67
#define hton
Definition: Types.h:584
bool end()
Definition: DNS.cpp:34
#define UNLIKELY(x)
Definition: Types.h:153
int gethostbyname(const char *hostname, uint8_t ip[4])
Definition: DNS.hh:83
#define ntoh
Definition: Types.h:583
#define EFAULT
Definition: Errno.h:41
static int nametopath(const char *hostname, char *path, bool progmem=false)
Definition: INET.cpp:63