Corrected more defects

- Serialized the sending of multiple async DNS queries since limits on event
message box sizes
- Added timer function that supervises the total time used to make DNS query
and triggers socket timeouts
- Changed nsapi_error_t to new nsapi_value_or_error_t on interface headers
- Corrected wording of gethostbyname_async return values
- Clarified .json options
- Added a new data type for socket callback that can be used from interrupts
- Corrected variable limits to use INT32_MAX etc. defines
- Changed mallocs to new
- Optimized variable sizes on DNS_QUERY definition
pull/6847/head
Mika Leppänen 2018-05-09 16:07:53 +03:00 committed by Kevin Bracey
parent 1c01f5dda4
commit c4424ff0a1
8 changed files with 237 additions and 109 deletions

View File

@ -69,11 +69,12 @@ public:
* @param callback Callback that is called for result * @param callback Callback that is called for result
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates * @param version IP version of address to resolve, NSAPI_UNSPEC indicates
* version is chosen by the stack (defaults to NSAPI_UNSPEC) * version is chosen by the stack (defaults to NSAPI_UNSPEC)
* @return 0 on success, negative error code on failure or an unique id that * @return 0 on immediate success,
* represents the hostname translation operation and can be passed to * negative error code on immediate failure or
* cancel * a positive unique id that represents the hostname translation operation
* and can be passed to cancel
*/ */
virtual nsapi_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback,
nsapi_version_t version = NSAPI_UNSPEC) = 0; nsapi_version_t version = NSAPI_UNSPEC) = 0;
/** Cancels asynchronous hostname translation /** Cancels asynchronous hostname translation
@ -83,7 +84,7 @@ public:
* @param id Unique id of the hostname translation operation * @param id Unique id of the hostname translation operation
* @return 0 on success, negative error code on failure * @return 0 on success, negative error code on failure
*/ */
virtual nsapi_error_t gethostbyname_async_cancel(nsapi_error_t id) = 0; virtual nsapi_error_t gethostbyname_async_cancel(int id) = 0;
/** Add a domain name server to list of servers to query /** Add a domain name server to list of servers to query
* *

View File

@ -60,14 +60,14 @@ nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *a
return get_stack()->gethostbyname(name, address, version); return get_stack()->gethostbyname(name, address, version);
} }
nsapi_error_t NetworkInterface::gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version) nsapi_value_or_error_t NetworkInterface::gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version)
{ {
return get_stack()->gethostbyname_async(host, callback, version); return get_stack()->gethostbyname_async(host, callback, version);
} }
nsapi_error_t NetworkInterface::gethostbyname_async_cancel(nsapi_error_t handle) nsapi_error_t NetworkInterface::gethostbyname_async_cancel(int id)
{ {
return get_stack()->gethostbyname_async_cancel(handle); return get_stack()->gethostbyname_async_cancel(id);
} }
nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address) nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address)

View File

@ -161,11 +161,12 @@ public:
* @param callback Callback that is called for result * @param callback Callback that is called for result
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates * @param version IP version of address to resolve, NSAPI_UNSPEC indicates
* version is chosen by the stack (defaults to NSAPI_UNSPEC) * version is chosen by the stack (defaults to NSAPI_UNSPEC)
* @return 0 on success, negative error code on failure or an unique id that * @return 0 on immediate success,
* represents the hostname translation operation and can be passed to * negative error code on immediate failure or
* cancel * a positive unique id that represents the hostname translation operation
* and can be passed to cancel
*/ */
virtual nsapi_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback,
nsapi_version_t version = NSAPI_UNSPEC); nsapi_version_t version = NSAPI_UNSPEC);
/** Cancels asynchronous hostname translation /** Cancels asynchronous hostname translation
@ -175,7 +176,7 @@ public:
* @param id Unique id of the hostname translation operation * @param id Unique id of the hostname translation operation
* @return 0 on success, negative error code on failure * @return 0 on success, negative error code on failure
*/ */
virtual nsapi_error_t gethostbyname_async_cancel(nsapi_error_t id); virtual nsapi_error_t gethostbyname_async_cancel(int id);
/** Add a domain name server to list of servers to query /** Add a domain name server to list of servers to query
* *

View File

@ -49,7 +49,7 @@ nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *addre
return nsapi_dns_query(this, name, address, version); return nsapi_dns_query(this, name, address, version);
} }
nsapi_error_t NetworkStack::gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version) nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version)
{ {
SocketAddress address; SocketAddress address;
@ -77,9 +77,9 @@ nsapi_error_t NetworkStack::gethostbyname_async(const char *name, hostbyname_cb_
return nsapi_dns_query_async(this, name, callback, call_in_cb, version); return nsapi_dns_query_async(this, name, callback, call_in_cb, version);
} }
nsapi_error_t NetworkStack::gethostbyname_async_cancel(nsapi_error_t handle) nsapi_error_t NetworkStack::gethostbyname_async_cancel(int id)
{ {
return nsapi_dns_query_async_cancel(handle); return nsapi_dns_query_async_cancel(id);
} }
nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address) nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address)
@ -115,6 +115,7 @@ nsapi_error_t NetworkStack::getsockopt(void *handle, int level, int optname, voi
nsapi_error_t NetworkStack::call_in(int delay, mbed::Callback<void()> func) nsapi_error_t NetworkStack::call_in(int delay, mbed::Callback<void()> func)
{ {
events::EventQueue *event_queue = mbed::mbed_event_queue(); events::EventQueue *event_queue = mbed::mbed_event_queue();
if (!event_queue) { if (!event_queue) {
return NSAPI_ERROR_NO_MEMORY; return NSAPI_ERROR_NO_MEMORY;
} }
@ -132,20 +133,12 @@ nsapi_error_t NetworkStack::call_in(int delay, mbed::Callback<void()> func)
return NSAPI_ERROR_OK; return NSAPI_ERROR_OK;
} }
typedef mbed::Callback<nsapi_error_t (int delay_ms, mbed::Callback<void()> user_cb)> call_in_callback_cb_t;
call_in_callback_cb_t NetworkStack::get_call_in_callback() call_in_callback_cb_t NetworkStack::get_call_in_callback()
{ {
events::EventQueue *event_queue = mbed::mbed_event_queue();
if (!event_queue) {
return NULL;
}
call_in_callback_cb_t cb(this, &NetworkStack::call_in); call_in_callback_cb_t cb(this, &NetworkStack::call_in);
return cb; return cb;
} }
// NetworkStackWrapper class for encapsulating the raw nsapi_stack structure // NetworkStackWrapper class for encapsulating the raw nsapi_stack structure
class NetworkStackWrapper : public NetworkStack class NetworkStackWrapper : public NetworkStack
{ {

View File

@ -95,11 +95,12 @@ public:
* @param callback Callback that is called for result * @param callback Callback that is called for result
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates * @param version IP version of address to resolve, NSAPI_UNSPEC indicates
* version is chosen by the stack (defaults to NSAPI_UNSPEC) * version is chosen by the stack (defaults to NSAPI_UNSPEC)
* @return 0 on success, negative error code on failure or an unique id that * @return 0 on immediate success,
* represents the hostname translation operation and can be passed to * negative error code on immediate failure or
* cancel * a positive unique id that represents the hostname translation operation
* and can be passed to cancel
*/ */
virtual nsapi_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback,
nsapi_version_t version = NSAPI_UNSPEC); nsapi_version_t version = NSAPI_UNSPEC);
/** Cancels asynchronous hostname translation /** Cancels asynchronous hostname translation
@ -109,7 +110,7 @@ public:
* @param id Unique id of the hostname translation operation * @param id Unique id of the hostname translation operation
* @return 0 on success, negative error code on failure * @return 0 on success, negative error code on failure
*/ */
virtual nsapi_error_t gethostbyname_async_cancel(nsapi_error_t id); virtual nsapi_error_t gethostbyname_async_cancel(int id);
/** Add a domain name server to list of servers to query /** Add a domain name server to list of servers to query
* *

View File

@ -4,15 +4,15 @@
"present": 1, "present": 1,
"default-stack": "LWIP", "default-stack": "LWIP",
"dns-response-wait-time": { "dns-response-wait-time": {
"help": "How long the DNS translator waits for a reply from a server", "help": "How long the DNS translator waits for a reply from a server in milliseconds",
"value": 5000 "value": 5000
}, },
"dns-total-retries": { "dns-total-attempts": {
"help": "Number of total DNS query retries that the DNS translator makes", "help": "Number of total DNS query attempts that the DNS translator makes",
"value": 3 "value": 3
}, },
"dns-retries": { "dns-retries": {
"help": "Number of DNS query retries that the DNS translator makes per server", "help": "Number of DNS query retries that the DNS translator makes per server, before moving on to the next server. Total retries/attempts is always limited by dns-total-attempts.",
"value": 0 "value": 0
}, },
"dns-cache-size": { "dns-cache-size": {

View File

@ -14,6 +14,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/* Declare __STDC_LIMIT_MACROS so stdint.h defines INT32_MAX when using C++ */
#define __STDC_LIMIT_MACROS
#include "nsapi_dns.h" #include "nsapi_dns.h"
#include "netsocket/UDPSocket.h" #include "netsocket/UDPSocket.h"
#include <string.h> #include <string.h>
@ -33,26 +37,10 @@
#define DNS_BUFFER_SIZE 512 #define DNS_BUFFER_SIZE 512
#define DNS_SERVERS_SIZE 5 #define DNS_SERVERS_SIZE 5
#define DNS_RESPONSE_MIN_SIZE 12 #define DNS_RESPONSE_MIN_SIZE 12
#define DNS_MAX_TTL 604800
#define DNS_STACK_SERVERS_NUM 5 #define DNS_STACK_SERVERS_NUM 5
#define DNS_QUERY_QUEUE_SIZE 5 #define DNS_QUERY_QUEUE_SIZE 5
#define DNS_HOST_NAME_MAX_LEN 255 #define DNS_HOST_NAME_MAX_LEN 255
#define DNS_TIMER_TIMEOUT 100
#ifndef MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME
#define MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME 5000
#endif
#ifndef MBED_CONF_NSAPI_DNS_TOTAL_RETRIES
#define MBED_CONF_NSAPI_DNS_TOTAL_RETRIES 3
#endif
#ifndef MBED_CONF_NSAPI_DNS_RETRIES
#define MBED_CONF_NSAPI_DNS_RETRIES 0
#endif
#ifndef MBED_CONF_NSAPI_DNS_CACHE_SIZE
#define MBED_CONF_NSAPI_DNS_CACHE_SIZE 3
#endif
struct DNS_CACHE { struct DNS_CACHE {
nsapi_addr_t address; nsapi_addr_t address;
@ -61,8 +49,14 @@ struct DNS_CACHE {
uint64_t accessed; /*!< last accessed */ uint64_t accessed; /*!< last accessed */
}; };
struct SOCKET_CB_DATA {
call_in_callback_cb_t call_in_cb;
NetworkStack *stack;
};
struct DNS_QUERY { struct DNS_QUERY {
int unique_id; int unique_id;
nsapi_error_t status;
NetworkStack *stack; NetworkStack *stack;
char *host; char *host;
NetworkStack::hostbyname_cb_t callback; NetworkStack::hostbyname_cb_t callback;
@ -70,13 +64,16 @@ struct DNS_QUERY {
nsapi_size_t addr_count; nsapi_size_t addr_count;
nsapi_version_t version; nsapi_version_t version;
UDPSocket *socket; UDPSocket *socket;
SOCKET_CB_DATA *socket_cb_data;
nsapi_addr_t *addrs; nsapi_addr_t *addrs;
int dns_server;
int retries;
int total_retries;
int dns_message_id;
int count;
uint32_t ttl; uint32_t ttl;
uint32_t total_timeout;
uint32_t socket_timeout;
uint16_t dns_message_id;
uint8_t dns_server;
uint8_t retries;
uint8_t total_attempts;
uint8_t count;
}; };
typedef nsapi_error_t (*nsapi_dns_call_t)(mbed::Callback<void()> func); typedef nsapi_error_t (*nsapi_dns_call_t)(mbed::Callback<void()> func);
@ -85,13 +82,14 @@ typedef nsapi_error_t (*nsapi_dns_call_in_t)(int delay, mbed::Callback<void()> f
static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl); static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl);
static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address); static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address);
static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, int *index, int *total_retries, SocketAddress *dns_addr); static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, SocketAddress *dns_addr);
static void nsapi_dns_query_async_create(void *ptr); static void nsapi_dns_query_async_create(void *ptr);
static nsapi_error_t nsapi_dns_query_async_delete(int unique_id); static nsapi_error_t nsapi_dns_query_async_delete(int unique_id);
static void nsapi_dns_query_async_send(void *ptr); static void nsapi_dns_query_async_send(void *ptr);
static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address); static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address);
static void nsapi_dns_query_async_socket_callback(NetworkStack *stack); static void nsapi_dns_query_async_socket_callback(void *ptr);
static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack);
static void nsapi_dns_query_async_response(void *ptr); static void nsapi_dns_query_async_response(void *ptr);
static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = { static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
@ -105,7 +103,7 @@ static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
}; };
static DNS_CACHE *dns_cache[MBED_CONF_NSAPI_DNS_CACHE_SIZE]; static DNS_CACHE *dns_cache[MBED_CONF_NSAPI_DNS_CACHE_SIZE];
static uint16_t dns_message_id = 0; static uint16_t dns_message_id = 1;
static int dns_unique_id = 1; static int dns_unique_id = 1;
static DNS_QUERY *dns_query_queue[DNS_QUERY_QUEUE_SIZE]; static DNS_QUERY *dns_query_queue[DNS_QUERY_QUEUE_SIZE];
// Protects cache shared between blocking and asynchronous calls // Protects cache shared between blocking and asynchronous calls
@ -259,8 +257,8 @@ static int dns_scan_response(const uint8_t *ptr, uint16_t exp_id, uint32_t *ttl,
if (i == 0) { if (i == 0) {
// Is interested only on first address that is stored to cache // Is interested only on first address that is stored to cache
if (ttl_val > DNS_MAX_TTL) { if (ttl_val > INT32_MAX) {
ttl_val = DNS_MAX_TTL; ttl_val = INT32_MAX;
} }
*ttl = ttl_val; *ttl = ttl_val;
} }
@ -295,7 +293,7 @@ static int dns_scan_response(const uint8_t *ptr, uint16_t exp_id, uint32_t *ttl,
static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl) static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl)
{ {
// RFC 1034: if TTL is zero, entry is not added to cache // RFC 1034: if TTL is zero, entry is not added to cache
if (!ttl) { if (ttl == 0) {
return; return;
} }
@ -307,7 +305,7 @@ static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_
dns_cache_mutex.lock(); dns_cache_mutex.lock();
int index = -1; int index = -1;
uint64_t accessed = ~0; uint64_t accessed = UINT64_MAX;
// Finds free or last accessed entry // Finds free or last accessed entry
for (int i = 0; i < MBED_CONF_NSAPI_DNS_CACHE_SIZE; i++) { for (int i = 0; i < MBED_CONF_NSAPI_DNS_CACHE_SIZE; i++) {
@ -329,15 +327,15 @@ static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_
if (!dns_cache[index]) { if (!dns_cache[index]) {
dns_cache[index] = new (std::nothrow) DNS_CACHE; dns_cache[index] = new (std::nothrow) DNS_CACHE;
} else { } else {
free(dns_cache[index]->host); delete dns_cache[index]->host;
} }
if (dns_cache[index]) { if (dns_cache[index]) {
dns_cache[index]->address = *address; dns_cache[index]->address = *address;
dns_cache[index]->host = (char *) malloc(strlen(host) + 1); dns_cache[index]->host = new (std::nothrow) char[strlen(host) + 1];
strcpy(dns_cache[index]->host, host); strcpy(dns_cache[index]->host, host);
uint64_t ms_count = rtos::Kernel::get_ms_count(); uint64_t ms_count = rtos::Kernel::get_ms_count();
dns_cache[index]->expires = ms_count + ttl * 1000; dns_cache[index]->expires = ms_count + (uint64_t) ttl * 1000;
dns_cache[index]->accessed = ms_count; dns_cache[index]->accessed = ms_count;
} }
@ -355,7 +353,7 @@ static nsapi_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t vers
uint64_t ms_count = rtos::Kernel::get_ms_count(); uint64_t ms_count = rtos::Kernel::get_ms_count();
// Checks all entries for expired entries // Checks all entries for expired entries
if (ms_count > dns_cache[i]->expires) { if (ms_count > dns_cache[i]->expires) {
free(dns_cache[i]->host); delete dns_cache[i]->host;
delete dns_cache[i]; delete dns_cache[i];
dns_cache[i] = NULL; dns_cache[i] = NULL;
} else if ((version == NSAPI_UNSPEC || version == dns_cache[i]->address.version) && } else if ((version == NSAPI_UNSPEC || version == dns_cache[i]->address.version) &&
@ -374,16 +372,16 @@ static nsapi_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t vers
return ret_val; return ret_val;
} }
static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, int *index, int *total_retries, SocketAddress *dns_addr) static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, SocketAddress *dns_addr)
{ {
bool dns_addr_set = false; bool dns_addr_set = false;
if (*total_retries == 0) { if (*total_attempts == 0) {
return NSAPI_ERROR_NO_ADDRESS; return NSAPI_ERROR_NO_ADDRESS;
} }
if (*index >= DNS_SERVERS_SIZE + DNS_STACK_SERVERS_NUM) { if (*index >= DNS_SERVERS_SIZE + DNS_STACK_SERVERS_NUM) {
if (*total_retries) { if (*total_attempts) {
*index = 0; *index = 0;
} else { } else {
return NSAPI_ERROR_NO_ADDRESS; return NSAPI_ERROR_NO_ADDRESS;
@ -440,15 +438,14 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
nsapi_size_or_error_t result = NSAPI_ERROR_DNS_FAILURE; nsapi_size_or_error_t result = NSAPI_ERROR_DNS_FAILURE;
int retries = MBED_CONF_NSAPI_DNS_RETRIES; uint8_t retries = MBED_CONF_NSAPI_DNS_RETRIES;
uint8_t index = 0;
int index = 0; uint8_t total_attempts = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS;
int total_retries = MBED_CONF_NSAPI_DNS_TOTAL_RETRIES;
// check against each dns server // check against each dns server
while (true) { while (true) {
SocketAddress dns_addr; SocketAddress dns_addr;
err = nsapi_dns_get_server_addr(stack, &index, &total_retries, &dns_addr); err = nsapi_dns_get_server_addr(stack, &index, &total_attempts, &dns_addr);
if (err != NSAPI_ERROR_OK) { if (err != NSAPI_ERROR_OK) {
break; break;
} }
@ -465,8 +462,8 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
continue; continue;
} }
if (total_retries) { if (total_attempts) {
total_retries--; total_attempts--;
} }
// recv the response // recv the response
@ -554,7 +551,7 @@ nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
return (nsapi_error_t)((result > 0) ? 0 : result); return (nsapi_error_t)((result > 0) ? 0 : result);
} }
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host, nsapi_value_or_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb, NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb,
nsapi_version_t version) nsapi_version_t version)
{ {
@ -576,7 +573,9 @@ nsapi_error_t nsapi_dns_call_in(call_in_callback_cb_t cb, int delay, mbed::Callb
return NSAPI_ERROR_OK; return NSAPI_ERROR_OK;
} }
nsapi_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host, void nsapi_dns_query_async_timeout(void);
nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host,
NetworkStack::hostbyname_cb_t callback, nsapi_size_t addr_count, NetworkStack::hostbyname_cb_t callback, nsapi_size_t addr_count,
call_in_callback_cb_t call_in_cb, nsapi_version_t version) call_in_callback_cb_t call_in_cb, nsapi_version_t version)
{ {
@ -620,39 +619,112 @@ nsapi_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *ho
return NSAPI_ERROR_NO_MEMORY; return NSAPI_ERROR_NO_MEMORY;
} }
query->host = (char *) malloc(host_len + 1); query->host = new (std::nothrow) char[host_len + 1];
strcpy(query->host, host); strcpy(query->host, host);
query->status = NSAPI_ERROR_DEVICE_ERROR;
query->callback = callback; query->callback = callback;
query->call_in_cb = call_in_cb; query->call_in_cb = call_in_cb;
query->stack = stack; query->stack = stack;
query->addr_count = addr_count; query->addr_count = addr_count;
query->version = version; query->version = version;
query->socket = NULL; query->socket = NULL;
query->socket_cb_data = NULL;
query->addrs = NULL; query->addrs = NULL;
query->dns_server = 0; query->dns_server = 0;
query->retries = MBED_CONF_NSAPI_DNS_RETRIES + 1; query->retries = MBED_CONF_NSAPI_DNS_RETRIES + 1;
query->total_retries = MBED_CONF_NSAPI_DNS_TOTAL_RETRIES; query->total_attempts = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS;
query->dns_message_id = -1; query->dns_message_id = 0;
query->socket_timeout = 0;
query->total_timeout = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS * MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME + 500;
query->unique_id = dns_unique_id++; query->unique_id = dns_unique_id++;
if (query->unique_id > 0x7FFF) { if (query->unique_id > 0x7FFF) {
query->unique_id = 1; query->unique_id = 1;
} }
int ongoing_queries = 0;
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
if (dns_query_queue[i]) {
if (!query->socket && dns_query_queue[i]->socket && dns_query_queue[i]->stack == query->stack) {
query->socket = dns_query_queue[i]->socket;
query->socket_cb_data = dns_query_queue[i]->socket_cb_data;
}
ongoing_queries++;
}
}
dns_query_queue[index] = query; dns_query_queue[index] = query;
if (nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_create, reinterpret_cast<void *>(query->unique_id))) != NSAPI_ERROR_OK) { // Add some overhead based on number of ongoing queries
query->total_timeout += ongoing_queries * 500;
if (ongoing_queries == 0) {
if (nsapi_dns_call_in(query->call_in_cb, DNS_TIMER_TIMEOUT, mbed::callback(nsapi_dns_query_async_timeout)) != NSAPI_ERROR_OK) {
delete query->host;
delete query; delete query;
dns_mutex.unlock(); dns_mutex.unlock();
return NSAPI_ERROR_NO_MEMORY; return NSAPI_ERROR_NO_MEMORY;
} }
if (nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_create, reinterpret_cast<void *>(query->unique_id))) != NSAPI_ERROR_OK) {
delete query->host;
delete query;
dns_mutex.unlock();
return NSAPI_ERROR_NO_MEMORY;
}
}
dns_mutex.unlock(); dns_mutex.unlock();
return query->unique_id; return query->unique_id;
} }
nsapi_error_t nsapi_dns_query_async_cancel(nsapi_error_t id) void nsapi_dns_query_async_timeout(void)
{
dns_mutex.lock();
DNS_QUERY *query = NULL;
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
if (dns_query_queue[i]) {
if (dns_query_queue[i]->total_timeout > DNS_TIMER_TIMEOUT) {
dns_query_queue[i]->total_timeout -= DNS_TIMER_TIMEOUT;
} else {
// If does not already have response, fails
if (query->status == NSAPI_ERROR_DEVICE_ERROR) {
query->socket_timeout = 0;
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)));
}
}
if (dns_query_queue[i]->socket_timeout > 0) {
if (dns_query_queue[i]->socket_timeout > DNS_TIMER_TIMEOUT) {
dns_query_queue[i]->socket_timeout -= DNS_TIMER_TIMEOUT;
} else {
// Retries
dns_query_queue[i]->socket_timeout = 0;
nsapi_dns_call_in(dns_query_queue[i]->call_in_cb, 0,
mbed::callback(nsapi_dns_query_async_send, reinterpret_cast<void *>(dns_query_queue[i]->unique_id)));
}
}
if (!query) {
query = dns_query_queue[i];
}
}
}
// Starts timer again
if (query) {
nsapi_dns_call_in(query->call_in_cb, DNS_TIMER_TIMEOUT, mbed::callback(nsapi_dns_query_async_timeout));
}
dns_mutex.unlock();
}
nsapi_error_t nsapi_dns_query_async_cancel(int id)
{ {
dns_mutex.lock(); dns_mutex.lock();
@ -684,14 +756,26 @@ static void nsapi_dns_query_async_create(void *ptr)
return; return;
} }
bool ongoing = false;
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) { for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
if (dns_query_queue[i] && dns_query_queue[i] != query) { if (dns_query_queue[i] && dns_query_queue[i] != query) {
if (dns_query_queue[i]->socket && dns_query_queue[i]->stack == query->stack) { if (!query->socket && dns_query_queue[i]->socket && dns_query_queue[i]->stack == query->stack) {
query->socket = dns_query_queue[i]->socket; query->socket = dns_query_queue[i]->socket;
query->socket_cb_data = dns_query_queue[i]->socket_cb_data;
}
if (dns_query_queue[i]->dns_message_id != 0) {
ongoing = true;
} }
} }
} }
if (ongoing) {
// If there is already operation ongoing exits
dns_mutex.unlock();
return;
}
UDPSocket *socket; UDPSocket *socket;
if (query->socket) { if (query->socket) {
@ -700,7 +784,6 @@ static void nsapi_dns_query_async_create(void *ptr)
socket = new (std::nothrow) UDPSocket; socket = new (std::nothrow) UDPSocket;
if (!socket) { if (!socket) {
nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL); nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
dns_mutex.unlock();
return; return;
} }
@ -708,12 +791,17 @@ static void nsapi_dns_query_async_create(void *ptr)
if (err) { if (err) {
delete socket; delete socket;
nsapi_dns_query_async_resp(query, err, NULL); nsapi_dns_query_async_resp(query, err, NULL);
dns_mutex.unlock();
return; return;
} }
socket->set_timeout(0); socket->set_timeout(0);
socket->sigio(mbed::callback(nsapi_dns_query_async_socket_callback, query->stack));
if (!query->socket_cb_data) {
query->socket_cb_data = new SOCKET_CB_DATA;
}
query->socket_cb_data->call_in_cb = query->call_in_cb;
query->socket_cb_data->stack = query->stack;
socket->sigio(mbed::callback(nsapi_dns_query_async_socket_callback, query->socket_cb_data));
query->socket = socket; query->socket = socket;
} }
@ -750,13 +838,14 @@ static nsapi_error_t nsapi_dns_query_async_delete(int unique_id)
if (close_socket && dns_query_queue[index]->socket) { if (close_socket && dns_query_queue[index]->socket) {
dns_query_queue[index]->socket->close(); dns_query_queue[index]->socket->close();
delete dns_query_queue[index]->socket; delete dns_query_queue[index]->socket;
delete dns_query_queue[index]->socket_cb_data;
} }
if (dns_query_queue[index]->addrs) { if (dns_query_queue[index]->addrs) {
delete[] dns_query_queue[index]->addrs; delete[] dns_query_queue[index]->addrs;
} }
free(dns_query_queue[index]->host); delete dns_query_queue[index]->host;
delete dns_query_queue[index]; delete dns_query_queue[index];
dns_query_queue[index] = NULL; dns_query_queue[index] = NULL;
@ -765,8 +854,29 @@ static nsapi_error_t nsapi_dns_query_async_delete(int unique_id)
static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address) static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address)
{ {
query->callback(status, address); NetworkStack::hostbyname_cb_t callback = query->callback;
nsapi_dns_query_async_delete(query->unique_id); nsapi_dns_query_async_delete(query->unique_id);
DNS_QUERY *next_query = NULL;
int unique_id = INT32_MAX;
// Find one that has been on queue longest
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
if (dns_query_queue[i]) {
if (dns_query_queue[i]->unique_id <= unique_id) {
next_query = dns_query_queue[i];
unique_id = dns_query_queue[i]->unique_id;
}
}
}
if (next_query) {
nsapi_dns_call_in(next_query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_create, reinterpret_cast<void *>(next_query->unique_id)));
}
dns_mutex.unlock();
callback(status, address);
} }
static void nsapi_dns_query_async_send(void *ptr) static void nsapi_dns_query_async_send(void *ptr)
@ -798,12 +908,14 @@ static void nsapi_dns_query_async_send(void *ptr)
} }
query->dns_message_id = dns_message_id++; query->dns_message_id = dns_message_id++;
if (dns_message_id == 0) {
dns_message_id = 1;
}
// create network packet // create network packet
uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE); uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE);
if (!packet) { if (!packet) {
nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL); nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
dns_mutex.unlock();
return; return;
} }
@ -812,11 +924,10 @@ static void nsapi_dns_query_async_send(void *ptr)
while (true) { while (true) {
SocketAddress dns_addr; SocketAddress dns_addr;
nsapi_size_or_error_t err = nsapi_dns_get_server_addr(query->stack, &(query->dns_server), &(query->total_retries), &dns_addr); nsapi_size_or_error_t err = nsapi_dns_get_server_addr(query->stack, &(query->dns_server), &(query->total_attempts), &dns_addr);
if (err != NSAPI_ERROR_OK) { if (err != NSAPI_ERROR_OK) {
nsapi_dns_query_async_resp(query, NSAPI_ERROR_DNS_FAILURE, NULL); nsapi_dns_query_async_resp(query, NSAPI_ERROR_DNS_FAILURE, NULL);
free(packet); free(packet);
dns_mutex.unlock();
return; return;
} }
@ -829,21 +940,27 @@ static void nsapi_dns_query_async_send(void *ptr)
} }
} }
if (query->total_retries) { if (query->total_attempts) {
query->total_retries--; query->total_attempts--;
} }
free(packet); free(packet);
if (nsapi_dns_call_in(query->call_in_cb, MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME, query->socket_timeout = MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME;
mbed::callback(nsapi_dns_query_async_send, reinterpret_cast<void *>(unique_id))) != NSAPI_ERROR_OK) {
nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
}
dns_mutex.unlock(); dns_mutex.unlock();
} }
static void nsapi_dns_query_async_socket_callback(NetworkStack *stack) static void nsapi_dns_query_async_socket_callback(void *ptr)
{
SOCKET_CB_DATA *cb_data = static_cast<SOCKET_CB_DATA *>(ptr);
if (cb_data) {
nsapi_dns_call_in(cb_data->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_socket_callback_handle, cb_data->stack));
}
}
static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack)
{ {
UDPSocket *socket = NULL; UDPSocket *socket = NULL;
@ -903,6 +1020,8 @@ static void nsapi_dns_query_async_socket_callback(NetworkStack *stack)
query->addrs = 0; query->addrs = 0;
} else { } else {
query->count = resp; query->count = resp;
query->status = NSAPI_ERROR_DNS_FAILURE; // Used in case failure, otherwise ok
query->socket_timeout = 0;
nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_response, reinterpret_cast<void *>(query->unique_id))); nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_response, reinterpret_cast<void *>(query->unique_id)));
} }
} }
@ -929,8 +1048,11 @@ static void nsapi_dns_query_async_response(void *ptr)
} }
if (query) { if (query) {
SocketAddress *addresses = NULL;
nsapi_error_t status = query->status; //NSAPI_ERROR_OK;
if (query->count > 0) { if (query->count > 0) {
SocketAddress *addresses = new (std::nothrow) SocketAddress[query->count]; addresses = new (std::nothrow) SocketAddress[query->count];
for (int i = 0; i < query->count; i++) { for (int i = 0; i < query->count; i++) {
addresses[i].set_addr(query->addrs[i]); addresses[i].set_addr(query->addrs[i]);
@ -939,16 +1061,19 @@ static void nsapi_dns_query_async_response(void *ptr)
// Adds address to cache // Adds address to cache
nsapi_dns_cache_add(query->host, &(query->addrs[0]), query->ttl); nsapi_dns_cache_add(query->host, &(query->addrs[0]), query->ttl);
nsapi_error_t status = NSAPI_ERROR_OK; status = NSAPI_ERROR_OK;
if (query->addr_count > 0) { if (query->addr_count > 0) {
status = query->count; status = query->count;
} }
nsapi_dns_query_async_resp(query, status, addresses); }
delete[] addresses;
} else { nsapi_dns_query_async_resp(query, status, addresses);
nsapi_dns_query_async_resp(query, NSAPI_ERROR_DNS_FAILURE, NULL);
} if (addresses) {
} delete[] addresses;
dns_mutex.unlock(); }
} else {
dns_mutex.unlock();
}
} }

View File

@ -103,6 +103,13 @@ typedef unsigned int nsapi_size_t;
*/ */
typedef signed int nsapi_size_or_error_t; typedef signed int nsapi_size_or_error_t;
/** Type used to represent either a value or error
*
* A valid nsapi_value_or_error_t is either a non-negative value or a
* negative error code from the nsapi_error_t
*/
typedef signed int nsapi_value_or_error_t;
/** Enum of encryption types /** Enum of encryption types
* *
* The security type specifies a particular security to use when * The security type specifies a particular security to use when