Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
nsapi_dns.cpp
00001 /* nsapi_dns.cpp 00002 * Original work Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) 00003 * Modified work Copyright (c) 2015 ARM Limited 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /* Declare __STDC_LIMIT_MACROS so stdint.h defines INT32_MAX when using C++ */ 00019 #define __STDC_LIMIT_MACROS 00020 00021 #include "nsapi_dns.h" 00022 #include "netsocket/UDPSocket.h" 00023 #include <string.h> 00024 #include <stdlib.h> 00025 #include <stdio.h> 00026 #include <stdint.h> 00027 #include "mbed_shared_queues.h" 00028 #include "events/EventQueue.h" 00029 #include "OnboardNetworkStack.h" 00030 #include "Kernel.h" 00031 #include "PlatformMutex.h" 00032 #include "SingletonPtr.h" 00033 00034 #define CLASS_IN 1 00035 00036 #define RR_A 1 00037 #define RR_AAAA 28 00038 00039 // DNS options 00040 #define DNS_BUFFER_SIZE 512 00041 #define DNS_SERVERS_SIZE 5 00042 #define DNS_RESPONSE_MIN_SIZE 12 00043 #define DNS_STACK_SERVERS_NUM 5 00044 #define DNS_QUERY_QUEUE_SIZE 5 00045 #define DNS_HOST_NAME_MAX_LEN 255 00046 #define DNS_TIMER_TIMEOUT 100 00047 00048 struct DNS_CACHE { 00049 nsapi_addr_t address; 00050 char *host; 00051 uint64_t expires; /*!< time to live in milliseconds */ 00052 uint64_t accessed; /*!< last accessed */ 00053 }; 00054 00055 struct SOCKET_CB_DATA { 00056 call_in_callback_cb_t call_in_cb; 00057 NetworkStack *stack; 00058 }; 00059 00060 enum dns_state { 00061 DNS_CREATED, /*!< created, not yet making query to network */ 00062 DNS_INITIATED, /*!< making query to network */ 00063 DNS_CANCELLED /*!< cancelled, callback will not be called */ 00064 }; 00065 00066 struct DNS_QUERY { 00067 intptr_t unique_id; 00068 nsapi_error_t status; 00069 NetworkStack *stack; 00070 char *host; 00071 const char *interface_name; 00072 NetworkStack::hostbyname_cb_t callback; 00073 call_in_callback_cb_t call_in_cb; 00074 nsapi_size_t addr_count; 00075 nsapi_version_t version; 00076 UDPSocket *socket; 00077 SOCKET_CB_DATA *socket_cb_data; 00078 nsapi_addr_t *addrs; 00079 uint32_t ttl; 00080 uint32_t total_timeout; 00081 uint32_t socket_timeout; 00082 uint16_t dns_message_id; 00083 uint8_t dns_server; 00084 uint8_t retries; 00085 uint8_t total_attempts; 00086 uint8_t send_success; 00087 uint8_t count; 00088 dns_state state; 00089 }; 00090 00091 static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl); 00092 static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address); 00093 static void nsapi_dns_cache_reset(); 00094 00095 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); 00096 00097 static void nsapi_dns_query_async_create(void *ptr); 00098 static nsapi_error_t nsapi_dns_query_async_delete(intptr_t unique_id); 00099 static void nsapi_dns_query_async_send(void *ptr); 00100 static void nsapi_dns_query_async_timeout(void); 00101 static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address); 00102 static void nsapi_dns_query_async_socket_callback(void *ptr); 00103 static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack); 00104 static void nsapi_dns_query_async_response(void *ptr); 00105 static void nsapi_dns_query_async_initiate_next(void); 00106 00107 // *INDENT-OFF* 00108 static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = { 00109 {NSAPI_IPv4 , {8, 8, 8, 8}}, // Google 00110 {NSAPI_IPv6 , {0x20,0x01, 0x48,0x60, 0x48,0x60, 0,0, // Google 00111 0,0, 0,0, 0,0, 0x88,0x88}}, 00112 {NSAPI_IPv4 , {209, 244, 0, 3}}, // Level 3 00113 {NSAPI_IPv4 , {84, 200, 69, 80}}, // DNS.WATCH 00114 {NSAPI_IPv6 , {0x20,0x01, 0x16,0x08, 0,0x10, 0,0x25, // DNS.WATCH 00115 0,0, 0,0, 0x1c,0x04, 0xb1,0x2f}}, 00116 }; 00117 // *INDENT-ON* 00118 00119 #if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0) 00120 static DNS_CACHE *dns_cache[MBED_CONF_NSAPI_DNS_CACHE_SIZE]; 00121 // Protects cache shared between blocking and asynchronous calls 00122 static SingletonPtr<PlatformMutex> dns_cache_mutex; 00123 #endif 00124 00125 static uint16_t dns_message_id = 1; 00126 static intptr_t dns_unique_id = 1; 00127 static DNS_QUERY *dns_query_queue[DNS_QUERY_QUEUE_SIZE]; 00128 // Protects from several threads running asynchronous DNS 00129 static SingletonPtr<PlatformMutex> dns_mutex; 00130 static SingletonPtr<call_in_callback_cb_t> dns_call_in; 00131 static bool dns_timer_running = false; 00132 00133 // DNS server configuration 00134 extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr, const char *interface_name) 00135 { 00136 // check if addr was already added 00137 for (int i = 0; i < DNS_SERVERS_SIZE; i++) { 00138 if (memcmp(&addr, &dns_servers[i], sizeof(nsapi_addr_t)) == 0) { 00139 return NSAPI_ERROR_OK ; 00140 } 00141 } 00142 00143 memmove(&dns_servers[1], &dns_servers[0], 00144 (DNS_SERVERS_SIZE - 1)*sizeof(nsapi_addr_t)); 00145 00146 dns_servers[0] = addr; 00147 return NSAPI_ERROR_OK ; 00148 } 00149 00150 00151 // DNS packet parsing 00152 static void dns_append_byte(uint8_t **p, uint8_t byte) 00153 { 00154 *(*p)++ = byte; 00155 } 00156 00157 static void dns_append_word(uint8_t **p, uint16_t word) 00158 { 00159 00160 dns_append_byte(p, 0xff & (word >> 8)); 00161 dns_append_byte(p, 0xff & (word >> 0)); 00162 } 00163 00164 static void dns_append_name(uint8_t **p, const char *name, uint8_t len) 00165 { 00166 dns_append_byte(p, len); 00167 memcpy(*p, name, len); 00168 *p += len; 00169 } 00170 00171 static uint8_t dns_scan_byte(const uint8_t **p) 00172 { 00173 return *(*p)++; 00174 } 00175 00176 static uint16_t dns_scan_word(const uint8_t **p) 00177 { 00178 uint16_t a = dns_scan_byte(p); 00179 uint16_t b = dns_scan_byte(p); 00180 return (a << 8) | b; 00181 } 00182 00183 static uint32_t dns_scan_word32(const uint8_t **p) 00184 { 00185 uint32_t value = dns_scan_byte(p) << 24; 00186 value |= dns_scan_byte(p) << 16; 00187 value |= dns_scan_byte(p) << 8; 00188 value |= dns_scan_byte(p); 00189 00190 return value; 00191 } 00192 00193 static int dns_append_question(uint8_t *ptr, uint16_t id, const char *host, nsapi_version_t version) 00194 { 00195 uint8_t *s_ptr = ptr; 00196 uint8_t **p = &ptr; 00197 00198 // fill the header 00199 dns_append_word(p, id); // id = 1 00200 dns_append_word(p, 0x0100); // flags = recursion required 00201 dns_append_word(p, 1); // qdcount = 1 00202 dns_append_word(p, 0); // ancount = 0 00203 dns_append_word(p, 0); // nscount = 0 00204 dns_append_word(p, 0); // arcount = 0 00205 00206 // fill out the question names 00207 while (host[0]) { 00208 size_t label_len = strcspn(host, "."); 00209 dns_append_name(p, host, label_len); 00210 host += label_len + (host[label_len] == '.'); 00211 } 00212 00213 dns_append_byte(p, 0); 00214 00215 // fill out question footer 00216 if (version != NSAPI_IPv6 ) { 00217 dns_append_word(p, RR_A); // qtype = ipv4 00218 } else { 00219 dns_append_word(p, RR_AAAA); // qtype = ipv6 00220 } 00221 dns_append_word(p, CLASS_IN); 00222 00223 return *p - s_ptr; 00224 } 00225 00226 static int dns_scan_response(const uint8_t *ptr, uint16_t exp_id, uint32_t *ttl, nsapi_addr_t *addr, unsigned addr_count) 00227 { 00228 const uint8_t **p = &ptr; 00229 00230 // scan header 00231 uint16_t id = dns_scan_word(p); 00232 uint16_t flags = dns_scan_word(p); 00233 bool qr = 0x1 & (flags >> 15); 00234 uint8_t opcode = 0xf & (flags >> 11); 00235 uint8_t rcode = 0xf & (flags >> 0); 00236 00237 uint16_t qdcount = dns_scan_word(p); // qdcount 00238 uint16_t ancount = dns_scan_word(p); // ancount 00239 dns_scan_word(p); // nscount 00240 dns_scan_word(p); // arcount 00241 00242 // verify header is response to query 00243 if (!(id == exp_id && qr && opcode == 0)) { 00244 return -1; 00245 } 00246 00247 if (rcode != 0) { 00248 return 0; 00249 } 00250 00251 // skip questions 00252 for (int i = 0; i < qdcount; i++) { 00253 while (true) { 00254 uint8_t len = dns_scan_byte(p); 00255 if (len == 0) { 00256 break; 00257 } 00258 00259 *p += len; 00260 } 00261 00262 dns_scan_word(p); // qtype 00263 dns_scan_word(p); // qclass 00264 } 00265 00266 // scan each response 00267 unsigned count = 0; 00268 00269 for (int i = 0; i < ancount && count < addr_count; i++) { 00270 while (true) { 00271 uint8_t len = dns_scan_byte(p); 00272 if (len == 0) { 00273 break; 00274 } else if (len & 0xc0) { // this is link 00275 dns_scan_byte(p); 00276 break; 00277 } 00278 00279 *p += len; 00280 } 00281 00282 uint16_t rtype = dns_scan_word(p); // rtype 00283 uint16_t rclass = dns_scan_word(p); // rclass 00284 uint32_t ttl_val = dns_scan_word32(p); // ttl 00285 uint16_t rdlength = dns_scan_word(p); // rdlength 00286 00287 if (i == 0) { 00288 // Is interested only on first address that is stored to cache 00289 if (ttl_val > INT32_MAX) { 00290 ttl_val = INT32_MAX; 00291 } 00292 *ttl = ttl_val; 00293 } 00294 00295 if (rtype == RR_A && rclass == CLASS_IN && rdlength == NSAPI_IPv4_BYTES) { 00296 // accept A record 00297 addr->version = NSAPI_IPv4 ; 00298 for (int i = 0; i < NSAPI_IPv4_BYTES; i++) { 00299 addr->bytes[i] = dns_scan_byte(p); 00300 } 00301 00302 addr += 1; 00303 count += 1; 00304 } else if (rtype == RR_AAAA && rclass == CLASS_IN && rdlength == NSAPI_IPv6_BYTES) { 00305 // accept AAAA record 00306 addr->version = NSAPI_IPv6 ; 00307 for (int i = 0; i < NSAPI_IPv6_BYTES; i++) { 00308 addr->bytes[i] = dns_scan_byte(p); 00309 } 00310 00311 addr += 1; 00312 count += 1; 00313 } else { 00314 // skip unrecognized records 00315 *p += rdlength; 00316 } 00317 } 00318 00319 return count; 00320 } 00321 00322 static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl) 00323 { 00324 #if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0) 00325 // RFC 1034: if TTL is zero, entry is not added to cache 00326 if (ttl == 0) { 00327 return; 00328 } 00329 00330 // Checks if already cached 00331 if (nsapi_dns_cache_find(host, address->version, NULL) == NSAPI_ERROR_OK ) { 00332 return; 00333 } 00334 00335 dns_cache_mutex->lock(); 00336 00337 int index = -1; 00338 uint64_t accessed = UINT64_MAX; 00339 00340 // Finds free or last accessed entry 00341 for (int i = 0; i < MBED_CONF_NSAPI_DNS_CACHE_SIZE; i++) { 00342 if (!dns_cache[i]) { 00343 index = i; 00344 break; 00345 } else if (dns_cache[i]->accessed <= accessed) { 00346 accessed = dns_cache[i]->accessed; 00347 index = i; 00348 } 00349 } 00350 00351 if (index < 0) { 00352 dns_cache_mutex->unlock(); 00353 return; 00354 } 00355 00356 // Allocates in case entry is free, otherwise reuses 00357 if (!dns_cache[index]) { 00358 dns_cache[index] = new (std::nothrow) DNS_CACHE; 00359 } else { 00360 delete dns_cache[index]->host; 00361 } 00362 00363 if (dns_cache[index]) { 00364 dns_cache[index]->address = *address; 00365 dns_cache[index]->host = new (std::nothrow) char[strlen(host) + 1]; 00366 strcpy(dns_cache[index]->host, host); 00367 uint64_t ms_count = rtos::Kernel::get_ms_count(); 00368 dns_cache[index]->expires = ms_count + (uint64_t) ttl * 1000; 00369 dns_cache[index]->accessed = ms_count; 00370 } 00371 00372 dns_cache_mutex->unlock(); 00373 #endif 00374 } 00375 00376 static nsapi_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address) 00377 { 00378 nsapi_error_t ret_val = NSAPI_ERROR_NO_ADDRESS ; 00379 00380 #if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0) 00381 dns_cache_mutex->lock(); 00382 00383 for (int i = 0; i < MBED_CONF_NSAPI_DNS_CACHE_SIZE; i++) { 00384 if (dns_cache[i]) { 00385 uint64_t ms_count = rtos::Kernel::get_ms_count(); 00386 // Checks all entries for expired entries 00387 if (ms_count > dns_cache[i]->expires) { 00388 delete dns_cache[i]->host; 00389 delete dns_cache[i]; 00390 dns_cache[i] = NULL; 00391 } else if ((version == NSAPI_UNSPEC || version == dns_cache[i]->address.version) && 00392 strcmp(dns_cache[i]->host, host) == 0) { 00393 if (address) { 00394 *address = dns_cache[i]->address; 00395 } 00396 dns_cache[i]->accessed = ms_count; 00397 ret_val = NSAPI_ERROR_OK ; 00398 } 00399 } 00400 } 00401 00402 dns_cache_mutex->unlock(); 00403 #endif 00404 00405 return ret_val; 00406 } 00407 00408 static void nsapi_dns_cache_reset() 00409 { 00410 #if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0) 00411 dns_cache_mutex->lock(); 00412 for (int i = 0; i < MBED_CONF_NSAPI_DNS_CACHE_SIZE; i++) { 00413 if (dns_cache[i]) { 00414 delete[] dns_cache[i]->host; 00415 dns_cache[i]->host = NULL; 00416 delete dns_cache[i]; 00417 dns_cache[i] = NULL; 00418 } 00419 } 00420 dns_cache_mutex->unlock(); 00421 #endif 00422 } 00423 00424 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) 00425 { 00426 bool dns_addr_set = false; 00427 00428 if (*total_attempts == 0) { 00429 return NSAPI_ERROR_NO_ADDRESS ; 00430 } 00431 00432 if (*index >= DNS_SERVERS_SIZE + DNS_STACK_SERVERS_NUM) { 00433 // If there are total attempts left and send to has been successful at least once on this round 00434 if (*total_attempts && *send_success) { 00435 *index = 0; 00436 *send_success = 0; 00437 } else { 00438 return NSAPI_ERROR_NO_ADDRESS ; 00439 } 00440 } 00441 00442 if (*index < DNS_STACK_SERVERS_NUM) { 00443 nsapi_error_t ret = stack->get_dns_server(*index, dns_addr, interface_name); 00444 if (ret < 0) { 00445 *index = DNS_STACK_SERVERS_NUM; 00446 } else { 00447 dns_addr_set = true; 00448 } 00449 } 00450 00451 if (!dns_addr_set) { 00452 dns_addr->set_addr(dns_servers[*index - DNS_STACK_SERVERS_NUM]); 00453 } 00454 00455 dns_addr->set_port(53); 00456 00457 return NSAPI_ERROR_OK ; 00458 } 00459 00460 // core query function 00461 static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host, 00462 nsapi_addr_t *addr, unsigned addr_count, const char *interface_name, nsapi_version_t version) 00463 { 00464 // check for valid host name 00465 int host_len = host ? strlen(host) : 0; 00466 if (host_len > DNS_HOST_NAME_MAX_LEN || host_len == 0) { 00467 return NSAPI_ERROR_PARAMETER ; 00468 } 00469 00470 // check cache 00471 if (nsapi_dns_cache_find(host, version, addr) == NSAPI_ERROR_OK ) { 00472 return 1; 00473 } 00474 00475 // create a udp socket 00476 UDPSocket socket; 00477 int err = socket.open(stack); 00478 if (err) { 00479 return err; 00480 } 00481 00482 socket.set_timeout (MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME); 00483 00484 if (interface_name != NULL) { 00485 socket.setsockopt (NSAPI_SOCKET , NSAPI_BIND_TO_DEVICE , interface_name, NSAPI_INTERFACE_NAME_MAX_SIZE); 00486 } 00487 // create network packet 00488 uint8_t *const packet = (uint8_t *)malloc(DNS_BUFFER_SIZE); 00489 if (!packet) { 00490 return NSAPI_ERROR_NO_MEMORY ; 00491 } 00492 00493 nsapi_size_or_error_t result = NSAPI_ERROR_DNS_FAILURE ; 00494 00495 uint8_t retries = MBED_CONF_NSAPI_DNS_RETRIES; 00496 uint8_t index = 0; 00497 uint8_t total_attempts = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS; 00498 uint8_t send_success = 0; 00499 00500 // check against each dns server 00501 while (true) { 00502 SocketAddress dns_addr; 00503 err = nsapi_dns_get_server_addr(stack, &index, &total_attempts, &send_success, &dns_addr, interface_name); 00504 if (err != NSAPI_ERROR_OK ) { 00505 break; 00506 } 00507 00508 if (version != NSAPI_UNSPEC && (dns_addr.get_ip_version() != version)) { 00509 retries = MBED_CONF_NSAPI_DNS_RETRIES; 00510 index++; 00511 continue; 00512 } 00513 // send the question 00514 int len = dns_append_question(packet, 1, host, dns_addr.get_ip_version()); 00515 00516 err = socket.sendto(dns_addr, packet, len); 00517 // send may fail for various reasons, including wrong address type - move on 00518 if (err < 0) { 00519 // goes to next dns server 00520 retries = MBED_CONF_NSAPI_DNS_RETRIES; 00521 index++; 00522 continue; 00523 } 00524 00525 send_success++; 00526 00527 if (total_attempts) { 00528 total_attempts--; 00529 } 00530 00531 // recv the response 00532 err = socket.recvfrom(NULL, packet, DNS_BUFFER_SIZE); 00533 if (err == NSAPI_ERROR_WOULD_BLOCK ) { 00534 if (retries) { 00535 // retries 00536 retries--; 00537 } else { 00538 // goes to next dns server 00539 retries = MBED_CONF_NSAPI_DNS_RETRIES; 00540 index++; 00541 } 00542 continue; 00543 } else if (err < 0) { 00544 result = err; 00545 break; 00546 } 00547 00548 const uint8_t *response = packet; 00549 uint32_t ttl; 00550 int resp = dns_scan_response(response, 1, &ttl, addr, addr_count); 00551 if (resp > 0) { 00552 nsapi_dns_cache_add(host, addr, ttl); 00553 result = resp; 00554 } else if (resp < 0) { 00555 continue; 00556 } 00557 00558 /* The DNS response is final, no need to check other servers */ 00559 break; 00560 } 00561 00562 // clean up packet 00563 free(packet); 00564 00565 // clean up udp 00566 err = socket.close(); 00567 if (err) { 00568 return err; 00569 } 00570 00571 // return result 00572 return result; 00573 } 00574 00575 // convenience functions for other forms of queries 00576 extern "C" nsapi_size_or_error_t nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host, 00577 nsapi_addr_t *addr, nsapi_size_t addr_count, const char *interface_name, nsapi_version_t version) 00578 { 00579 NetworkStack *nstack = nsapi_create_stack(stack); 00580 return nsapi_dns_query_multiple(nstack, host, addr, addr_count, interface_name, version); 00581 } 00582 00583 nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host, 00584 SocketAddress *addresses, nsapi_size_t addr_count, const char *interface_name, nsapi_version_t version) 00585 { 00586 nsapi_addr_t *addrs = new (std::nothrow) nsapi_addr_t[addr_count]; 00587 nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, addrs, addr_count, interface_name, version); 00588 00589 if (result > 0) { 00590 for (int i = 0; i < result; i++) { 00591 addresses[i].set_addr(addrs[i]); 00592 } 00593 } 00594 00595 delete[] addrs; 00596 return result; 00597 } 00598 00599 extern "C" nsapi_error_t nsapi_dns_query(nsapi_stack_t *stack, const char *host, 00600 nsapi_addr_t *addr, nsapi_version_t version) 00601 { 00602 NetworkStack *nstack = nsapi_create_stack(stack); 00603 nsapi_size_or_error_t result = nsapi_dns_query_multiple(nstack, host, addr, 1, NULL, version); 00604 return (nsapi_error_t)((result > 0) ? 0 : result); 00605 } 00606 00607 nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host, 00608 SocketAddress *address, nsapi_version_t version) 00609 { 00610 nsapi_addr_t addr; 00611 nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, &addr, 1, NULL, version); 00612 address->set_addr(addr); 00613 return (nsapi_error_t)((result > 0) ? 0 : result); 00614 } 00615 00616 nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host, 00617 SocketAddress *address, const char *interface_name, nsapi_version_t version) 00618 { 00619 nsapi_addr_t addr; 00620 nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, &addr, 1, interface_name, version); 00621 address->set_addr(addr); 00622 return (nsapi_error_t)((result > 0) ? 0 : result); 00623 } 00624 00625 nsapi_value_or_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host, 00626 NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb, 00627 nsapi_version_t version) 00628 { 00629 return nsapi_dns_query_multiple_async(stack, host, callback, 0, call_in_cb, NULL, version); 00630 } 00631 00632 nsapi_value_or_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host, 00633 NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb, 00634 const char *interface_name, nsapi_version_t version) 00635 { 00636 return nsapi_dns_query_multiple_async(stack, host, callback, 0, call_in_cb, interface_name, version); 00637 } 00638 00639 void nsapi_dns_call_in_set(call_in_callback_cb_t callback) 00640 { 00641 *dns_call_in.get() = callback; 00642 } 00643 00644 void nsapi_dns_reset() 00645 { 00646 nsapi_dns_cache_reset(); 00647 dns_message_id = 1; 00648 dns_unique_id = 1; 00649 } 00650 00651 nsapi_error_t nsapi_dns_call_in(call_in_callback_cb_t cb, int delay, mbed::Callback<void()> func) 00652 { 00653 if (*dns_call_in.get()) { 00654 dns_call_in->call(delay, func); 00655 } else { 00656 return cb(delay, func); 00657 } 00658 return NSAPI_ERROR_OK ; 00659 } 00660 00661 nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host, 00662 NetworkStack::hostbyname_cb_t callback, nsapi_size_t addr_count, 00663 call_in_callback_cb_t call_in_cb, const char *interface_name, nsapi_version_t version) 00664 { 00665 dns_mutex->lock(); 00666 00667 if (!stack) { 00668 return NSAPI_ERROR_PARAMETER ; 00669 } 00670 00671 // check for valid host name 00672 int host_len = host ? strlen(host) : 0; 00673 if (host_len > DNS_HOST_NAME_MAX_LEN || host_len == 0) { 00674 dns_mutex->unlock(); 00675 return NSAPI_ERROR_PARAMETER ; 00676 } 00677 00678 nsapi_addr address; 00679 if (nsapi_dns_cache_find(host, version, &address) == NSAPI_ERROR_OK ) { 00680 SocketAddress addr(address); 00681 dns_mutex->unlock(); 00682 callback(NSAPI_ERROR_OK , &addr); 00683 return NSAPI_ERROR_OK ; 00684 } 00685 00686 int index = -1; 00687 00688 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00689 if (!dns_query_queue[i]) { 00690 index = i; 00691 break; 00692 } 00693 } 00694 00695 if (index < 0) { 00696 dns_mutex->unlock(); 00697 return NSAPI_ERROR_NO_MEMORY ; 00698 } 00699 00700 DNS_QUERY *query = new (std::nothrow) DNS_QUERY; 00701 00702 if (!query) { 00703 dns_mutex->unlock(); 00704 return NSAPI_ERROR_NO_MEMORY ; 00705 } 00706 00707 query->host = new (std::nothrow) char[host_len + 1]; 00708 if (!query->host) { 00709 delete query; 00710 dns_mutex->unlock(); 00711 return NSAPI_ERROR_NO_MEMORY ; 00712 } 00713 strcpy(query->host, host); 00714 query->status = NSAPI_ERROR_TIMEOUT ; 00715 query->callback = callback; 00716 query->call_in_cb = call_in_cb; 00717 query->stack = stack; 00718 query->addr_count = addr_count; 00719 query->version = version; 00720 query->socket = NULL; 00721 query->socket_cb_data = NULL; 00722 query->addrs = NULL; 00723 query->dns_server = 0; 00724 query->retries = MBED_CONF_NSAPI_DNS_RETRIES + 1; 00725 query->total_attempts = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS; 00726 query->send_success = 0; 00727 query->dns_message_id = 0; 00728 query->socket_timeout = 0; 00729 query->total_timeout = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS * MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME + 500; 00730 query->count = 0; 00731 query->state = DNS_CREATED; 00732 query->interface_name = interface_name; 00733 query->unique_id = dns_unique_id++; 00734 if (query->unique_id > 0x7FFF) { 00735 query->unique_id = 1; 00736 } 00737 00738 int ongoing_queries = 0; 00739 00740 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00741 if (dns_query_queue[i]) { 00742 if (!query->socket && dns_query_queue[i]->socket && dns_query_queue[i]->stack == query->stack) { 00743 query->socket = dns_query_queue[i]->socket; 00744 query->socket_cb_data = dns_query_queue[i]->socket_cb_data; 00745 } 00746 ongoing_queries++; 00747 } 00748 } 00749 00750 dns_query_queue[index] = query; 00751 00752 // Add some overhead based on number of ongoing queries 00753 query->total_timeout += ongoing_queries * 500; 00754 00755 if (!dns_timer_running) { 00756 if (nsapi_dns_call_in(query->call_in_cb, DNS_TIMER_TIMEOUT, mbed::callback(nsapi_dns_query_async_timeout)) != NSAPI_ERROR_OK ) { 00757 delete[] query->host; 00758 delete query; 00759 dns_query_queue[index] = NULL; 00760 dns_mutex->unlock(); 00761 return NSAPI_ERROR_NO_MEMORY ; 00762 } 00763 dns_timer_running = true; 00764 } 00765 00766 // Initiates query 00767 nsapi_dns_query_async_initiate_next(); 00768 00769 dns_mutex->unlock(); 00770 00771 return query->unique_id; 00772 } 00773 00774 static void nsapi_dns_query_async_initiate_next(void) 00775 { 00776 intptr_t id = INTPTR_MAX; 00777 DNS_QUERY *query = NULL; 00778 00779 // Trigger next query to start, find one that has been on queue longest 00780 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00781 if (dns_query_queue[i]) { 00782 if (dns_query_queue[i]->state == DNS_CREATED) { 00783 if (dns_query_queue[i]->unique_id <= id) { 00784 query = dns_query_queue[i]; 00785 id = dns_query_queue[i]->unique_id; 00786 } 00787 // If some query is already ongoing do not trigger 00788 } else if (dns_query_queue[i]->state == DNS_INITIATED) { 00789 query = NULL; 00790 break; 00791 } 00792 } 00793 } 00794 00795 if (query) { 00796 query->state = DNS_INITIATED; 00797 nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_create, reinterpret_cast<void *>(query->unique_id))); 00798 } 00799 } 00800 00801 static void nsapi_dns_query_async_timeout(void) 00802 { 00803 dns_mutex->lock(); 00804 00805 DNS_QUERY *query = NULL; 00806 00807 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00808 if (dns_query_queue[i]) { 00809 if (dns_query_queue[i]->state == DNS_CANCELLED) { 00810 // Delete cancelled 00811 nsapi_dns_query_async_delete(dns_query_queue[i]->unique_id); 00812 nsapi_dns_query_async_initiate_next(); 00813 continue; 00814 } 00815 00816 if (dns_query_queue[i]->total_timeout > DNS_TIMER_TIMEOUT) { 00817 dns_query_queue[i]->total_timeout -= DNS_TIMER_TIMEOUT; 00818 } else { 00819 // If does not already have response, fails 00820 if (dns_query_queue[i]->status == NSAPI_ERROR_TIMEOUT ) { 00821 dns_query_queue[i]->socket_timeout = 0; 00822 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))); 00823 } 00824 } 00825 00826 if (dns_query_queue[i]->socket_timeout > 0) { 00827 if (dns_query_queue[i]->socket_timeout > DNS_TIMER_TIMEOUT) { 00828 dns_query_queue[i]->socket_timeout -= DNS_TIMER_TIMEOUT; 00829 } else { 00830 // Retries 00831 dns_query_queue[i]->socket_timeout = 0; 00832 nsapi_dns_call_in(dns_query_queue[i]->call_in_cb, 0, 00833 mbed::callback(nsapi_dns_query_async_send, reinterpret_cast<void *>(dns_query_queue[i]->unique_id))); 00834 } 00835 } 00836 00837 if (!query) { 00838 query = dns_query_queue[i]; 00839 } 00840 } 00841 } 00842 00843 // Starts timer again 00844 if (query) { 00845 nsapi_dns_call_in(query->call_in_cb, DNS_TIMER_TIMEOUT, mbed::callback(nsapi_dns_query_async_timeout)); 00846 } else { 00847 dns_timer_running = false; 00848 } 00849 00850 dns_mutex->unlock(); 00851 } 00852 00853 nsapi_error_t nsapi_dns_query_async_cancel(nsapi_size_or_error_t id) 00854 { 00855 dns_mutex->lock(); 00856 00857 DNS_QUERY *query = NULL; 00858 00859 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00860 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == id) { 00861 query = dns_query_queue[i]; 00862 break; 00863 } 00864 } 00865 00866 if (!query || query->state == DNS_CANCELLED) { 00867 dns_mutex->unlock(); 00868 return NSAPI_ERROR_PARAMETER ; 00869 } 00870 00871 // Mark the query as cancelled, deleted by timer handler 00872 query->state = DNS_CANCELLED; 00873 // Do not call callback 00874 query->callback = 0; 00875 00876 dns_mutex->unlock(); 00877 00878 return NSAPI_ERROR_OK ; 00879 } 00880 00881 static void nsapi_dns_query_async_create(void *ptr) 00882 { 00883 dns_mutex->lock(); 00884 00885 intptr_t unique_id = reinterpret_cast<intptr_t>(ptr); 00886 00887 DNS_QUERY *query = NULL; 00888 00889 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00890 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) { 00891 query = dns_query_queue[i]; 00892 break; 00893 } 00894 } 00895 00896 if (!query || query->state == DNS_CANCELLED) { 00897 // Cancel has been called 00898 dns_mutex->unlock(); 00899 return; 00900 } 00901 00902 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00903 if (dns_query_queue[i] && dns_query_queue[i] != query) { 00904 if (!query->socket && dns_query_queue[i]->socket && dns_query_queue[i]->stack == query->stack) { 00905 query->socket = dns_query_queue[i]->socket; 00906 query->socket_cb_data = dns_query_queue[i]->socket_cb_data; 00907 } 00908 } 00909 } 00910 00911 UDPSocket *socket; 00912 00913 if (query->socket) { 00914 socket = query->socket; 00915 } else { 00916 socket = new (std::nothrow) UDPSocket; 00917 if (!socket) { 00918 nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY , NULL); 00919 return; 00920 } 00921 00922 int err = socket->open(query->stack); 00923 00924 if (err) { 00925 delete socket; 00926 nsapi_dns_query_async_resp(query, err, NULL); 00927 return; 00928 } 00929 00930 socket->set_timeout (0); 00931 if (query->interface_name != NULL) { 00932 socket->setsockopt (NSAPI_SOCKET , NSAPI_BIND_TO_DEVICE , query->interface_name, NSAPI_INTERFACE_NAME_MAX_SIZE); 00933 } 00934 00935 if (!query->socket_cb_data) { 00936 query->socket_cb_data = new SOCKET_CB_DATA; 00937 } 00938 query->socket_cb_data->call_in_cb = query->call_in_cb; 00939 query->socket_cb_data->stack = query->stack; 00940 socket->sigio (mbed::callback(nsapi_dns_query_async_socket_callback, query->socket_cb_data)); 00941 00942 query->socket = socket; 00943 } 00944 00945 dns_mutex->unlock(); 00946 00947 nsapi_dns_query_async_send(reinterpret_cast<void *>(query->unique_id)); 00948 00949 } 00950 00951 static nsapi_error_t nsapi_dns_query_async_delete(intptr_t unique_id) 00952 { 00953 int index = -1; 00954 DNS_QUERY *query = NULL; 00955 00956 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00957 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) { 00958 query = dns_query_queue[i]; 00959 index = i; 00960 break; 00961 } 00962 } 00963 00964 if (!query) { 00965 return NSAPI_ERROR_PARAMETER ; 00966 } 00967 00968 bool close_socket = true; 00969 00970 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 00971 if (dns_query_queue[i] && dns_query_queue[i] != query && dns_query_queue[i]->socket && 00972 dns_query_queue[i]->stack == query->stack) { 00973 close_socket = false; 00974 } 00975 } 00976 00977 if (close_socket && query->socket) { 00978 query->socket->close(); 00979 delete query->socket; 00980 delete query->socket_cb_data; 00981 } 00982 00983 if (query->addrs) { 00984 delete[] query->addrs; 00985 } 00986 00987 delete[] query->host; 00988 delete query; 00989 dns_query_queue[index] = NULL; 00990 00991 return NSAPI_ERROR_OK ; 00992 } 00993 00994 static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address) 00995 { 00996 NetworkStack::hostbyname_cb_t callback = query->callback; 00997 nsapi_dns_query_async_delete(query->unique_id); 00998 nsapi_dns_query_async_initiate_next(); 00999 01000 dns_mutex->unlock(); 01001 01002 if (callback) { 01003 callback(status, address); 01004 } 01005 } 01006 01007 static void nsapi_dns_query_async_send(void *ptr) 01008 { 01009 dns_mutex->lock(); 01010 01011 intptr_t unique_id = reinterpret_cast<intptr_t>(ptr); 01012 01013 DNS_QUERY *query = NULL; 01014 01015 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 01016 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) { 01017 query = dns_query_queue[i]; 01018 break; 01019 } 01020 } 01021 01022 if (!query || query->state != DNS_INITIATED) { 01023 // Cancel has been called 01024 dns_mutex->unlock(); 01025 return; 01026 } 01027 01028 if (query->retries) { 01029 query->retries--; 01030 } else { 01031 query->dns_server++; 01032 query->retries = MBED_CONF_NSAPI_DNS_RETRIES; 01033 } 01034 01035 query->dns_message_id = dns_message_id++; 01036 if (dns_message_id == 0) { 01037 dns_message_id = 1; 01038 } 01039 01040 // create network packet 01041 uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE); 01042 if (!packet) { 01043 nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY , NULL); 01044 return; 01045 } 01046 01047 while (true) { 01048 SocketAddress dns_addr; 01049 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); 01050 if (err != NSAPI_ERROR_OK ) { 01051 nsapi_dns_query_async_resp(query, NSAPI_ERROR_TIMEOUT , NULL); 01052 free(packet); 01053 return; 01054 } 01055 01056 if (query->version != NSAPI_UNSPEC && dns_addr.get_ip_version() != query->version) { 01057 query->dns_server++; 01058 continue; 01059 } 01060 // send the question 01061 int len = dns_append_question(packet, query->dns_message_id, query->host, dns_addr.get_ip_version()); 01062 01063 err = query->socket->sendto(dns_addr, packet, len); 01064 01065 if (err < 0) { 01066 if (err == NSAPI_ERROR_WOULD_BLOCK ) { 01067 nsapi_dns_call_in(query->call_in_cb, DNS_TIMER_TIMEOUT, mbed::callback(nsapi_dns_query_async_send, ptr)); 01068 free(packet); 01069 dns_mutex->unlock(); 01070 return; // Timeout handler will retry the connection if possible 01071 } else { 01072 query->dns_server++; 01073 } 01074 } else { 01075 break; 01076 } 01077 } 01078 01079 query->send_success++; 01080 01081 if (query->total_attempts) { 01082 query->total_attempts--; 01083 } 01084 01085 free(packet); 01086 01087 query->socket_timeout = MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME; 01088 01089 dns_mutex->unlock(); 01090 } 01091 01092 static void nsapi_dns_query_async_socket_callback(void *ptr) 01093 { 01094 SOCKET_CB_DATA *cb_data = static_cast<SOCKET_CB_DATA *>(ptr); 01095 01096 if (cb_data) { 01097 nsapi_dns_call_in(cb_data->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_socket_callback_handle, cb_data->stack)); 01098 } 01099 } 01100 01101 static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack) 01102 { 01103 UDPSocket *socket = NULL; 01104 01105 dns_mutex->lock(); 01106 01107 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 01108 if (dns_query_queue[i] && dns_query_queue[i]->stack == stack) { 01109 socket = dns_query_queue[i]->socket; 01110 break; 01111 } 01112 } 01113 01114 if (socket) { 01115 // create network packet 01116 uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE); 01117 if (!packet) { 01118 dns_mutex->unlock(); 01119 return; 01120 } 01121 01122 while (true) { 01123 // recv the response 01124 nsapi_size_or_error_t size = socket->recvfrom(NULL, packet, DNS_BUFFER_SIZE); 01125 01126 if (size < DNS_RESPONSE_MIN_SIZE) { 01127 break; 01128 } 01129 01130 // gets id from response to associate with correct query 01131 uint16_t id = (packet[0] << 8) | packet[1]; 01132 01133 DNS_QUERY *query = NULL; 01134 01135 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 01136 if (dns_query_queue[i] && dns_query_queue[i]->dns_message_id == id) { 01137 query = dns_query_queue[i]; 01138 break; 01139 } 01140 } 01141 01142 if (!query || query->state != DNS_INITIATED) { 01143 continue; 01144 } 01145 01146 int requested_count = 1; 01147 if (query->addr_count > 1) { 01148 requested_count = query->addr_count; 01149 } 01150 01151 query->addrs = new (std::nothrow) nsapi_addr_t[requested_count]; 01152 01153 int resp = dns_scan_response(packet, id, &(query->ttl), query->addrs, requested_count); 01154 01155 // Ignore invalid responses 01156 if (resp < 0) { 01157 delete[] query->addrs; 01158 query->addrs = 0; 01159 } else { 01160 query->count = resp; 01161 query->status = NSAPI_ERROR_DNS_FAILURE ; // Used in case failure, otherwise ok 01162 query->socket_timeout = 0; 01163 nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_response, reinterpret_cast<void *>(query->unique_id))); 01164 } 01165 } 01166 01167 free(packet); 01168 } 01169 01170 dns_mutex->unlock(); 01171 } 01172 01173 static void nsapi_dns_query_async_response(void *ptr) 01174 { 01175 dns_mutex->lock(); 01176 01177 intptr_t unique_id = reinterpret_cast<intptr_t>(ptr); 01178 01179 DNS_QUERY *query = NULL; 01180 01181 for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { 01182 if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) { 01183 query = dns_query_queue[i]; 01184 break; 01185 } 01186 } 01187 01188 if (query && query->state == DNS_INITIATED) { 01189 SocketAddress *addresses = NULL; 01190 nsapi_error_t status = query->status; 01191 01192 if (query->count > 0) { 01193 addresses = new (std::nothrow) SocketAddress[query->count]; 01194 01195 for (int i = 0; i < query->count; i++) { 01196 addresses[i].set_addr(query->addrs[i]); 01197 } 01198 01199 // Adds address to cache 01200 nsapi_dns_cache_add(query->host, &(query->addrs[0]), query->ttl); 01201 01202 status = NSAPI_ERROR_OK ; 01203 if (query->addr_count > 0) { 01204 status = query->count; 01205 } 01206 } 01207 01208 nsapi_dns_query_async_resp(query, status, addresses); 01209 delete[] addresses; 01210 } else { 01211 dns_mutex->unlock(); 01212 } 01213 }
Generated on Tue Jul 12 2022 13:54:39 by
