mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 17 23:23:45 2019 +0000
Revision:
0:5b88d5760320
Child:
1:9db0e321a9f4
mbed-os5 only for TYBLE16

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