mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 31 06:02:27 2019 +0000
Revision:
1:9db0e321a9f4
Parent:
0:5b88d5760320
updated based on mbed-os5.15.0

Who changed what in which revision?

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