mirror of https://github.com/ARMmbed/mbed-os.git
Corrected asynchronous DNS functionality
- Set network stack to store event queue so that mbed::mbed_event_queue() call is not needed every time call_in() is called - Added dns state variables and enum (states are: created, initiated and cancelled) - Corrected DNS response handling so that if DNS server returns that host name is unknown the DNS query is not tried again - Reorder mutexes in nsapi_dns_query_multiple_async() - Created nsapi_dns_query_async_initiate_next() function to initiate the next DNS query from the queue after delete of previous query - Added dsn_timer_running variable to supervise DNS timer start/stop - Changed cancel function to only mark query as deleted and moved deletion to timer function. This allows to run socket close on DNS thread - Added new nsapi error NSAPI_ERROR_TIMEOUT for DNS (and other) timeoutspull/7016/head
parent
2eac96eb04
commit
d648bf8477
|
@ -209,7 +209,7 @@ void LWIP::tcpip_thread_callback(void *ptr)
|
|||
|
||||
nsapi_error_t LWIP::call_in(int delay, mbed::Callback<void()> func)
|
||||
{
|
||||
lwip_callback *cb = new lwip_callback;
|
||||
lwip_callback *cb = new (std::nothrow) lwip_callback;
|
||||
if (!cb) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,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)
|
||||
{
|
||||
events::EventQueue *event_queue = mbed::mbed_event_queue();
|
||||
static events::EventQueue *event_queue = mbed::mbed_event_queue();
|
||||
|
||||
if (!event_queue) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
|
|
|
@ -55,6 +55,12 @@ struct SOCKET_CB_DATA {
|
|||
NetworkStack *stack;
|
||||
};
|
||||
|
||||
enum dns_state {
|
||||
DNS_CREATED, /*!< created, not yet making query to network */
|
||||
DNS_INITIATED, /*!< making query to network */
|
||||
DNS_CANCELLED /*!< cancelled, callback will not be called */
|
||||
};
|
||||
|
||||
struct DNS_QUERY {
|
||||
int unique_id;
|
||||
nsapi_error_t status;
|
||||
|
@ -75,6 +81,7 @@ struct DNS_QUERY {
|
|||
uint8_t retries;
|
||||
uint8_t total_attempts;
|
||||
uint8_t count;
|
||||
dns_state state;
|
||||
};
|
||||
|
||||
static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl);
|
||||
|
@ -85,10 +92,12 @@ static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *ind
|
|||
static void nsapi_dns_query_async_create(void *ptr);
|
||||
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_timeout(void);
|
||||
static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address);
|
||||
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_initiate_next(void);
|
||||
|
||||
static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
|
||||
{NSAPI_IPv4, {8, 8, 8, 8}}, // Google
|
||||
|
@ -109,6 +118,7 @@ static PlatformMutex dns_cache_mutex;
|
|||
// Protects from several threads running asynchronous DNS
|
||||
static PlatformMutex dns_mutex;
|
||||
static call_in_callback_cb_t dns_call_in = 0;
|
||||
static bool dns_timer_running = false;
|
||||
|
||||
// DNS server configuration
|
||||
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr)
|
||||
|
@ -213,10 +223,14 @@ static int dns_scan_response(const uint8_t *ptr, uint16_t exp_id, uint32_t *ttl,
|
|||
dns_scan_word(p); // arcount
|
||||
|
||||
// verify header is response to query
|
||||
if (!(id == exp_id && qr && opcode == 0 && rcode == 0)) {
|
||||
if (!(id == exp_id && qr && opcode == 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rcode != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// skip questions
|
||||
for (int i = 0; i < qdcount; i++) {
|
||||
while (true) {
|
||||
|
@ -571,12 +585,12 @@ nsapi_error_t nsapi_dns_call_in(call_in_callback_cb_t cb, int delay, mbed::Callb
|
|||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
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,
|
||||
call_in_callback_cb_t call_in_cb, nsapi_version_t version)
|
||||
{
|
||||
dns_mutex.lock();
|
||||
|
||||
if (!stack) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
@ -584,18 +598,18 @@ nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const
|
|||
// check for valid host name
|
||||
int host_len = host ? strlen(host) : 0;
|
||||
if (host_len > DNS_HOST_NAME_MAX_LEN || host_len == 0) {
|
||||
dns_mutex.unlock();
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
nsapi_addr address;
|
||||
if (nsapi_dns_cache_find(host, version, &address) == NSAPI_ERROR_OK) {
|
||||
SocketAddress addr(address);
|
||||
dns_mutex.unlock();
|
||||
callback(NSAPI_ERROR_OK, &addr);
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
dns_mutex.lock();
|
||||
|
||||
int index = -1;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
|
@ -617,9 +631,14 @@ nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const
|
|||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
query->host = new (std::nothrow) char[host_len + 1];
|
||||
query->host = new (std::nothrow) char[host_len + 1];
|
||||
if (!query->host) {
|
||||
delete query;
|
||||
dns_mutex.unlock();
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
strcpy(query->host, host);
|
||||
query->status = NSAPI_ERROR_DEVICE_ERROR;
|
||||
query->status = NSAPI_ERROR_TIMEOUT;
|
||||
query->callback = callback;
|
||||
query->call_in_cb = call_in_cb;
|
||||
query->stack = stack;
|
||||
|
@ -634,6 +653,8 @@ nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const
|
|||
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->count = 0;
|
||||
query->state = DNS_CREATED;
|
||||
|
||||
query->unique_id = dns_unique_id++;
|
||||
if (query->unique_id > 0x7FFF) {
|
||||
|
@ -657,28 +678,52 @@ nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const
|
|||
// Add some overhead based on number of ongoing queries
|
||||
query->total_timeout += ongoing_queries * 500;
|
||||
|
||||
if (ongoing_queries == 0) {
|
||||
if (!dns_timer_running) {
|
||||
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;
|
||||
dns_mutex.unlock();
|
||||
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_timer_running = true;
|
||||
}
|
||||
|
||||
// Initiates query
|
||||
nsapi_dns_query_async_initiate_next();
|
||||
|
||||
dns_mutex.unlock();
|
||||
|
||||
return query->unique_id;
|
||||
}
|
||||
|
||||
void nsapi_dns_query_async_timeout(void)
|
||||
static void nsapi_dns_query_async_initiate_next(void)
|
||||
{
|
||||
int id = INT32_MAX;
|
||||
DNS_QUERY *query = NULL;
|
||||
|
||||
// Trigger next query to start, 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]->state == DNS_CREATED) {
|
||||
if (dns_query_queue[i]->unique_id <= id) {
|
||||
query = dns_query_queue[i];
|
||||
id = dns_query_queue[i]->unique_id;
|
||||
}
|
||||
// If some query is already ongoing do not trigger
|
||||
} else if (dns_query_queue[i]->state == DNS_INITIATED) {
|
||||
query = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (query) {
|
||||
query->state = DNS_INITIATED;
|
||||
nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_create, reinterpret_cast<void *>(query->unique_id)));
|
||||
}
|
||||
}
|
||||
|
||||
static void nsapi_dns_query_async_timeout(void)
|
||||
{
|
||||
dns_mutex.lock();
|
||||
|
||||
|
@ -686,13 +731,19 @@ void nsapi_dns_query_async_timeout(void)
|
|||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (dns_query_queue[i]) {
|
||||
if (dns_query_queue[i]->state == DNS_CANCELLED) {
|
||||
// Delete cancelled
|
||||
nsapi_dns_query_async_delete(dns_query_queue[i]->unique_id);
|
||||
nsapi_dns_query_async_initiate_next();
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
if (dns_query_queue[i]->status == NSAPI_ERROR_TIMEOUT) {
|
||||
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_response, reinterpret_cast<void *>(dns_query_queue[i]->unique_id)));
|
||||
}
|
||||
}
|
||||
|
@ -717,6 +768,8 @@ void nsapi_dns_query_async_timeout(void)
|
|||
// Starts timer again
|
||||
if (query) {
|
||||
nsapi_dns_call_in(query->call_in_cb, DNS_TIMER_TIMEOUT, mbed::callback(nsapi_dns_query_async_timeout));
|
||||
} else {
|
||||
dns_timer_running = false;
|
||||
}
|
||||
|
||||
dns_mutex.unlock();
|
||||
|
@ -726,11 +779,28 @@ nsapi_error_t nsapi_dns_query_async_cancel(int id)
|
|||
{
|
||||
dns_mutex.lock();
|
||||
|
||||
nsapi_error_t ret = nsapi_dns_query_async_delete(id);
|
||||
DNS_QUERY *query = NULL;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (dns_query_queue[i] && dns_query_queue[i]->unique_id == id) {
|
||||
query = dns_query_queue[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!query || query->state == DNS_CANCELLED) {
|
||||
dns_mutex.unlock();
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
// Mark the query as cancelled, deleted by timer handler
|
||||
query->state = DNS_CANCELLED;
|
||||
// Do not call callback
|
||||
query->callback = 0;
|
||||
|
||||
dns_mutex.unlock();
|
||||
|
||||
return ret;
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
static void nsapi_dns_query_async_create(void *ptr)
|
||||
|
@ -748,32 +818,21 @@ static void nsapi_dns_query_async_create(void *ptr)
|
|||
}
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
if (!query || query->state == DNS_CANCELLED) {
|
||||
// Cancel has been called
|
||||
dns_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
bool ongoing = false;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (dns_query_queue[i] && dns_query_queue[i] != query) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
if (query->socket) {
|
||||
|
@ -786,6 +845,7 @@ static void nsapi_dns_query_async_create(void *ptr)
|
|||
}
|
||||
|
||||
int err = socket->open(query->stack);
|
||||
|
||||
if (err) {
|
||||
delete socket;
|
||||
nsapi_dns_query_async_resp(query, err, NULL);
|
||||
|
@ -807,46 +867,49 @@ static void nsapi_dns_query_async_create(void *ptr)
|
|||
dns_mutex.unlock();
|
||||
|
||||
nsapi_dns_query_async_send(reinterpret_cast<void *>(query->unique_id));
|
||||
|
||||
}
|
||||
|
||||
static nsapi_error_t nsapi_dns_query_async_delete(int unique_id)
|
||||
{
|
||||
int index = -1;
|
||||
DNS_QUERY *query = NULL;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (dns_query_queue[i] && dns_query_queue[i]->unique_id == unique_id) {
|
||||
query = dns_query_queue[i];
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
if (!query) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
bool close_socket = true;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (i != index && dns_query_queue[i] && dns_query_queue[i]->socket &&
|
||||
dns_query_queue[i]->stack == dns_query_queue[index]->stack) {
|
||||
if (dns_query_queue[i] && dns_query_queue[i] != query && dns_query_queue[i]->socket &&
|
||||
dns_query_queue[i]->stack == query->stack) {
|
||||
close_socket = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (close_socket && dns_query_queue[index]->socket) {
|
||||
dns_query_queue[index]->socket->close();
|
||||
delete dns_query_queue[index]->socket;
|
||||
delete dns_query_queue[index]->socket_cb_data;
|
||||
if (close_socket && query->socket) {
|
||||
query->socket->close();
|
||||
delete query->socket;
|
||||
delete query->socket_cb_data;
|
||||
}
|
||||
|
||||
if (dns_query_queue[index]->addrs) {
|
||||
delete[] dns_query_queue[index]->addrs;
|
||||
if (query->addrs) {
|
||||
delete[] query->addrs;
|
||||
}
|
||||
|
||||
delete dns_query_queue[index]->host;
|
||||
|
||||
delete dns_query_queue[index];
|
||||
delete query->host;
|
||||
delete query;
|
||||
dns_query_queue[index] = NULL;
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
|
@ -854,27 +917,13 @@ static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, S
|
|||
{
|
||||
NetworkStack::hostbyname_cb_t callback = query->callback;
|
||||
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)));
|
||||
}
|
||||
nsapi_dns_query_async_initiate_next();
|
||||
|
||||
dns_mutex.unlock();
|
||||
|
||||
callback(status, address);
|
||||
if (callback) {
|
||||
callback(status, address);
|
||||
}
|
||||
}
|
||||
|
||||
static void nsapi_dns_query_async_send(void *ptr)
|
||||
|
@ -892,7 +941,7 @@ static void nsapi_dns_query_async_send(void *ptr)
|
|||
}
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
if (!query || query->state != DNS_INITIATED) {
|
||||
// Cancel has been called
|
||||
dns_mutex.unlock();
|
||||
return;
|
||||
|
@ -924,7 +973,7 @@ static void nsapi_dns_query_async_send(void *ptr)
|
|||
SocketAddress 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) {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_DNS_FAILURE, NULL);
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_TIMEOUT, NULL);
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
|
@ -999,7 +1048,7 @@ static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack)
|
|||
}
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
if (!query || query->state != DNS_INITIATED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1045,9 +1094,9 @@ static void nsapi_dns_query_async_response(void *ptr)
|
|||
}
|
||||
}
|
||||
|
||||
if (query) {
|
||||
if (query && query->state == DNS_INITIATED) {
|
||||
SocketAddress *addresses = NULL;
|
||||
nsapi_error_t status = query->status; //NSAPI_ERROR_OK;
|
||||
nsapi_error_t status = query->status;
|
||||
|
||||
if (query->count > 0) {
|
||||
addresses = new (std::nothrow) SocketAddress[query->count];
|
||||
|
@ -1066,10 +1115,8 @@ static void nsapi_dns_query_async_response(void *ptr)
|
|||
}
|
||||
|
||||
nsapi_dns_query_async_resp(query, status, addresses);
|
||||
|
||||
delete[] addresses;
|
||||
} else {
|
||||
dns_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ enum nsapi_error {
|
|||
NSAPI_ERROR_CONNECTION_LOST = -3016, /*!< connection lost */
|
||||
NSAPI_ERROR_CONNECTION_TIMEOUT = -3017, /*!< connection timed out */
|
||||
NSAPI_ERROR_ADDRESS_IN_USE = -3018, /*!< Address already in use */
|
||||
NSAPI_ERROR_TIMEOUT = -3019, /*!< operation timed out */
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue