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