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