Kev Mann / mbed-dev-OS5_10_4
Committer:
kevman
Date:
Wed Mar 13 11:03:24 2019 +0000
Revision:
2:7aab896b1a3b
Parent:
0:38ceb79fef03
2019-03-13

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kevman 0:38ceb79fef03 1 /* nsapi_dns.cpp
kevman 0:38ceb79fef03 2 * Original work Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
kevman 0:38ceb79fef03 3 * Modified work Copyright (c) 2015 ARM Limited
kevman 0:38ceb79fef03 4 *
kevman 0:38ceb79fef03 5 * Licensed under the Apache License, Version 2.0 (the "License");
kevman 0:38ceb79fef03 6 * you may not use this file except in compliance with the License.
kevman 0:38ceb79fef03 7 * You may obtain a copy of the License at
kevman 0:38ceb79fef03 8 *
kevman 0:38ceb79fef03 9 * http://www.apache.org/licenses/LICENSE-2.0
kevman 0:38ceb79fef03 10 *
kevman 0:38ceb79fef03 11 * Unless required by applicable law or agreed to in writing, software
kevman 0:38ceb79fef03 12 * distributed under the License is distributed on an "AS IS" BASIS,
kevman 0:38ceb79fef03 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kevman 0:38ceb79fef03 14 * See the License for the specific language governing permissions and
kevman 0:38ceb79fef03 15 * limitations under the License.
kevman 0:38ceb79fef03 16 */
kevman 0:38ceb79fef03 17
kevman 0:38ceb79fef03 18 /* Declare __STDC_LIMIT_MACROS so stdint.h defines INT32_MAX when using C++ */
kevman 0:38ceb79fef03 19 #define __STDC_LIMIT_MACROS
kevman 0:38ceb79fef03 20
kevman 0:38ceb79fef03 21 #include "nsapi_dns.h"
kevman 0:38ceb79fef03 22 #include "netsocket/UDPSocket.h"
kevman 0:38ceb79fef03 23 #include <string.h>
kevman 0:38ceb79fef03 24 #include <stdlib.h>
kevman 0:38ceb79fef03 25 #include <stdio.h>
kevman 0:38ceb79fef03 26 #include "mbed_shared_queues.h"
kevman 0:38ceb79fef03 27 #include "EventQueue.h"
kevman 0:38ceb79fef03 28 #include "OnboardNetworkStack.h"
kevman 0:38ceb79fef03 29 #include "Kernel.h"
kevman 0:38ceb79fef03 30 #include "PlatformMutex.h"
kevman 0:38ceb79fef03 31 #include "SingletonPtr.h"
kevman 0:38ceb79fef03 32
kevman 0:38ceb79fef03 33 #define CLASS_IN 1
kevman 0:38ceb79fef03 34
kevman 0:38ceb79fef03 35 #define RR_A 1
kevman 0:38ceb79fef03 36 #define RR_AAAA 28
kevman 0:38ceb79fef03 37
kevman 0:38ceb79fef03 38 // DNS options
kevman 0:38ceb79fef03 39 #define DNS_BUFFER_SIZE 512
kevman 0:38ceb79fef03 40 #define DNS_SERVERS_SIZE 5
kevman 0:38ceb79fef03 41 #define DNS_RESPONSE_MIN_SIZE 12
kevman 0:38ceb79fef03 42 #define DNS_STACK_SERVERS_NUM 5
kevman 0:38ceb79fef03 43 #define DNS_QUERY_QUEUE_SIZE 5
kevman 0:38ceb79fef03 44 #define DNS_HOST_NAME_MAX_LEN 255
kevman 0:38ceb79fef03 45 #define DNS_TIMER_TIMEOUT 100
kevman 0:38ceb79fef03 46
kevman 0:38ceb79fef03 47 struct DNS_CACHE {
kevman 0:38ceb79fef03 48 nsapi_addr_t address;
kevman 0:38ceb79fef03 49 char *host;
kevman 0:38ceb79fef03 50 uint64_t expires; /*!< time to live in milliseconds */
kevman 0:38ceb79fef03 51 uint64_t accessed; /*!< last accessed */
kevman 0:38ceb79fef03 52 };
kevman 0:38ceb79fef03 53
kevman 0:38ceb79fef03 54 struct SOCKET_CB_DATA {
kevman 0:38ceb79fef03 55 call_in_callback_cb_t call_in_cb;
kevman 0:38ceb79fef03 56 NetworkStack *stack;
kevman 0:38ceb79fef03 57 };
kevman 0:38ceb79fef03 58
kevman 0:38ceb79fef03 59 enum dns_state {
kevman 0:38ceb79fef03 60 DNS_CREATED, /*!< created, not yet making query to network */
kevman 0:38ceb79fef03 61 DNS_INITIATED, /*!< making query to network */
kevman 0:38ceb79fef03 62 DNS_CANCELLED /*!< cancelled, callback will not be called */
kevman 0:38ceb79fef03 63 };
kevman 0:38ceb79fef03 64
kevman 0:38ceb79fef03 65 struct DNS_QUERY {
kevman 0:38ceb79fef03 66 int unique_id;
kevman 0:38ceb79fef03 67 nsapi_error_t status;
kevman 0:38ceb79fef03 68 NetworkStack *stack;
kevman 0:38ceb79fef03 69 char *host;
kevman 0:38ceb79fef03 70 NetworkStack::hostbyname_cb_t callback;
kevman 0:38ceb79fef03 71 call_in_callback_cb_t call_in_cb;
kevman 0:38ceb79fef03 72 nsapi_size_t addr_count;
kevman 0:38ceb79fef03 73 nsapi_version_t version;
kevman 0:38ceb79fef03 74 UDPSocket *socket;
kevman 0:38ceb79fef03 75 SOCKET_CB_DATA *socket_cb_data;
kevman 0:38ceb79fef03 76 nsapi_addr_t *addrs;
kevman 0:38ceb79fef03 77 uint32_t ttl;
kevman 0:38ceb79fef03 78 uint32_t total_timeout;
kevman 0:38ceb79fef03 79 uint32_t socket_timeout;
kevman 0:38ceb79fef03 80 uint16_t dns_message_id;
kevman 0:38ceb79fef03 81 uint8_t dns_server;
kevman 0:38ceb79fef03 82 uint8_t retries;
kevman 0:38ceb79fef03 83 uint8_t total_attempts;
kevman 0:38ceb79fef03 84 uint8_t send_success;
kevman 0:38ceb79fef03 85 uint8_t count;
kevman 0:38ceb79fef03 86 dns_state state;
kevman 0:38ceb79fef03 87 };
kevman 0:38ceb79fef03 88
kevman 0:38ceb79fef03 89 static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl);
kevman 0:38ceb79fef03 90 static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address);
kevman 0:38ceb79fef03 91
kevman 0:38ceb79fef03 92 static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, uint8_t *send_success, SocketAddress *dns_addr);
kevman 0:38ceb79fef03 93
kevman 0:38ceb79fef03 94 static void nsapi_dns_query_async_create(void *ptr);
kevman 0:38ceb79fef03 95 static nsapi_error_t nsapi_dns_query_async_delete(int unique_id);
kevman 0:38ceb79fef03 96 static void nsapi_dns_query_async_send(void *ptr);
kevman 0:38ceb79fef03 97 static void nsapi_dns_query_async_timeout(void);
kevman 0:38ceb79fef03 98 static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address);
kevman 0:38ceb79fef03 99 static void nsapi_dns_query_async_socket_callback(void *ptr);
kevman 0:38ceb79fef03 100 static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack);
kevman 0:38ceb79fef03 101 static void nsapi_dns_query_async_response(void *ptr);
kevman 0:38ceb79fef03 102 static void nsapi_dns_query_async_initiate_next(void);
kevman 0:38ceb79fef03 103
kevman 0:38ceb79fef03 104 // *INDENT-OFF*
kevman 0:38ceb79fef03 105 static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
kevman 0:38ceb79fef03 106 {NSAPI_IPv4, {8, 8, 8, 8}}, // Google
kevman 0:38ceb79fef03 107 {NSAPI_IPv4, {209, 244, 0, 3}}, // Level 3
kevman 0:38ceb79fef03 108 {NSAPI_IPv4, {84, 200, 69, 80}}, // DNS.WATCH
kevman 0:38ceb79fef03 109 {NSAPI_IPv6, {0x20,0x01, 0x48,0x60, 0x48,0x60, 0,0, // Google
kevman 0:38ceb79fef03 110 0,0, 0,0, 0,0, 0x88,0x88}},
kevman 0:38ceb79fef03 111 {NSAPI_IPv6, {0x20,0x01, 0x16,0x08, 0,0x10, 0,0x25, // DNS.WATCH
kevman 0:38ceb79fef03 112 0,0, 0,0, 0x1c,0x04, 0xb1,0x2f}},
kevman 0:38ceb79fef03 113 };
kevman 0:38ceb79fef03 114 // *INDENT-ON*
kevman 0:38ceb79fef03 115
kevman 0:38ceb79fef03 116 #if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0)
kevman 0:38ceb79fef03 117 static DNS_CACHE *dns_cache[MBED_CONF_NSAPI_DNS_CACHE_SIZE];
kevman 0:38ceb79fef03 118 // Protects cache shared between blocking and asynchronous calls
kevman 0:38ceb79fef03 119 static SingletonPtr<PlatformMutex> dns_cache_mutex;
kevman 0:38ceb79fef03 120 #endif
kevman 0:38ceb79fef03 121
kevman 0:38ceb79fef03 122 static uint16_t dns_message_id = 1;
kevman 0:38ceb79fef03 123 static int dns_unique_id = 1;
kevman 0:38ceb79fef03 124 static DNS_QUERY *dns_query_queue[DNS_QUERY_QUEUE_SIZE];
kevman 0:38ceb79fef03 125 // Protects from several threads running asynchronous DNS
kevman 0:38ceb79fef03 126 static SingletonPtr<PlatformMutex> dns_mutex;
kevman 0:38ceb79fef03 127 static SingletonPtr<call_in_callback_cb_t> dns_call_in;
kevman 0:38ceb79fef03 128 static bool dns_timer_running = false;
kevman 0:38ceb79fef03 129
kevman 0:38ceb79fef03 130 // DNS server configuration
kevman 0:38ceb79fef03 131 extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr)
kevman 0:38ceb79fef03 132 {
kevman 0:38ceb79fef03 133 memmove(&dns_servers[1], &dns_servers[0],
kevman 0:38ceb79fef03 134 (DNS_SERVERS_SIZE - 1)*sizeof(nsapi_addr_t));
kevman 0:38ceb79fef03 135
kevman 0:38ceb79fef03 136 dns_servers[0] = addr;
kevman 0:38ceb79fef03 137 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 138 }
kevman 0:38ceb79fef03 139
kevman 0:38ceb79fef03 140
kevman 0:38ceb79fef03 141 // DNS packet parsing
kevman 0:38ceb79fef03 142 static void dns_append_byte(uint8_t **p, uint8_t byte)
kevman 0:38ceb79fef03 143 {
kevman 0:38ceb79fef03 144 *(*p)++ = byte;
kevman 0:38ceb79fef03 145 }
kevman 0:38ceb79fef03 146
kevman 0:38ceb79fef03 147 static void dns_append_word(uint8_t **p, uint16_t word)
kevman 0:38ceb79fef03 148 {
kevman 0:38ceb79fef03 149
kevman 0:38ceb79fef03 150 dns_append_byte(p, 0xff & (word >> 8));
kevman 0:38ceb79fef03 151 dns_append_byte(p, 0xff & (word >> 0));
kevman 0:38ceb79fef03 152 }
kevman 0:38ceb79fef03 153
kevman 0:38ceb79fef03 154 static void dns_append_name(uint8_t **p, const char *name, uint8_t len)
kevman 0:38ceb79fef03 155 {
kevman 0:38ceb79fef03 156 dns_append_byte(p, len);
kevman 0:38ceb79fef03 157 memcpy(*p, name, len);
kevman 0:38ceb79fef03 158 *p += len;
kevman 0:38ceb79fef03 159 }
kevman 0:38ceb79fef03 160
kevman 0:38ceb79fef03 161 static uint8_t dns_scan_byte(const uint8_t **p)
kevman 0:38ceb79fef03 162 {
kevman 0:38ceb79fef03 163 return *(*p)++;
kevman 0:38ceb79fef03 164 }
kevman 0:38ceb79fef03 165
kevman 0:38ceb79fef03 166 static uint16_t dns_scan_word(const uint8_t **p)
kevman 0:38ceb79fef03 167 {
kevman 0:38ceb79fef03 168 uint16_t a = dns_scan_byte(p);
kevman 0:38ceb79fef03 169 uint16_t b = dns_scan_byte(p);
kevman 0:38ceb79fef03 170 return (a << 8) | b;
kevman 0:38ceb79fef03 171 }
kevman 0:38ceb79fef03 172
kevman 0:38ceb79fef03 173 static uint32_t dns_scan_word32(const uint8_t **p)
kevman 0:38ceb79fef03 174 {
kevman 0:38ceb79fef03 175 uint32_t value = dns_scan_byte(p) << 24;
kevman 0:38ceb79fef03 176 value |= dns_scan_byte(p) << 16;
kevman 0:38ceb79fef03 177 value |= dns_scan_byte(p) << 8;
kevman 0:38ceb79fef03 178 value |= dns_scan_byte(p);
kevman 0:38ceb79fef03 179
kevman 0:38ceb79fef03 180 return value;
kevman 0:38ceb79fef03 181 }
kevman 0:38ceb79fef03 182
kevman 0:38ceb79fef03 183 static int dns_append_question(uint8_t *ptr, uint16_t id, const char *host, nsapi_version_t version)
kevman 0:38ceb79fef03 184 {
kevman 0:38ceb79fef03 185 uint8_t *s_ptr = ptr;
kevman 0:38ceb79fef03 186 uint8_t **p = &ptr;
kevman 0:38ceb79fef03 187
kevman 0:38ceb79fef03 188 // fill the header
kevman 0:38ceb79fef03 189 dns_append_word(p, id); // id = 1
kevman 0:38ceb79fef03 190 dns_append_word(p, 0x0100); // flags = recursion required
kevman 0:38ceb79fef03 191 dns_append_word(p, 1); // qdcount = 1
kevman 0:38ceb79fef03 192 dns_append_word(p, 0); // ancount = 0
kevman 0:38ceb79fef03 193 dns_append_word(p, 0); // nscount = 0
kevman 0:38ceb79fef03 194 dns_append_word(p, 0); // arcount = 0
kevman 0:38ceb79fef03 195
kevman 0:38ceb79fef03 196 // fill out the question names
kevman 0:38ceb79fef03 197 while (host[0]) {
kevman 0:38ceb79fef03 198 size_t label_len = strcspn(host, ".");
kevman 0:38ceb79fef03 199 dns_append_name(p, host, label_len);
kevman 0:38ceb79fef03 200 host += label_len + (host[label_len] == '.');
kevman 0:38ceb79fef03 201 }
kevman 0:38ceb79fef03 202
kevman 0:38ceb79fef03 203 dns_append_byte(p, 0);
kevman 0:38ceb79fef03 204
kevman 0:38ceb79fef03 205 // fill out question footer
kevman 0:38ceb79fef03 206 if (version != NSAPI_IPv6) {
kevman 0:38ceb79fef03 207 dns_append_word(p, RR_A); // qtype = ipv4
kevman 0:38ceb79fef03 208 } else {
kevman 0:38ceb79fef03 209 dns_append_word(p, RR_AAAA); // qtype = ipv6
kevman 0:38ceb79fef03 210 }
kevman 0:38ceb79fef03 211 dns_append_word(p, CLASS_IN);
kevman 0:38ceb79fef03 212
kevman 0:38ceb79fef03 213 return *p - s_ptr;
kevman 0:38ceb79fef03 214 }
kevman 0:38ceb79fef03 215
kevman 0:38ceb79fef03 216 static int dns_scan_response(const uint8_t *ptr, uint16_t exp_id, uint32_t *ttl, nsapi_addr_t *addr, unsigned addr_count)
kevman 0:38ceb79fef03 217 {
kevman 0:38ceb79fef03 218 const uint8_t **p = &ptr;
kevman 0:38ceb79fef03 219
kevman 0:38ceb79fef03 220 // scan header
kevman 0:38ceb79fef03 221 uint16_t id = dns_scan_word(p);
kevman 0:38ceb79fef03 222 uint16_t flags = dns_scan_word(p);
kevman 0:38ceb79fef03 223 bool qr = 0x1 & (flags >> 15);
kevman 0:38ceb79fef03 224 uint8_t opcode = 0xf & (flags >> 11);
kevman 0:38ceb79fef03 225 uint8_t rcode = 0xf & (flags >> 0);
kevman 0:38ceb79fef03 226
kevman 0:38ceb79fef03 227 uint16_t qdcount = dns_scan_word(p); // qdcount
kevman 0:38ceb79fef03 228 uint16_t ancount = dns_scan_word(p); // ancount
kevman 0:38ceb79fef03 229 dns_scan_word(p); // nscount
kevman 0:38ceb79fef03 230 dns_scan_word(p); // arcount
kevman 0:38ceb79fef03 231
kevman 0:38ceb79fef03 232 // verify header is response to query
kevman 0:38ceb79fef03 233 if (!(id == exp_id && qr && opcode == 0)) {
kevman 0:38ceb79fef03 234 return -1;
kevman 0:38ceb79fef03 235 }
kevman 0:38ceb79fef03 236
kevman 0:38ceb79fef03 237 if (rcode != 0) {
kevman 0:38ceb79fef03 238 return 0;
kevman 0:38ceb79fef03 239 }
kevman 0:38ceb79fef03 240
kevman 0:38ceb79fef03 241 // skip questions
kevman 0:38ceb79fef03 242 for (int i = 0; i < qdcount; i++) {
kevman 0:38ceb79fef03 243 while (true) {
kevman 0:38ceb79fef03 244 uint8_t len = dns_scan_byte(p);
kevman 0:38ceb79fef03 245 if (len == 0) {
kevman 0:38ceb79fef03 246 break;
kevman 0:38ceb79fef03 247 }
kevman 0:38ceb79fef03 248
kevman 0:38ceb79fef03 249 *p += len;
kevman 0:38ceb79fef03 250 }
kevman 0:38ceb79fef03 251
kevman 0:38ceb79fef03 252 dns_scan_word(p); // qtype
kevman 0:38ceb79fef03 253 dns_scan_word(p); // qclass
kevman 0:38ceb79fef03 254 }
kevman 0:38ceb79fef03 255
kevman 0:38ceb79fef03 256 // scan each response
kevman 0:38ceb79fef03 257 unsigned count = 0;
kevman 0:38ceb79fef03 258
kevman 0:38ceb79fef03 259 for (int i = 0; i < ancount && count < addr_count; i++) {
kevman 0:38ceb79fef03 260 while (true) {
kevman 0:38ceb79fef03 261 uint8_t len = dns_scan_byte(p);
kevman 0:38ceb79fef03 262 if (len == 0) {
kevman 0:38ceb79fef03 263 break;
kevman 0:38ceb79fef03 264 } else if (len & 0xc0) { // this is link
kevman 0:38ceb79fef03 265 dns_scan_byte(p);
kevman 0:38ceb79fef03 266 break;
kevman 0:38ceb79fef03 267 }
kevman 0:38ceb79fef03 268
kevman 0:38ceb79fef03 269 *p += len;
kevman 0:38ceb79fef03 270 }
kevman 0:38ceb79fef03 271
kevman 0:38ceb79fef03 272 uint16_t rtype = dns_scan_word(p); // rtype
kevman 0:38ceb79fef03 273 uint16_t rclass = dns_scan_word(p); // rclass
kevman 0:38ceb79fef03 274 uint32_t ttl_val = dns_scan_word32(p); // ttl
kevman 0:38ceb79fef03 275 uint16_t rdlength = dns_scan_word(p); // rdlength
kevman 0:38ceb79fef03 276
kevman 0:38ceb79fef03 277 if (i == 0) {
kevman 0:38ceb79fef03 278 // Is interested only on first address that is stored to cache
kevman 0:38ceb79fef03 279 if (ttl_val > INT32_MAX) {
kevman 0:38ceb79fef03 280 ttl_val = INT32_MAX;
kevman 0:38ceb79fef03 281 }
kevman 0:38ceb79fef03 282 *ttl = ttl_val;
kevman 0:38ceb79fef03 283 }
kevman 0:38ceb79fef03 284
kevman 0:38ceb79fef03 285 if (rtype == RR_A && rclass == CLASS_IN && rdlength == NSAPI_IPv4_BYTES) {
kevman 0:38ceb79fef03 286 // accept A record
kevman 0:38ceb79fef03 287 addr->version = NSAPI_IPv4;
kevman 0:38ceb79fef03 288 for (int i = 0; i < NSAPI_IPv4_BYTES; i++) {
kevman 0:38ceb79fef03 289 addr->bytes[i] = dns_scan_byte(p);
kevman 0:38ceb79fef03 290 }
kevman 0:38ceb79fef03 291
kevman 0:38ceb79fef03 292 addr += 1;
kevman 0:38ceb79fef03 293 count += 1;
kevman 0:38ceb79fef03 294 } else if (rtype == RR_AAAA && rclass == CLASS_IN && rdlength == NSAPI_IPv6_BYTES) {
kevman 0:38ceb79fef03 295 // accept AAAA record
kevman 0:38ceb79fef03 296 addr->version = NSAPI_IPv6;
kevman 0:38ceb79fef03 297 for (int i = 0; i < NSAPI_IPv6_BYTES; i++) {
kevman 0:38ceb79fef03 298 addr->bytes[i] = dns_scan_byte(p);
kevman 0:38ceb79fef03 299 }
kevman 0:38ceb79fef03 300
kevman 0:38ceb79fef03 301 addr += 1;
kevman 0:38ceb79fef03 302 count += 1;
kevman 0:38ceb79fef03 303 } else {
kevman 0:38ceb79fef03 304 // skip unrecognized records
kevman 0:38ceb79fef03 305 *p += rdlength;
kevman 0:38ceb79fef03 306 }
kevman 0:38ceb79fef03 307 }
kevman 0:38ceb79fef03 308
kevman 0:38ceb79fef03 309 return count;
kevman 0:38ceb79fef03 310 }
kevman 0:38ceb79fef03 311
kevman 0:38ceb79fef03 312 static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl)
kevman 0:38ceb79fef03 313 {
kevman 0:38ceb79fef03 314 #if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0)
kevman 0:38ceb79fef03 315 // RFC 1034: if TTL is zero, entry is not added to cache
kevman 0:38ceb79fef03 316 if (ttl == 0) {
kevman 0:38ceb79fef03 317 return;
kevman 0:38ceb79fef03 318 }
kevman 0:38ceb79fef03 319
kevman 0:38ceb79fef03 320 // Checks if already cached
kevman 0:38ceb79fef03 321 if (nsapi_dns_cache_find(host, address->version, NULL) == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 322 return;
kevman 0:38ceb79fef03 323 }
kevman 0:38ceb79fef03 324
kevman 0:38ceb79fef03 325 dns_cache_mutex->lock();
kevman 0:38ceb79fef03 326
kevman 0:38ceb79fef03 327 int index = -1;
kevman 0:38ceb79fef03 328 uint64_t accessed = UINT64_MAX;
kevman 0:38ceb79fef03 329
kevman 0:38ceb79fef03 330 // Finds free or last accessed entry
kevman 0:38ceb79fef03 331 for (int i = 0; i < MBED_CONF_NSAPI_DNS_CACHE_SIZE; i++) {
kevman 0:38ceb79fef03 332 if (!dns_cache[i]) {
kevman 0:38ceb79fef03 333 index = i;
kevman 0:38ceb79fef03 334 break;
kevman 0:38ceb79fef03 335 } else if (dns_cache[i]->accessed <= accessed) {
kevman 0:38ceb79fef03 336 accessed = dns_cache[i]->accessed;
kevman 0:38ceb79fef03 337 index = i;
kevman 0:38ceb79fef03 338 }
kevman 0:38ceb79fef03 339 }
kevman 0:38ceb79fef03 340
kevman 0:38ceb79fef03 341 if (index < 0) {
kevman 0:38ceb79fef03 342 dns_cache_mutex->unlock();
kevman 0:38ceb79fef03 343 return;
kevman 0:38ceb79fef03 344 }
kevman 0:38ceb79fef03 345
kevman 0:38ceb79fef03 346 // Allocates in case entry is free, otherwise reuses
kevman 0:38ceb79fef03 347 if (!dns_cache[index]) {
kevman 0:38ceb79fef03 348 dns_cache[index] = new (std::nothrow) DNS_CACHE;
kevman 0:38ceb79fef03 349 } else {
kevman 0:38ceb79fef03 350 delete dns_cache[index]->host;
kevman 0:38ceb79fef03 351 }
kevman 0:38ceb79fef03 352
kevman 0:38ceb79fef03 353 if (dns_cache[index]) {
kevman 0:38ceb79fef03 354 dns_cache[index]->address = *address;
kevman 0:38ceb79fef03 355 dns_cache[index]->host = new (std::nothrow) char[strlen(host) + 1];
kevman 0:38ceb79fef03 356 strcpy(dns_cache[index]->host, host);
kevman 0:38ceb79fef03 357 uint64_t ms_count = rtos::Kernel::get_ms_count();
kevman 0:38ceb79fef03 358 dns_cache[index]->expires = ms_count + (uint64_t) ttl * 1000;
kevman 0:38ceb79fef03 359 dns_cache[index]->accessed = ms_count;
kevman 0:38ceb79fef03 360 }
kevman 0:38ceb79fef03 361
kevman 0:38ceb79fef03 362 dns_cache_mutex->unlock();
kevman 0:38ceb79fef03 363 #endif
kevman 0:38ceb79fef03 364 }
kevman 0:38ceb79fef03 365
kevman 0:38ceb79fef03 366 static nsapi_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address)
kevman 0:38ceb79fef03 367 {
kevman 0:38ceb79fef03 368 nsapi_error_t ret_val = NSAPI_ERROR_NO_ADDRESS;
kevman 0:38ceb79fef03 369
kevman 0:38ceb79fef03 370 #if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0)
kevman 0:38ceb79fef03 371 dns_cache_mutex->lock();
kevman 0:38ceb79fef03 372
kevman 0:38ceb79fef03 373 for (int i = 0; i < MBED_CONF_NSAPI_DNS_CACHE_SIZE; i++) {
kevman 0:38ceb79fef03 374 if (dns_cache[i]) {
kevman 0:38ceb79fef03 375 uint64_t ms_count = rtos::Kernel::get_ms_count();
kevman 0:38ceb79fef03 376 // Checks all entries for expired entries
kevman 0:38ceb79fef03 377 if (ms_count > dns_cache[i]->expires) {
kevman 0:38ceb79fef03 378 delete dns_cache[i]->host;
kevman 0:38ceb79fef03 379 delete dns_cache[i];
kevman 0:38ceb79fef03 380 dns_cache[i] = NULL;
kevman 0:38ceb79fef03 381 } else if ((version == NSAPI_UNSPEC || version == dns_cache[i]->address.version) &&
kevman 0:38ceb79fef03 382 strcmp(dns_cache[i]->host, host) == 0) {
kevman 0:38ceb79fef03 383 if (address) {
kevman 0:38ceb79fef03 384 *address = dns_cache[i]->address;
kevman 0:38ceb79fef03 385 }
kevman 0:38ceb79fef03 386 dns_cache[i]->accessed = ms_count;
kevman 0:38ceb79fef03 387 ret_val = NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 388 }
kevman 0:38ceb79fef03 389 }
kevman 0:38ceb79fef03 390 }
kevman 0:38ceb79fef03 391
kevman 0:38ceb79fef03 392 dns_cache_mutex->unlock();
kevman 0:38ceb79fef03 393 #endif
kevman 0:38ceb79fef03 394
kevman 0:38ceb79fef03 395 return ret_val;
kevman 0:38ceb79fef03 396 }
kevman 0:38ceb79fef03 397
kevman 0:38ceb79fef03 398 static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, uint8_t *send_success, SocketAddress *dns_addr)
kevman 0:38ceb79fef03 399 {
kevman 0:38ceb79fef03 400 bool dns_addr_set = false;
kevman 0:38ceb79fef03 401
kevman 0:38ceb79fef03 402 if (*total_attempts == 0) {
kevman 0:38ceb79fef03 403 return NSAPI_ERROR_NO_ADDRESS;
kevman 0:38ceb79fef03 404 }
kevman 0:38ceb79fef03 405
kevman 0:38ceb79fef03 406 if (*index >= DNS_SERVERS_SIZE + DNS_STACK_SERVERS_NUM) {
kevman 0:38ceb79fef03 407 // If there are total attempts left and send to has been successful at least once on this round
kevman 0:38ceb79fef03 408 if (*total_attempts && *send_success) {
kevman 0:38ceb79fef03 409 *index = 0;
kevman 0:38ceb79fef03 410 *send_success = 0;
kevman 0:38ceb79fef03 411 } else {
kevman 0:38ceb79fef03 412 return NSAPI_ERROR_NO_ADDRESS;
kevman 0:38ceb79fef03 413 }
kevman 0:38ceb79fef03 414 }
kevman 0:38ceb79fef03 415
kevman 0:38ceb79fef03 416 if (*index < DNS_STACK_SERVERS_NUM) {
kevman 0:38ceb79fef03 417 nsapi_error_t ret = stack->get_dns_server(*index, dns_addr);
kevman 0:38ceb79fef03 418 if (ret < 0) {
kevman 0:38ceb79fef03 419 *index = DNS_STACK_SERVERS_NUM;
kevman 0:38ceb79fef03 420 } else {
kevman 0:38ceb79fef03 421 dns_addr_set = true;
kevman 0:38ceb79fef03 422 }
kevman 0:38ceb79fef03 423 }
kevman 0:38ceb79fef03 424
kevman 0:38ceb79fef03 425 if (!dns_addr_set) {
kevman 0:38ceb79fef03 426 dns_addr->set_addr(dns_servers[*index - DNS_STACK_SERVERS_NUM]);
kevman 0:38ceb79fef03 427 }
kevman 0:38ceb79fef03 428
kevman 0:38ceb79fef03 429 dns_addr->set_port(53);
kevman 0:38ceb79fef03 430
kevman 0:38ceb79fef03 431 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 432 }
kevman 0:38ceb79fef03 433
kevman 0:38ceb79fef03 434 // core query function
kevman 0:38ceb79fef03 435 static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host,
kevman 0:38ceb79fef03 436 nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version)
kevman 0:38ceb79fef03 437 {
kevman 0:38ceb79fef03 438 // check for valid host name
kevman 0:38ceb79fef03 439 int host_len = host ? strlen(host) : 0;
kevman 0:38ceb79fef03 440 if (host_len > DNS_HOST_NAME_MAX_LEN || host_len == 0) {
kevman 0:38ceb79fef03 441 return NSAPI_ERROR_PARAMETER;
kevman 0:38ceb79fef03 442 }
kevman 0:38ceb79fef03 443
kevman 0:38ceb79fef03 444 // check cache
kevman 0:38ceb79fef03 445 if (nsapi_dns_cache_find(host, version, addr) == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 446 return 1;
kevman 0:38ceb79fef03 447 }
kevman 0:38ceb79fef03 448
kevman 0:38ceb79fef03 449 // create a udp socket
kevman 0:38ceb79fef03 450 UDPSocket socket;
kevman 0:38ceb79fef03 451 int err = socket.open(stack);
kevman 0:38ceb79fef03 452 if (err) {
kevman 0:38ceb79fef03 453 return err;
kevman 0:38ceb79fef03 454 }
kevman 0:38ceb79fef03 455
kevman 0:38ceb79fef03 456 socket.set_timeout(MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME);
kevman 0:38ceb79fef03 457
kevman 0:38ceb79fef03 458 // create network packet
kevman 0:38ceb79fef03 459 uint8_t *const packet = (uint8_t *)malloc(DNS_BUFFER_SIZE);
kevman 0:38ceb79fef03 460 if (!packet) {
kevman 0:38ceb79fef03 461 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 462 }
kevman 0:38ceb79fef03 463
kevman 0:38ceb79fef03 464 nsapi_size_or_error_t result = NSAPI_ERROR_DNS_FAILURE;
kevman 0:38ceb79fef03 465
kevman 0:38ceb79fef03 466 uint8_t retries = MBED_CONF_NSAPI_DNS_RETRIES;
kevman 0:38ceb79fef03 467 uint8_t index = 0;
kevman 0:38ceb79fef03 468 uint8_t total_attempts = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS;
kevman 0:38ceb79fef03 469 uint8_t send_success = 0;
kevman 0:38ceb79fef03 470
kevman 0:38ceb79fef03 471 // check against each dns server
kevman 0:38ceb79fef03 472 while (true) {
kevman 0:38ceb79fef03 473 SocketAddress dns_addr;
kevman 0:38ceb79fef03 474 err = nsapi_dns_get_server_addr(stack, &index, &total_attempts, &send_success, &dns_addr);
kevman 0:38ceb79fef03 475 if (err != NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 476 break;
kevman 0:38ceb79fef03 477 }
kevman 0:38ceb79fef03 478
kevman 0:38ceb79fef03 479 // send the question
kevman 0:38ceb79fef03 480 int len = dns_append_question(packet, 1, host, version);
kevman 0:38ceb79fef03 481
kevman 0:38ceb79fef03 482 err = socket.sendto(dns_addr, packet, len);
kevman 0:38ceb79fef03 483 // send may fail for various reasons, including wrong address type - move on
kevman 0:38ceb79fef03 484 if (err < 0) {
kevman 0:38ceb79fef03 485 // goes to next dns server
kevman 0:38ceb79fef03 486 retries = MBED_CONF_NSAPI_DNS_RETRIES;
kevman 0:38ceb79fef03 487 index++;
kevman 0:38ceb79fef03 488 continue;
kevman 0:38ceb79fef03 489 }
kevman 0:38ceb79fef03 490
kevman 0:38ceb79fef03 491 send_success++;
kevman 0:38ceb79fef03 492
kevman 0:38ceb79fef03 493 if (total_attempts) {
kevman 0:38ceb79fef03 494 total_attempts--;
kevman 0:38ceb79fef03 495 }
kevman 0:38ceb79fef03 496
kevman 0:38ceb79fef03 497 // recv the response
kevman 0:38ceb79fef03 498 err = socket.recvfrom(NULL, packet, DNS_BUFFER_SIZE);
kevman 0:38ceb79fef03 499 if (err == NSAPI_ERROR_WOULD_BLOCK) {
kevman 0:38ceb79fef03 500 if (retries) {
kevman 0:38ceb79fef03 501 // retries
kevman 0:38ceb79fef03 502 retries--;
kevman 0:38ceb79fef03 503 } else {
kevman 0:38ceb79fef03 504 // goes to next dns server
kevman 0:38ceb79fef03 505 retries = MBED_CONF_NSAPI_DNS_RETRIES;
kevman 0:38ceb79fef03 506 index++;
kevman 0:38ceb79fef03 507 }
kevman 0:38ceb79fef03 508 continue;
kevman 0:38ceb79fef03 509 } else if (err < 0) {
kevman 0:38ceb79fef03 510 result = err;
kevman 0:38ceb79fef03 511 break;
kevman 0:38ceb79fef03 512 }
kevman 0:38ceb79fef03 513
kevman 0:38ceb79fef03 514 const uint8_t *response = packet;
kevman 0:38ceb79fef03 515 uint32_t ttl;
kevman 0:38ceb79fef03 516 int resp = dns_scan_response(response, 1, &ttl, addr, addr_count);
kevman 0:38ceb79fef03 517 if (resp > 0) {
kevman 0:38ceb79fef03 518 nsapi_dns_cache_add(host, addr, ttl);
kevman 0:38ceb79fef03 519 result = resp;
kevman 0:38ceb79fef03 520 } else if (resp < 0) {
kevman 0:38ceb79fef03 521 continue;
kevman 0:38ceb79fef03 522 }
kevman 0:38ceb79fef03 523
kevman 0:38ceb79fef03 524 /* The DNS response is final, no need to check other servers */
kevman 0:38ceb79fef03 525 break;
kevman 0:38ceb79fef03 526 }
kevman 0:38ceb79fef03 527
kevman 0:38ceb79fef03 528 // clean up packet
kevman 0:38ceb79fef03 529 free(packet);
kevman 0:38ceb79fef03 530
kevman 0:38ceb79fef03 531 // clean up udp
kevman 0:38ceb79fef03 532 err = socket.close();
kevman 0:38ceb79fef03 533 if (err) {
kevman 0:38ceb79fef03 534 return err;
kevman 0:38ceb79fef03 535 }
kevman 0:38ceb79fef03 536
kevman 0:38ceb79fef03 537 // return result
kevman 0:38ceb79fef03 538 return result;
kevman 0:38ceb79fef03 539 }
kevman 0:38ceb79fef03 540
kevman 0:38ceb79fef03 541 // convenience functions for other forms of queries
kevman 0:38ceb79fef03 542 extern "C" nsapi_size_or_error_t nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host,
kevman 0:38ceb79fef03 543 nsapi_addr_t *addr, nsapi_size_t addr_count, nsapi_version_t version)
kevman 0:38ceb79fef03 544 {
kevman 0:38ceb79fef03 545 NetworkStack *nstack = nsapi_create_stack(stack);
kevman 0:38ceb79fef03 546 return nsapi_dns_query_multiple(nstack, host, addr, addr_count, version);
kevman 0:38ceb79fef03 547 }
kevman 0:38ceb79fef03 548
kevman 0:38ceb79fef03 549 nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host,
kevman 0:38ceb79fef03 550 SocketAddress *addresses, nsapi_size_t addr_count, nsapi_version_t version)
kevman 0:38ceb79fef03 551 {
kevman 0:38ceb79fef03 552 nsapi_addr_t *addrs = new (std::nothrow) nsapi_addr_t[addr_count];
kevman 0:38ceb79fef03 553 nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, addrs, addr_count, version);
kevman 0:38ceb79fef03 554
kevman 0:38ceb79fef03 555 if (result > 0) {
kevman 0:38ceb79fef03 556 for (int i = 0; i < result; i++) {
kevman 0:38ceb79fef03 557 addresses[i].set_addr(addrs[i]);
kevman 0:38ceb79fef03 558 }
kevman 0:38ceb79fef03 559 }
kevman 0:38ceb79fef03 560
kevman 0:38ceb79fef03 561 delete[] addrs;
kevman 0:38ceb79fef03 562 return result;
kevman 0:38ceb79fef03 563 }
kevman 0:38ceb79fef03 564
kevman 0:38ceb79fef03 565 extern "C" nsapi_error_t nsapi_dns_query(nsapi_stack_t *stack, const char *host,
kevman 0:38ceb79fef03 566 nsapi_addr_t *addr, nsapi_version_t version)
kevman 0:38ceb79fef03 567 {
kevman 0:38ceb79fef03 568 NetworkStack *nstack = nsapi_create_stack(stack);
kevman 0:38ceb79fef03 569 nsapi_size_or_error_t result = nsapi_dns_query_multiple(nstack, host, addr, 1, version);
kevman 0:38ceb79fef03 570 return (nsapi_error_t)((result > 0) ? 0 : result);
kevman 0:38ceb79fef03 571 }
kevman 0:38ceb79fef03 572
kevman 0:38ceb79fef03 573 nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
kevman 0:38ceb79fef03 574 SocketAddress *address, nsapi_version_t version)
kevman 0:38ceb79fef03 575 {
kevman 0:38ceb79fef03 576 nsapi_addr_t addr;
kevman 0:38ceb79fef03 577 nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, &addr, 1, version);
kevman 0:38ceb79fef03 578 address->set_addr(addr);
kevman 0:38ceb79fef03 579 return (nsapi_error_t)((result > 0) ? 0 : result);
kevman 0:38ceb79fef03 580 }
kevman 0:38ceb79fef03 581
kevman 0:38ceb79fef03 582 nsapi_value_or_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
kevman 0:38ceb79fef03 583 NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb,
kevman 0:38ceb79fef03 584 nsapi_version_t version)
kevman 0:38ceb79fef03 585 {
kevman 0:38ceb79fef03 586 return nsapi_dns_query_multiple_async(stack, host, callback, 0, call_in_cb, version);
kevman 0:38ceb79fef03 587 }
kevman 0:38ceb79fef03 588
kevman 0:38ceb79fef03 589 void nsapi_dns_call_in_set(call_in_callback_cb_t callback)
kevman 0:38ceb79fef03 590 {
kevman 0:38ceb79fef03 591 *dns_call_in.get() = callback;
kevman 0:38ceb79fef03 592 }
kevman 0:38ceb79fef03 593
kevman 0:38ceb79fef03 594 nsapi_error_t nsapi_dns_call_in(call_in_callback_cb_t cb, int delay, mbed::Callback<void()> func)
kevman 0:38ceb79fef03 595 {
kevman 0:38ceb79fef03 596 if (*dns_call_in.get()) {
kevman 0:38ceb79fef03 597 dns_call_in->call(delay, func);
kevman 0:38ceb79fef03 598 } else {
kevman 0:38ceb79fef03 599 return cb(delay, func);
kevman 0:38ceb79fef03 600 }
kevman 0:38ceb79fef03 601 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 602 }
kevman 0:38ceb79fef03 603
kevman 0:38ceb79fef03 604 nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host,
kevman 0:38ceb79fef03 605 NetworkStack::hostbyname_cb_t callback, nsapi_size_t addr_count,
kevman 0:38ceb79fef03 606 call_in_callback_cb_t call_in_cb, nsapi_version_t version)
kevman 0:38ceb79fef03 607 {
kevman 0:38ceb79fef03 608 dns_mutex->lock();
kevman 0:38ceb79fef03 609
kevman 0:38ceb79fef03 610 if (!stack) {
kevman 0:38ceb79fef03 611 return NSAPI_ERROR_PARAMETER;
kevman 0:38ceb79fef03 612 }
kevman 0:38ceb79fef03 613
kevman 0:38ceb79fef03 614 // check for valid host name
kevman 0:38ceb79fef03 615 int host_len = host ? strlen(host) : 0;
kevman 0:38ceb79fef03 616 if (host_len > DNS_HOST_NAME_MAX_LEN || host_len == 0) {
kevman 0:38ceb79fef03 617 dns_mutex->unlock();
kevman 0:38ceb79fef03 618 return NSAPI_ERROR_PARAMETER;
kevman 0:38ceb79fef03 619 }
kevman 0:38ceb79fef03 620
kevman 0:38ceb79fef03 621 nsapi_addr address;
kevman 0:38ceb79fef03 622 if (nsapi_dns_cache_find(host, version, &address) == NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 623 SocketAddress addr(address);
kevman 0:38ceb79fef03 624 dns_mutex->unlock();
kevman 0:38ceb79fef03 625 callback(NSAPI_ERROR_OK, &addr);
kevman 0:38ceb79fef03 626 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 627 }
kevman 0:38ceb79fef03 628
kevman 0:38ceb79fef03 629 int index = -1;
kevman 0:38ceb79fef03 630
kevman 0:38ceb79fef03 631 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 632 if (!dns_query_queue[i]) {
kevman 0:38ceb79fef03 633 index = i;
kevman 0:38ceb79fef03 634 break;
kevman 0:38ceb79fef03 635 }
kevman 0:38ceb79fef03 636 }
kevman 0:38ceb79fef03 637
kevman 0:38ceb79fef03 638 if (index < 0) {
kevman 0:38ceb79fef03 639 dns_mutex->unlock();
kevman 0:38ceb79fef03 640 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 641 }
kevman 0:38ceb79fef03 642
kevman 0:38ceb79fef03 643 DNS_QUERY *query = new (std::nothrow) DNS_QUERY;
kevman 0:38ceb79fef03 644
kevman 0:38ceb79fef03 645 if (!query) {
kevman 0:38ceb79fef03 646 dns_mutex->unlock();
kevman 0:38ceb79fef03 647 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 648 }
kevman 0:38ceb79fef03 649
kevman 0:38ceb79fef03 650 query->host = new (std::nothrow) char[host_len + 1];
kevman 0:38ceb79fef03 651 if (!query->host) {
kevman 0:38ceb79fef03 652 delete query;
kevman 0:38ceb79fef03 653 dns_mutex->unlock();
kevman 0:38ceb79fef03 654 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 655 }
kevman 0:38ceb79fef03 656 strcpy(query->host, host);
kevman 0:38ceb79fef03 657 query->status = NSAPI_ERROR_TIMEOUT;
kevman 0:38ceb79fef03 658 query->callback = callback;
kevman 0:38ceb79fef03 659 query->call_in_cb = call_in_cb;
kevman 0:38ceb79fef03 660 query->stack = stack;
kevman 0:38ceb79fef03 661 query->addr_count = addr_count;
kevman 0:38ceb79fef03 662 query->version = version;
kevman 0:38ceb79fef03 663 query->socket = NULL;
kevman 0:38ceb79fef03 664 query->socket_cb_data = NULL;
kevman 0:38ceb79fef03 665 query->addrs = NULL;
kevman 0:38ceb79fef03 666 query->dns_server = 0;
kevman 0:38ceb79fef03 667 query->retries = MBED_CONF_NSAPI_DNS_RETRIES + 1;
kevman 0:38ceb79fef03 668 query->total_attempts = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS;
kevman 0:38ceb79fef03 669 query->send_success = 0;
kevman 0:38ceb79fef03 670 query->dns_message_id = 0;
kevman 0:38ceb79fef03 671 query->socket_timeout = 0;
kevman 0:38ceb79fef03 672 query->total_timeout = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS * MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME + 500;
kevman 0:38ceb79fef03 673 query->count = 0;
kevman 0:38ceb79fef03 674 query->state = DNS_CREATED;
kevman 0:38ceb79fef03 675
kevman 0:38ceb79fef03 676 query->unique_id = dns_unique_id++;
kevman 0:38ceb79fef03 677 if (query->unique_id > 0x7FFF) {
kevman 0:38ceb79fef03 678 query->unique_id = 1;
kevman 0:38ceb79fef03 679 }
kevman 0:38ceb79fef03 680
kevman 0:38ceb79fef03 681 int ongoing_queries = 0;
kevman 0:38ceb79fef03 682
kevman 0:38ceb79fef03 683 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 684 if (dns_query_queue[i]) {
kevman 0:38ceb79fef03 685 if (!query->socket && dns_query_queue[i]->socket && dns_query_queue[i]->stack == query->stack) {
kevman 0:38ceb79fef03 686 query->socket = dns_query_queue[i]->socket;
kevman 0:38ceb79fef03 687 query->socket_cb_data = dns_query_queue[i]->socket_cb_data;
kevman 0:38ceb79fef03 688 }
kevman 0:38ceb79fef03 689 ongoing_queries++;
kevman 0:38ceb79fef03 690 }
kevman 0:38ceb79fef03 691 }
kevman 0:38ceb79fef03 692
kevman 0:38ceb79fef03 693 dns_query_queue[index] = query;
kevman 0:38ceb79fef03 694
kevman 0:38ceb79fef03 695 // Add some overhead based on number of ongoing queries
kevman 0:38ceb79fef03 696 query->total_timeout += ongoing_queries * 500;
kevman 0:38ceb79fef03 697
kevman 0:38ceb79fef03 698 if (!dns_timer_running) {
kevman 0:38ceb79fef03 699 if (nsapi_dns_call_in(query->call_in_cb, DNS_TIMER_TIMEOUT, mbed::callback(nsapi_dns_query_async_timeout)) != NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 700 delete query->host;
kevman 0:38ceb79fef03 701 delete query;
kevman 0:38ceb79fef03 702 dns_mutex->unlock();
kevman 0:38ceb79fef03 703 return NSAPI_ERROR_NO_MEMORY;
kevman 0:38ceb79fef03 704 }
kevman 0:38ceb79fef03 705 dns_timer_running = true;
kevman 0:38ceb79fef03 706 }
kevman 0:38ceb79fef03 707
kevman 0:38ceb79fef03 708 // Initiates query
kevman 0:38ceb79fef03 709 nsapi_dns_query_async_initiate_next();
kevman 0:38ceb79fef03 710
kevman 0:38ceb79fef03 711 dns_mutex->unlock();
kevman 0:38ceb79fef03 712
kevman 0:38ceb79fef03 713 return query->unique_id;
kevman 0:38ceb79fef03 714 }
kevman 0:38ceb79fef03 715
kevman 0:38ceb79fef03 716 static void nsapi_dns_query_async_initiate_next(void)
kevman 0:38ceb79fef03 717 {
kevman 0:38ceb79fef03 718 int id = INT32_MAX;
kevman 0:38ceb79fef03 719 DNS_QUERY *query = NULL;
kevman 0:38ceb79fef03 720
kevman 0:38ceb79fef03 721 // Trigger next query to start, find one that has been on queue longest
kevman 0:38ceb79fef03 722 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 723 if (dns_query_queue[i]) {
kevman 0:38ceb79fef03 724 if (dns_query_queue[i]->state == DNS_CREATED) {
kevman 0:38ceb79fef03 725 if (dns_query_queue[i]->unique_id <= id) {
kevman 0:38ceb79fef03 726 query = dns_query_queue[i];
kevman 0:38ceb79fef03 727 id = dns_query_queue[i]->unique_id;
kevman 0:38ceb79fef03 728 }
kevman 0:38ceb79fef03 729 // If some query is already ongoing do not trigger
kevman 0:38ceb79fef03 730 } else if (dns_query_queue[i]->state == DNS_INITIATED) {
kevman 0:38ceb79fef03 731 query = NULL;
kevman 0:38ceb79fef03 732 break;
kevman 0:38ceb79fef03 733 }
kevman 0:38ceb79fef03 734 }
kevman 0:38ceb79fef03 735 }
kevman 0:38ceb79fef03 736
kevman 0:38ceb79fef03 737 if (query) {
kevman 0:38ceb79fef03 738 query->state = DNS_INITIATED;
kevman 0:38ceb79fef03 739 nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_create, reinterpret_cast<void *>(query->unique_id)));
kevman 0:38ceb79fef03 740 }
kevman 0:38ceb79fef03 741 }
kevman 0:38ceb79fef03 742
kevman 0:38ceb79fef03 743 static void nsapi_dns_query_async_timeout(void)
kevman 0:38ceb79fef03 744 {
kevman 0:38ceb79fef03 745 dns_mutex->lock();
kevman 0:38ceb79fef03 746
kevman 0:38ceb79fef03 747 DNS_QUERY *query = NULL;
kevman 0:38ceb79fef03 748
kevman 0:38ceb79fef03 749 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 750 if (dns_query_queue[i]) {
kevman 0:38ceb79fef03 751 if (dns_query_queue[i]->state == DNS_CANCELLED) {
kevman 0:38ceb79fef03 752 // Delete cancelled
kevman 0:38ceb79fef03 753 nsapi_dns_query_async_delete(dns_query_queue[i]->unique_id);
kevman 0:38ceb79fef03 754 nsapi_dns_query_async_initiate_next();
kevman 0:38ceb79fef03 755 continue;
kevman 0:38ceb79fef03 756 }
kevman 0:38ceb79fef03 757
kevman 0:38ceb79fef03 758 if (dns_query_queue[i]->total_timeout > DNS_TIMER_TIMEOUT) {
kevman 0:38ceb79fef03 759 dns_query_queue[i]->total_timeout -= DNS_TIMER_TIMEOUT;
kevman 0:38ceb79fef03 760 } else {
kevman 0:38ceb79fef03 761 // If does not already have response, fails
kevman 0:38ceb79fef03 762 if (dns_query_queue[i]->status == NSAPI_ERROR_TIMEOUT) {
kevman 0:38ceb79fef03 763 dns_query_queue[i]->socket_timeout = 0;
kevman 0:38ceb79fef03 764 nsapi_dns_call_in(dns_query_queue[i]->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_response, reinterpret_cast<void *>(dns_query_queue[i]->unique_id)));
kevman 0:38ceb79fef03 765 }
kevman 0:38ceb79fef03 766 }
kevman 0:38ceb79fef03 767
kevman 0:38ceb79fef03 768 if (dns_query_queue[i]->socket_timeout > 0) {
kevman 0:38ceb79fef03 769 if (dns_query_queue[i]->socket_timeout > DNS_TIMER_TIMEOUT) {
kevman 0:38ceb79fef03 770 dns_query_queue[i]->socket_timeout -= DNS_TIMER_TIMEOUT;
kevman 0:38ceb79fef03 771 } else {
kevman 0:38ceb79fef03 772 // Retries
kevman 0:38ceb79fef03 773 dns_query_queue[i]->socket_timeout = 0;
kevman 0:38ceb79fef03 774 nsapi_dns_call_in(dns_query_queue[i]->call_in_cb, 0,
kevman 0:38ceb79fef03 775 mbed::callback(nsapi_dns_query_async_send, reinterpret_cast<void *>(dns_query_queue[i]->unique_id)));
kevman 0:38ceb79fef03 776 }
kevman 0:38ceb79fef03 777 }
kevman 0:38ceb79fef03 778
kevman 0:38ceb79fef03 779 if (!query) {
kevman 0:38ceb79fef03 780 query = dns_query_queue[i];
kevman 0:38ceb79fef03 781 }
kevman 0:38ceb79fef03 782 }
kevman 0:38ceb79fef03 783 }
kevman 0:38ceb79fef03 784
kevman 0:38ceb79fef03 785 // Starts timer again
kevman 0:38ceb79fef03 786 if (query) {
kevman 0:38ceb79fef03 787 nsapi_dns_call_in(query->call_in_cb, DNS_TIMER_TIMEOUT, mbed::callback(nsapi_dns_query_async_timeout));
kevman 0:38ceb79fef03 788 } else {
kevman 0:38ceb79fef03 789 dns_timer_running = false;
kevman 0:38ceb79fef03 790 }
kevman 0:38ceb79fef03 791
kevman 0:38ceb79fef03 792 dns_mutex->unlock();
kevman 0:38ceb79fef03 793 }
kevman 0:38ceb79fef03 794
kevman 0:38ceb79fef03 795 nsapi_error_t nsapi_dns_query_async_cancel(int id)
kevman 0:38ceb79fef03 796 {
kevman 0:38ceb79fef03 797 dns_mutex->lock();
kevman 0:38ceb79fef03 798
kevman 0:38ceb79fef03 799 DNS_QUERY *query = NULL;
kevman 0:38ceb79fef03 800
kevman 0:38ceb79fef03 801 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 802 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == id) {
kevman 0:38ceb79fef03 803 query = dns_query_queue[i];
kevman 0:38ceb79fef03 804 break;
kevman 0:38ceb79fef03 805 }
kevman 0:38ceb79fef03 806 }
kevman 0:38ceb79fef03 807
kevman 0:38ceb79fef03 808 if (!query || query->state == DNS_CANCELLED) {
kevman 0:38ceb79fef03 809 dns_mutex->unlock();
kevman 0:38ceb79fef03 810 return NSAPI_ERROR_PARAMETER;
kevman 0:38ceb79fef03 811 }
kevman 0:38ceb79fef03 812
kevman 0:38ceb79fef03 813 // Mark the query as cancelled, deleted by timer handler
kevman 0:38ceb79fef03 814 query->state = DNS_CANCELLED;
kevman 0:38ceb79fef03 815 // Do not call callback
kevman 0:38ceb79fef03 816 query->callback = 0;
kevman 0:38ceb79fef03 817
kevman 0:38ceb79fef03 818 dns_mutex->unlock();
kevman 0:38ceb79fef03 819
kevman 0:38ceb79fef03 820 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 821 }
kevman 0:38ceb79fef03 822
kevman 0:38ceb79fef03 823 static void nsapi_dns_query_async_create(void *ptr)
kevman 0:38ceb79fef03 824 {
kevman 0:38ceb79fef03 825 dns_mutex->lock();
kevman 0:38ceb79fef03 826
kevman 0:38ceb79fef03 827 int unique_id = reinterpret_cast<int>(ptr);
kevman 0:38ceb79fef03 828
kevman 0:38ceb79fef03 829 DNS_QUERY *query = NULL;
kevman 0:38ceb79fef03 830
kevman 0:38ceb79fef03 831 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 832 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) {
kevman 0:38ceb79fef03 833 query = dns_query_queue[i];
kevman 0:38ceb79fef03 834 break;
kevman 0:38ceb79fef03 835 }
kevman 0:38ceb79fef03 836 }
kevman 0:38ceb79fef03 837
kevman 0:38ceb79fef03 838 if (!query || query->state == DNS_CANCELLED) {
kevman 0:38ceb79fef03 839 // Cancel has been called
kevman 0:38ceb79fef03 840 dns_mutex->unlock();
kevman 0:38ceb79fef03 841 return;
kevman 0:38ceb79fef03 842 }
kevman 0:38ceb79fef03 843
kevman 0:38ceb79fef03 844 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 845 if (dns_query_queue[i] && dns_query_queue[i] != query) {
kevman 0:38ceb79fef03 846 if (!query->socket && dns_query_queue[i]->socket && dns_query_queue[i]->stack == query->stack) {
kevman 0:38ceb79fef03 847 query->socket = dns_query_queue[i]->socket;
kevman 0:38ceb79fef03 848 query->socket_cb_data = dns_query_queue[i]->socket_cb_data;
kevman 0:38ceb79fef03 849 }
kevman 0:38ceb79fef03 850 }
kevman 0:38ceb79fef03 851 }
kevman 0:38ceb79fef03 852
kevman 0:38ceb79fef03 853 UDPSocket *socket;
kevman 0:38ceb79fef03 854
kevman 0:38ceb79fef03 855 if (query->socket) {
kevman 0:38ceb79fef03 856 socket = query->socket;
kevman 0:38ceb79fef03 857 } else {
kevman 0:38ceb79fef03 858 socket = new (std::nothrow) UDPSocket;
kevman 0:38ceb79fef03 859 if (!socket) {
kevman 0:38ceb79fef03 860 nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
kevman 0:38ceb79fef03 861 return;
kevman 0:38ceb79fef03 862 }
kevman 0:38ceb79fef03 863
kevman 0:38ceb79fef03 864 int err = socket->open(query->stack);
kevman 0:38ceb79fef03 865
kevman 0:38ceb79fef03 866 if (err) {
kevman 0:38ceb79fef03 867 delete socket;
kevman 0:38ceb79fef03 868 nsapi_dns_query_async_resp(query, err, NULL);
kevman 0:38ceb79fef03 869 return;
kevman 0:38ceb79fef03 870 }
kevman 0:38ceb79fef03 871
kevman 0:38ceb79fef03 872 socket->set_timeout(0);
kevman 0:38ceb79fef03 873
kevman 0:38ceb79fef03 874 if (!query->socket_cb_data) {
kevman 0:38ceb79fef03 875 query->socket_cb_data = new SOCKET_CB_DATA;
kevman 0:38ceb79fef03 876 }
kevman 0:38ceb79fef03 877 query->socket_cb_data->call_in_cb = query->call_in_cb;
kevman 0:38ceb79fef03 878 query->socket_cb_data->stack = query->stack;
kevman 0:38ceb79fef03 879 socket->sigio(mbed::callback(nsapi_dns_query_async_socket_callback, query->socket_cb_data));
kevman 0:38ceb79fef03 880
kevman 0:38ceb79fef03 881 query->socket = socket;
kevman 0:38ceb79fef03 882 }
kevman 0:38ceb79fef03 883
kevman 0:38ceb79fef03 884 dns_mutex->unlock();
kevman 0:38ceb79fef03 885
kevman 0:38ceb79fef03 886 nsapi_dns_query_async_send(reinterpret_cast<void *>(query->unique_id));
kevman 0:38ceb79fef03 887
kevman 0:38ceb79fef03 888 }
kevman 0:38ceb79fef03 889
kevman 0:38ceb79fef03 890 static nsapi_error_t nsapi_dns_query_async_delete(int unique_id)
kevman 0:38ceb79fef03 891 {
kevman 0:38ceb79fef03 892 int index = -1;
kevman 0:38ceb79fef03 893 DNS_QUERY *query = NULL;
kevman 0:38ceb79fef03 894
kevman 0:38ceb79fef03 895 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 896 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) {
kevman 0:38ceb79fef03 897 query = dns_query_queue[i];
kevman 0:38ceb79fef03 898 index = i;
kevman 0:38ceb79fef03 899 break;
kevman 0:38ceb79fef03 900 }
kevman 0:38ceb79fef03 901 }
kevman 0:38ceb79fef03 902
kevman 0:38ceb79fef03 903 if (!query) {
kevman 0:38ceb79fef03 904 return NSAPI_ERROR_PARAMETER;
kevman 0:38ceb79fef03 905 }
kevman 0:38ceb79fef03 906
kevman 0:38ceb79fef03 907 bool close_socket = true;
kevman 0:38ceb79fef03 908
kevman 0:38ceb79fef03 909 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 910 if (dns_query_queue[i] && dns_query_queue[i] != query && dns_query_queue[i]->socket &&
kevman 0:38ceb79fef03 911 dns_query_queue[i]->stack == query->stack) {
kevman 0:38ceb79fef03 912 close_socket = false;
kevman 0:38ceb79fef03 913 }
kevman 0:38ceb79fef03 914 }
kevman 0:38ceb79fef03 915
kevman 0:38ceb79fef03 916 if (close_socket && query->socket) {
kevman 0:38ceb79fef03 917 query->socket->close();
kevman 0:38ceb79fef03 918 delete query->socket;
kevman 0:38ceb79fef03 919 delete query->socket_cb_data;
kevman 0:38ceb79fef03 920 }
kevman 0:38ceb79fef03 921
kevman 0:38ceb79fef03 922 if (query->addrs) {
kevman 0:38ceb79fef03 923 delete[] query->addrs;
kevman 0:38ceb79fef03 924 }
kevman 0:38ceb79fef03 925
kevman 0:38ceb79fef03 926 delete query->host;
kevman 0:38ceb79fef03 927 delete query;
kevman 0:38ceb79fef03 928 dns_query_queue[index] = NULL;
kevman 0:38ceb79fef03 929
kevman 0:38ceb79fef03 930 return NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 931 }
kevman 0:38ceb79fef03 932
kevman 0:38ceb79fef03 933 static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address)
kevman 0:38ceb79fef03 934 {
kevman 0:38ceb79fef03 935 NetworkStack::hostbyname_cb_t callback = query->callback;
kevman 0:38ceb79fef03 936 nsapi_dns_query_async_delete(query->unique_id);
kevman 0:38ceb79fef03 937 nsapi_dns_query_async_initiate_next();
kevman 0:38ceb79fef03 938
kevman 0:38ceb79fef03 939 dns_mutex->unlock();
kevman 0:38ceb79fef03 940
kevman 0:38ceb79fef03 941 if (callback) {
kevman 0:38ceb79fef03 942 callback(status, address);
kevman 0:38ceb79fef03 943 }
kevman 0:38ceb79fef03 944 }
kevman 0:38ceb79fef03 945
kevman 0:38ceb79fef03 946 static void nsapi_dns_query_async_send(void *ptr)
kevman 0:38ceb79fef03 947 {
kevman 0:38ceb79fef03 948 dns_mutex->lock();
kevman 0:38ceb79fef03 949
kevman 0:38ceb79fef03 950 int unique_id = reinterpret_cast<int>(ptr);
kevman 0:38ceb79fef03 951
kevman 0:38ceb79fef03 952 DNS_QUERY *query = NULL;
kevman 0:38ceb79fef03 953
kevman 0:38ceb79fef03 954 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 955 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) {
kevman 0:38ceb79fef03 956 query = dns_query_queue[i];
kevman 0:38ceb79fef03 957 break;
kevman 0:38ceb79fef03 958 }
kevman 0:38ceb79fef03 959 }
kevman 0:38ceb79fef03 960
kevman 0:38ceb79fef03 961 if (!query || query->state != DNS_INITIATED) {
kevman 0:38ceb79fef03 962 // Cancel has been called
kevman 0:38ceb79fef03 963 dns_mutex->unlock();
kevman 0:38ceb79fef03 964 return;
kevman 0:38ceb79fef03 965 }
kevman 0:38ceb79fef03 966
kevman 0:38ceb79fef03 967 if (query->retries) {
kevman 0:38ceb79fef03 968 query->retries--;
kevman 0:38ceb79fef03 969 } else {
kevman 0:38ceb79fef03 970 query->dns_server++;
kevman 0:38ceb79fef03 971 query->retries = MBED_CONF_NSAPI_DNS_RETRIES;
kevman 0:38ceb79fef03 972 }
kevman 0:38ceb79fef03 973
kevman 0:38ceb79fef03 974 query->dns_message_id = dns_message_id++;
kevman 0:38ceb79fef03 975 if (dns_message_id == 0) {
kevman 0:38ceb79fef03 976 dns_message_id = 1;
kevman 0:38ceb79fef03 977 }
kevman 0:38ceb79fef03 978
kevman 0:38ceb79fef03 979 // create network packet
kevman 0:38ceb79fef03 980 uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE);
kevman 0:38ceb79fef03 981 if (!packet) {
kevman 0:38ceb79fef03 982 nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
kevman 0:38ceb79fef03 983 return;
kevman 0:38ceb79fef03 984 }
kevman 0:38ceb79fef03 985
kevman 0:38ceb79fef03 986 // send the question
kevman 0:38ceb79fef03 987 int len = dns_append_question(packet, query->dns_message_id, query->host, query->version);
kevman 0:38ceb79fef03 988
kevman 0:38ceb79fef03 989 while (true) {
kevman 0:38ceb79fef03 990 SocketAddress dns_addr;
kevman 0:38ceb79fef03 991 nsapi_size_or_error_t err = nsapi_dns_get_server_addr(query->stack, &(query->dns_server), &(query->total_attempts), &(query->send_success), &dns_addr);
kevman 0:38ceb79fef03 992 if (err != NSAPI_ERROR_OK) {
kevman 0:38ceb79fef03 993 nsapi_dns_query_async_resp(query, NSAPI_ERROR_TIMEOUT, NULL);
kevman 0:38ceb79fef03 994 free(packet);
kevman 0:38ceb79fef03 995 return;
kevman 0:38ceb79fef03 996 }
kevman 0:38ceb79fef03 997
kevman 0:38ceb79fef03 998 err = query->socket->sendto(dns_addr, packet, len);
kevman 0:38ceb79fef03 999
kevman 0:38ceb79fef03 1000 if (err < 0) {
kevman 0:38ceb79fef03 1001 query->dns_server++;
kevman 0:38ceb79fef03 1002 } else {
kevman 0:38ceb79fef03 1003 break;
kevman 0:38ceb79fef03 1004 }
kevman 0:38ceb79fef03 1005 }
kevman 0:38ceb79fef03 1006
kevman 0:38ceb79fef03 1007 query->send_success++;
kevman 0:38ceb79fef03 1008
kevman 0:38ceb79fef03 1009 if (query->total_attempts) {
kevman 0:38ceb79fef03 1010 query->total_attempts--;
kevman 0:38ceb79fef03 1011 }
kevman 0:38ceb79fef03 1012
kevman 0:38ceb79fef03 1013 free(packet);
kevman 0:38ceb79fef03 1014
kevman 0:38ceb79fef03 1015 query->socket_timeout = MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME;
kevman 0:38ceb79fef03 1016
kevman 0:38ceb79fef03 1017 dns_mutex->unlock();
kevman 0:38ceb79fef03 1018 }
kevman 0:38ceb79fef03 1019
kevman 0:38ceb79fef03 1020 static void nsapi_dns_query_async_socket_callback(void *ptr)
kevman 0:38ceb79fef03 1021 {
kevman 0:38ceb79fef03 1022 SOCKET_CB_DATA *cb_data = static_cast<SOCKET_CB_DATA *>(ptr);
kevman 0:38ceb79fef03 1023
kevman 0:38ceb79fef03 1024 if (cb_data) {
kevman 0:38ceb79fef03 1025 nsapi_dns_call_in(cb_data->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_socket_callback_handle, cb_data->stack));
kevman 0:38ceb79fef03 1026 }
kevman 0:38ceb79fef03 1027 }
kevman 0:38ceb79fef03 1028
kevman 0:38ceb79fef03 1029 static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack)
kevman 0:38ceb79fef03 1030 {
kevman 0:38ceb79fef03 1031 UDPSocket *socket = NULL;
kevman 0:38ceb79fef03 1032
kevman 0:38ceb79fef03 1033 dns_mutex->lock();
kevman 0:38ceb79fef03 1034
kevman 0:38ceb79fef03 1035 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 1036 if (dns_query_queue[i] && dns_query_queue[i]->stack == stack) {
kevman 0:38ceb79fef03 1037 socket = dns_query_queue[i]->socket;
kevman 0:38ceb79fef03 1038 break;
kevman 0:38ceb79fef03 1039 }
kevman 0:38ceb79fef03 1040 }
kevman 0:38ceb79fef03 1041
kevman 0:38ceb79fef03 1042 if (socket) {
kevman 0:38ceb79fef03 1043 // create network packet
kevman 0:38ceb79fef03 1044 uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE);
kevman 0:38ceb79fef03 1045 if (!packet) {
kevman 0:38ceb79fef03 1046 dns_mutex->unlock();
kevman 0:38ceb79fef03 1047 return;
kevman 0:38ceb79fef03 1048 }
kevman 0:38ceb79fef03 1049
kevman 0:38ceb79fef03 1050 while (true) {
kevman 0:38ceb79fef03 1051 // recv the response
kevman 0:38ceb79fef03 1052 nsapi_size_or_error_t size = socket->recvfrom(NULL, packet, DNS_BUFFER_SIZE);
kevman 0:38ceb79fef03 1053
kevman 0:38ceb79fef03 1054 if (size < DNS_RESPONSE_MIN_SIZE) {
kevman 0:38ceb79fef03 1055 break;
kevman 0:38ceb79fef03 1056 }
kevman 0:38ceb79fef03 1057
kevman 0:38ceb79fef03 1058 // gets id from response to associate with correct query
kevman 0:38ceb79fef03 1059 uint16_t id = (packet[0] << 8) | packet[1];
kevman 0:38ceb79fef03 1060
kevman 0:38ceb79fef03 1061 DNS_QUERY *query = NULL;
kevman 0:38ceb79fef03 1062
kevman 0:38ceb79fef03 1063 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 1064 if (dns_query_queue[i] && dns_query_queue[i]->dns_message_id == id) {
kevman 0:38ceb79fef03 1065 query = dns_query_queue[i];
kevman 0:38ceb79fef03 1066 break;
kevman 0:38ceb79fef03 1067 }
kevman 0:38ceb79fef03 1068 }
kevman 0:38ceb79fef03 1069
kevman 0:38ceb79fef03 1070 if (!query || query->state != DNS_INITIATED) {
kevman 0:38ceb79fef03 1071 continue;
kevman 0:38ceb79fef03 1072 }
kevman 0:38ceb79fef03 1073
kevman 0:38ceb79fef03 1074 int requested_count = 1;
kevman 0:38ceb79fef03 1075 if (query->addr_count > 1) {
kevman 0:38ceb79fef03 1076 requested_count = query->addr_count;
kevman 0:38ceb79fef03 1077 }
kevman 0:38ceb79fef03 1078
kevman 0:38ceb79fef03 1079 query->addrs = new (std::nothrow) nsapi_addr_t[requested_count];
kevman 0:38ceb79fef03 1080
kevman 0:38ceb79fef03 1081 int resp = dns_scan_response(packet, id, &(query->ttl), query->addrs, requested_count);
kevman 0:38ceb79fef03 1082
kevman 0:38ceb79fef03 1083 // Ignore invalid responses
kevman 0:38ceb79fef03 1084 if (resp < 0) {
kevman 0:38ceb79fef03 1085 delete[] query->addrs;
kevman 0:38ceb79fef03 1086 query->addrs = 0;
kevman 0:38ceb79fef03 1087 } else {
kevman 0:38ceb79fef03 1088 query->count = resp;
kevman 0:38ceb79fef03 1089 query->status = NSAPI_ERROR_DNS_FAILURE; // Used in case failure, otherwise ok
kevman 0:38ceb79fef03 1090 query->socket_timeout = 0;
kevman 0:38ceb79fef03 1091 nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_response, reinterpret_cast<void *>(query->unique_id)));
kevman 0:38ceb79fef03 1092 }
kevman 0:38ceb79fef03 1093 }
kevman 0:38ceb79fef03 1094
kevman 0:38ceb79fef03 1095 free(packet);
kevman 0:38ceb79fef03 1096 }
kevman 0:38ceb79fef03 1097
kevman 0:38ceb79fef03 1098 dns_mutex->unlock();
kevman 0:38ceb79fef03 1099 }
kevman 0:38ceb79fef03 1100
kevman 0:38ceb79fef03 1101 static void nsapi_dns_query_async_response(void *ptr)
kevman 0:38ceb79fef03 1102 {
kevman 0:38ceb79fef03 1103 dns_mutex->lock();
kevman 0:38ceb79fef03 1104
kevman 0:38ceb79fef03 1105 int unique_id = reinterpret_cast<int>(ptr);
kevman 0:38ceb79fef03 1106
kevman 0:38ceb79fef03 1107 DNS_QUERY *query = NULL;
kevman 0:38ceb79fef03 1108
kevman 0:38ceb79fef03 1109 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
kevman 0:38ceb79fef03 1110 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) {
kevman 0:38ceb79fef03 1111 query = dns_query_queue[i];
kevman 0:38ceb79fef03 1112 break;
kevman 0:38ceb79fef03 1113 }
kevman 0:38ceb79fef03 1114 }
kevman 0:38ceb79fef03 1115
kevman 0:38ceb79fef03 1116 if (query && query->state == DNS_INITIATED) {
kevman 0:38ceb79fef03 1117 SocketAddress *addresses = NULL;
kevman 0:38ceb79fef03 1118 nsapi_error_t status = query->status;
kevman 0:38ceb79fef03 1119
kevman 0:38ceb79fef03 1120 if (query->count > 0) {
kevman 0:38ceb79fef03 1121 addresses = new (std::nothrow) SocketAddress[query->count];
kevman 0:38ceb79fef03 1122
kevman 0:38ceb79fef03 1123 for (int i = 0; i < query->count; i++) {
kevman 0:38ceb79fef03 1124 addresses[i].set_addr(query->addrs[i]);
kevman 0:38ceb79fef03 1125 }
kevman 0:38ceb79fef03 1126
kevman 0:38ceb79fef03 1127 // Adds address to cache
kevman 0:38ceb79fef03 1128 nsapi_dns_cache_add(query->host, &(query->addrs[0]), query->ttl);
kevman 0:38ceb79fef03 1129
kevman 0:38ceb79fef03 1130 status = NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 1131 if (query->addr_count > 0) {
kevman 0:38ceb79fef03 1132 status = query->count;
kevman 0:38ceb79fef03 1133 }
kevman 0:38ceb79fef03 1134 }
kevman 0:38ceb79fef03 1135
kevman 0:38ceb79fef03 1136 nsapi_dns_query_async_resp(query, status, addresses);
kevman 0:38ceb79fef03 1137 delete[] addresses;
kevman 0:38ceb79fef03 1138 } else {
kevman 0:38ceb79fef03 1139 dns_mutex->unlock();
kevman 0:38ceb79fef03 1140 }
kevman 0:38ceb79fef03 1141 }