Getaddrinfo interface for multiple DNS adresses added.

New members are added to the network interface
-getaddrinfo
-getaddrinfo_async
gethostbyname is unchanged but gethostbyname_async  result param now contains results od DNS records found.
Test cases for sync/async added added to DNS test folder.
pull/11653/head
Tymoteusz Bloch 2019-10-08 16:21:52 +02:00
parent f77f4ea911
commit 8b2f4c2e7e
30 changed files with 556 additions and 52 deletions

View File

@ -22,6 +22,7 @@
#include "utest.h"
#include "dns_tests.h"
#define RESULTS_NUM 1
using namespace utest::v1;
namespace {
@ -53,7 +54,7 @@ void ASYNCHRONOUS_DNS_CACHE()
semaphore.acquire();
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, data.result);
TEST_ASSERT_EQUAL(RESULTS_NUM, data.result);
TEST_ASSERT(strlen(data.addr.get_ip_address()) > 1);
int delay_ms = (ticker_us - started_us) / 1000;

View File

@ -37,9 +37,9 @@ void ASYNCHRONOUS_DNS_CANCEL()
data[i].semaphore = &semaphore;
data[i].req_result = get_interface()->gethostbyname_async(dns_test_hosts[i],
mbed::Callback<void(nsapi_error_t, SocketAddress *)>(hostbyname_cb, (void *) &data[i]));
TEST_ASSERT(data[i].req_result >= 0 || data[i].req_result == NSAPI_ERROR_NO_MEMORY || data[i].req_result == NSAPI_ERROR_BUSY);
TEST_ASSERT(data[i].req_result > 0 || data[i].req_result == NSAPI_ERROR_NO_MEMORY || data[i].req_result == NSAPI_ERROR_BUSY);
if (data[i].req_result >= 0) {
if (data[i].req_result > 0) {
// Callback will be called
count++;
} else {
@ -68,10 +68,10 @@ void ASYNCHRONOUS_DNS_CANCEL()
tr_info("DNS: query \"%s\" => cancel", dns_test_hosts[i]);
continue;
}
TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
if (data[i].result == NSAPI_ERROR_OK) {
tr_info("DNS: query \"%s\" => \"%s\"",
dns_test_hosts[i], data[i].addr.get_ip_address());
TEST_ASSERT(data[i].result == 1 || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
if (data[i].result == 1) {
printf("DNS: query \"%s\" => \"%s\"\n",
dns_test_hosts[i], data[i].addr.get_ip_address());
} else if (data[i].result == NSAPI_ERROR_DNS_FAILURE) {
tr_error("DNS: query \"%s\" => DNS failure", dns_test_hosts[i]);
} else if (data[i].result == NSAPI_ERROR_TIMEOUT) {

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "dns_tests.h"
using namespace utest::v1;
namespace {
int result_number;
int result_no_mem;
int result_dns_failure;
int result_exp_timeout;
}
// Callback used for asynchronous DNS result
void getaddrinfo_cb(void *data, nsapi_error_t result, SocketAddress *address)
{
dns_application_data_multi_ip *app_data = static_cast<dns_application_data_multi_ip *>(data);
app_data->result = result;
for (unsigned int i = 0; i < result; i++) {
if (address) {
app_data->addr[i] = address[i];
}
}
app_data->semaphore->release();
app_data->value_set = true;
}
void do_getaddrinfo_async(const char hosts[][DNS_TEST_HOST_LEN], unsigned int op_count, int *exp_ok, int *exp_no_mem, int *exp_dns_failure, int *exp_timeout)
{
// Verify that there is enough hosts in the host list
TEST_ASSERT(op_count <= MBED_CONF_APP_DNS_TEST_HOSTS_NUM)
// Reset counters
(*exp_ok) = 0;
(*exp_no_mem) = 0;
(*exp_dns_failure) = 0;
(*exp_timeout) = 0;
// Create callback semaphore and data
rtos::Semaphore semaphore;
dns_application_data_multi_ip *data = new dns_application_data_multi_ip[op_count];
SocketAddress hints{{NSAPI_IPv4}, 80};
unsigned int count = 0;
for (unsigned int i = 0; i < op_count; i++) {
data[i].semaphore = &semaphore;
nsapi_error_t err = NetworkInterface::get_default_instance()->getaddrinfo_async(hosts[i], &hints, mbed::Callback<void(nsapi_error_t, SocketAddress *)>(getaddrinfo_cb, (void *) &data[i]));
TEST_ASSERT(err >= 0 || err == NSAPI_ERROR_NO_MEMORY || err == NSAPI_ERROR_BUSY);
if (err >= 0) {
// Callback will be called
count++;
} else {
// No memory to initiate DNS query, callback will not be called
data[i].result = err;
}
}
// Wait for callback(s) to complete
for (unsigned int i = 0; i < count; i++) {
semaphore.acquire();
}
// Print result
for (unsigned int i = 0; i < op_count; i++) {
TEST_ASSERT(data[i].result > 0 || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY
|| data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
if (data[i].result > 0) {
(*exp_ok)++;
for (unsigned int results = 0; results < data[i].result; results++) {
printf("DNS: query \"%s\" => \"%s\"\n",
hosts[i], data[i].addr[results].get_ip_address());
}
} else if (data[i].result == NSAPI_ERROR_DNS_FAILURE) {
(*exp_dns_failure)++;
printf("DNS: query \"%s\" => DNS failure\n", hosts[i]);
} else if (data[i].result == NSAPI_ERROR_TIMEOUT) {
(*exp_timeout)++;
printf("DNS: query \"%s\" => timeout\n", hosts[i]);
} else if (data[i].result == NSAPI_ERROR_NO_MEMORY) {
(*exp_no_mem)++;
printf("DNS: query \"%s\" => no memory\n", hosts[i]);
} else if (data[i].result == NSAPI_ERROR_BUSY) {
(*exp_no_mem)++;
printf("DNS: query \"%s\" => busy\n", hosts[i]);
}
}
delete[] data;
}
void ASYNCHRONOUS_DNS_MULTI_IP()
{
nsapi_dns_reset();
do_getaddrinfo_async(dns_test_hosts_multi_ip, MBED_CONF_APP_DNS_SIMULT_QUERIES, &result_number, &result_no_mem, &result_dns_failure, &result_exp_timeout);
TEST_ASSERT_EQUAL(MBED_CONF_APP_DNS_SIMULT_QUERIES, result_number);
TEST_ASSERT_EQUAL(0, result_no_mem);
TEST_ASSERT_EQUAL(0, result_dns_failure);
TEST_ASSERT_EQUAL(0, result_exp_timeout);
}

View File

@ -54,7 +54,7 @@ void ASYNCHRONOUS_DNS_NON_ASYNC_AND_ASYNC()
get_interface()->gethostbyname_async_cancel(err);
}
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, data.result);
TEST_ASSERT_EQUAL(1, data.result);
tr_info("DNS: query \"%s\" => \"%s\"",
dns_test_hosts_second[0], data.addr.get_ip_address());

View File

@ -35,6 +35,10 @@
#define MBED_CONF_NSAPI_DNS_CACHE_SIZE 3
#endif
#ifndef MBED_CONF_APP_DNS_TEST_HOSTS_NUM
#define MBED_CONF_APP_DNS_TEST_HOSTS_NUM 6
#endif
// Hostnames for testing against
// Both lists must have A and AAAA records
#ifndef MBED_CONF_APP_DNS_TEST_HOSTS
@ -45,8 +49,8 @@
#define MBED_CONF_APP_DNS_TEST_HOSTS_SECOND {"ipv6ready.org", "wireshark.org", "bbc.co.uk", "cnn.com", "www.flickr.com", "www.mozilla.org"}
#endif
#ifndef MBED_CONF_APP_DNS_TEST_HOSTS_NUM
#define MBED_CONF_APP_DNS_TEST_HOSTS_NUM 6
#ifndef MBED_CONF_APP_DNS_TEST_MULTI_IP_HOSTS
#define MBED_CONF_APP_DNS_TEST_MULTI_IP_HOSTS {"google.com", "www.mozilla.org", "yahoo.com", "instagram.com","www.flickr.com"}
#endif
#define DNS_TEST_HOST_LEN 40
@ -59,8 +63,17 @@ struct dns_application_data {
bool value_set;
};
struct dns_application_data_multi_ip {
rtos::Semaphore *semaphore;
nsapi_error_t result;
SocketAddress addr[MBED_CONF_NSAPI_DNS_ADDRESSES_LIMIT];
nsapi_error_t req_result;
bool value_set;
};
extern const char dns_test_hosts[MBED_CONF_APP_DNS_TEST_HOSTS_NUM][DNS_TEST_HOST_LEN];
extern const char dns_test_hosts_second[MBED_CONF_APP_DNS_TEST_HOSTS_NUM][DNS_TEST_HOST_LEN];
extern const char dns_test_hosts_multi_ip[MBED_CONF_APP_DNS_SIMULT_QUERIES][DNS_TEST_HOST_LEN];
/*
* Utility functions
@ -95,4 +108,6 @@ void SYNCHRONOUS_DNS();
void SYNCHRONOUS_DNS_MULTIPLE();
void SYNCHRONOUS_DNS_CACHE();
void SYNCHRONOUS_DNS_INVALID();
void SYNCHRONOUS_DNS_MULTI_IP();
void ASYNCHRONOUS_DNS_MULTI_IP();
#endif

View File

@ -42,6 +42,7 @@ NetworkInterface *net;
const char dns_test_hosts[MBED_CONF_APP_DNS_TEST_HOSTS_NUM][DNS_TEST_HOST_LEN] = MBED_CONF_APP_DNS_TEST_HOSTS;
const char dns_test_hosts_second[MBED_CONF_APP_DNS_TEST_HOSTS_NUM][DNS_TEST_HOST_LEN] = MBED_CONF_APP_DNS_TEST_HOSTS_SECOND;
const char dns_test_hosts_multi_ip[MBED_CONF_APP_DNS_SIMULT_QUERIES][DNS_TEST_HOST_LEN] = MBED_CONF_APP_DNS_TEST_MULTI_IP_HOSTS;
// Callback used for asynchronous DNS result
void hostbyname_cb(void *data, nsapi_error_t result, SocketAddress *address)
@ -92,8 +93,8 @@ void do_asynchronous_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsign
// Print result
for (unsigned int i = 0; i < op_count; i++) {
TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
if (data[i].result == NSAPI_ERROR_OK) {
TEST_ASSERT(data[i].result > 0 || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
if (data[i].result > 0) {
(*exp_ok)++;
tr_info("DNS: query \"%s\" => \"%s\"",
hosts[i], data[i].addr.get_ip_address());
@ -220,6 +221,8 @@ Case cases[] = {
Case("SYNCHRONOUS_DNS", SYNCHRONOUS_DNS),
Case("SYNCHRONOUS_DNS_MULTIPLE", SYNCHRONOUS_DNS_MULTIPLE),
Case("SYNCHRONOUS_DNS_INVALID", SYNCHRONOUS_DNS_INVALID),
Case("SYNCHRONOUS_DNS_MULTI_IP", SYNCHRONOUS_DNS_MULTI_IP),
Case("ASYNCHRONOUS_DNS_MULTI_IP", ASYNCHRONOUS_DNS_MULTI_IP),
};
Specification specification(test_setup, cases, greentea_teardown, greentea_continue_handlers);

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "dns_tests.h"
using namespace utest::v1;
namespace {
int result_number;
int result_no_mem;
int result_dns_failure;
int result_exp_timeout;
}
void do_getaddrinfo(const char hosts[][DNS_TEST_HOST_LEN], unsigned int op_count, int *exp_ok, int *exp_no_mem, int *exp_dns_failure, int *exp_timeout)
{
// Verify that there is enough hosts in the host list
TEST_ASSERT(op_count <= MBED_CONF_APP_DNS_TEST_HOSTS_NUM)
// Reset counters
(*exp_ok) = 0;
(*exp_no_mem) = 0;
(*exp_dns_failure) = 0;
(*exp_timeout) = 0;
SocketAddress hints{{NSAPI_IPv4}, 80};
for (unsigned int i = 0; i < op_count; i++) {
SocketAddress *result;
nsapi_error_t err = NetworkInterface::get_default_instance()->get_default_instance()->getaddrinfo(hosts[i], &hints, &result);
if (err == NSAPI_ERROR_DNS_FAILURE) {
(*exp_dns_failure)++;
printf("DNS: query \"%s\" => DNS failure\n", hosts[i]);
} else if (err == NSAPI_ERROR_TIMEOUT) {
(*exp_timeout)++;
printf("DNS: query \"%s\" => timeout\n", hosts[i]);
} else if (err == NSAPI_ERROR_NO_MEMORY) {
(*exp_no_mem)++;
printf("DNS: query \"%s\" => no memory\n", hosts[i]);
} else if (err == NSAPI_ERROR_BUSY) {
(*exp_no_mem)++;
printf("DNS: query \"%s\" => busy\n", hosts[i]);
} else if (err > NSAPI_ERROR_OK) {
(*exp_ok)++;
for (unsigned int results = 0; results < err; results++) {
printf("DNS: query \"%s\" => \"%s\"\n", hosts[i], result[results].get_ip_address());
}
} else if (err == 0) {
printf("DNS: query \"%s\", no results\n", hosts[i]);
TEST_FAIL();
} else if (err < 0) {
printf("DNS: query \"%s\" => %d, unexpected answer\n", hosts[i], err);
TEST_FAIL();
}
}
}
void SYNCHRONOUS_DNS_MULTI_IP()
{
nsapi_dns_reset();
do_getaddrinfo(dns_test_hosts_multi_ip, MBED_CONF_APP_DNS_SIMULT_QUERIES, &result_number, &result_no_mem, &result_dns_failure, &result_exp_timeout);
TEST_ASSERT_EQUAL(MBED_CONF_APP_DNS_SIMULT_QUERIES, result_number);
TEST_ASSERT_EQUAL(0, result_no_mem);
TEST_ASSERT_EQUAL(0, result_dns_failure);
TEST_ASSERT_EQUAL(0, result_exp_timeout);
}

View File

@ -332,11 +332,14 @@ TEST_F(Test_IfaceDnsSocket, multiple_queries)
SocketAddress *addr_cache;
// Cache will only raturn one address.
EXPECT_EQ(Test_IfaceDnsSocket::query_id, getaddrinfo(&stackMock(), "www.google.com", hints, &addr_cache));
EXPECT_EQ(3, getaddrinfo(&stackMock(), "www.google.com", hints, &addr_cache));
// This is a bug which will be fixed in
EXPECT_EQ(addr_cache[0].get_ip_version(), NSAPI_IPv4);
EXPECT_FALSE(strncmp(addr_cache[0].get_ip_address(), "216.58.207.238", sizeof("216.58.207.238")));
EXPECT_EQ(addr_cache[1].get_ip_version(), NSAPI_IPv4);
EXPECT_FALSE(strncmp(addr_cache[1].get_ip_address(), "222.173.190.239", sizeof("222.173.190.239")));
EXPECT_EQ(addr_cache[2].get_ip_version(), NSAPI_IPv4);
EXPECT_FALSE(strncmp(addr_cache[2].get_ip_address(), "1.2.3.4", sizeof("1.2.3.4")));
delete[] addr_cache;
}
@ -400,7 +403,7 @@ TEST_F(Test_IfaceDnsSocket, simultaneous_query_async)
// Run again to execute response_handler
executeEventQueueCallbacks();
EXPECT_EQ(NSAPI_ERROR_OK, Test_IfaceDnsSocket::hostname_cb_result);
EXPECT_EQ(1, Test_IfaceDnsSocket::hostname_cb_result);
EXPECT_EQ(Test_IfaceDnsSocket::hostname_cb_address[0].get_ip_version(), NSAPI_IPv4);
EXPECT_FALSE(strncmp(Test_IfaceDnsSocket::hostname_cb_address[0].get_ip_address(), "216.58.207.238", sizeof("216.58.207.238")));
@ -473,11 +476,12 @@ TEST_F(Test_IfaceDnsSocket, single_query_async_multiple)
Test_IfaceDnsSocket::hostname_cb_result = NSAPI_ERROR_DEVICE_ERROR;
// Do not set any return values. Second call should use cache.
// Cache will only return one address!
EXPECT_EQ(0, getaddrinfo_async(&stackMock(), "www.google.com", &Test_IfaceDnsSocket::hostbyname_cb));
EXPECT_EQ(NSAPI_ERROR_OK, Test_IfaceDnsSocket::hostname_cb_result);
EXPECT_EQ(3, getaddrinfo_async(&stackMock(), "www.google.com", &Test_IfaceDnsSocket::hostbyname_cb));
EXPECT_EQ(3, Test_IfaceDnsSocket::hostname_cb_result);
EXPECT_EQ(Test_IfaceDnsSocket::hostname_cb_address[0].get_ip_version(), NSAPI_IPv4);
EXPECT_FALSE(strncmp(Test_IfaceDnsSocket::hostname_cb_address[0].get_ip_address(), "216.58.207.238", sizeof("216.58.207.238")));
EXPECT_FALSE(strncmp(Test_IfaceDnsSocket::hostname_cb_address[1].get_ip_address(), "222.173.190.239", sizeof("222.173.190.239")));
EXPECT_FALSE(strncmp(Test_IfaceDnsSocket::hostname_cb_address[2].get_ip_address(), "1.2.3.4", sizeof("1.2.3.4")));
delete[] Test_IfaceDnsSocket::hostname_cb_address;
}

View File

@ -3,6 +3,8 @@
# UNIT TESTS
####################
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_NSAPI_DNS_ADDRESSES_LIMIT=10")
set(unittest-sources
../features/netsocket/SocketAddress.cpp
../features/netsocket/NetworkStack.cpp

View File

@ -23,6 +23,8 @@
#include "equeue_stub.h"
#define EXPECTED_DNS_RESULT 1
// Control nsapi stub return value. See stubs/nsapi_dns_stub.cpp
extern nsapi_error_t nsapi_stub_return_value;
@ -219,7 +221,7 @@ TEST_F(TestNetworkStack, gethostbyname_async_eventqueue_simple_address)
EXPECT_FALSE(callback_is_called);
EXPECT_EQ(stack->gethostbyname_async("127.0.0.1", mbed::callback(my_callback), NSAPI_IPv4), NSAPI_ERROR_OK);
EXPECT_TRUE(callback_is_called);
EXPECT_EQ(result_received, NSAPI_ERROR_OK);
EXPECT_EQ(result_received, EXPECTED_DNS_RESULT);
EXPECT_EQ(std::string(address_received.get_ip_address()), stack->ip_address);
}

View File

@ -81,6 +81,11 @@ nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *a
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_value_or_error_t NetworkInterface::getaddrinfo(const char *hostname, SocketAddress *hints, SocketAddress **res, const char *interface_name)
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address, const char *interface_name)
{
return NSAPI_ERROR_UNSUPPORTED;
@ -106,6 +111,11 @@ nsapi_value_or_error_t NetworkInterface::gethostbyname_async(char const *, mbed:
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_value_or_error_t NetworkInterface::getaddrinfo_async(const char *hostname, SocketAddress *hints, hostbyname_cb_t callback, const char *interface_name)
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t NetworkInterface::gethostbyname_async_cancel(int id)
{
return NSAPI_ERROR_UNSUPPORTED;

View File

@ -27,6 +27,11 @@ nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *addre
return NSAPI_ERROR_OK;
}
nsapi_value_or_error_t NetworkStack::getaddrinfo(const char *hostname, SocketAddress *hints, SocketAddress **res, const char *interface_name)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address, const char *interface_name)
{
return NSAPI_ERROR_OK;
@ -74,6 +79,11 @@ nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *host, hostb
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_value_or_error_t NetworkStack::getaddrinfo_async(const char *hostname, SocketAddress *hints, hostbyname_cb_t callback, const char *interface_name)
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t NetworkStack::gethostbyname_async_cancel(int id)
{
return NSAPI_ERROR_UNSUPPORTED;

View File

@ -54,11 +54,19 @@ public:
{
return return_value;
}
virtual nsapi_value_or_error_t getaddrinfo(const char *hostname, SocketAddress *hints, SocketAddress **res, const char *interface_name)
{
return return_value;
}
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version,
const char *interface_name)
{
return return_value;
}
virtual nsapi_value_or_error_t getaddrinfo_async(const char *hostname, SocketAddress *hints, hostbyname_cb_t callback, const char *interface_name)
{
return return_value;
}
virtual nsapi_error_t gethostbyname_async_cancel(int id)
{
return return_value;

View File

@ -28,6 +28,12 @@ nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
return nsapi_stub_return_value;
}
nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host,
SocketAddress *addresses, nsapi_size_t addr_count, const char *interface_name, nsapi_version_t version)
{
return nsapi_stub_return_value;
}
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb, const char *interface_name,
nsapi_version_t version)
@ -37,6 +43,15 @@ nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
return nsapi_stub_return_value;
}
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, const char *interface_name, nsapi_version_t version)
{
query_callback = callback;
callin_callback = call_in_cb;
return nsapi_stub_return_value;
}
nsapi_error_t nsapi_dns_query_async_cancel(nsapi_error_t id)
{
return nsapi_stub_return_value;

View File

@ -42,6 +42,23 @@ public:
*/
virtual nsapi_error_t gethostbyname(const char *host,
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC, const char *interface_name = NULL) = 0;
/** Translate a hostname to the multiple IP addresses with specific version using network interface name.
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolve using a UDP socket on the stack.
*
* @param hostname Hostname to resolve.
* @param hints Pointer to a SocketAddress with query parameters.
* @param res Pointer to a SocketAddress array to store the result..
* @param interface_name Network interface name
* @return number of results on success, negative error code on failure.
*/
virtual nsapi_value_or_error_t getaddrinfo(const char *hostname, SocketAddress *hints, SocketAddress **res, const char *interface_name = NULL) = 0;
/** Hostname translation callback for gethostbyname_async.
*
* The callback is called after DNS resolution completes, or a failure occurs.
@ -52,10 +69,11 @@ public:
* The callback should not perform expensive operations such as socket recv/send
* calls or blocking operations.
*
* @param result NSAPI_ERROR_OK on success, negative error code on failure.
* @param result Negative error code on failure or
* value that represents the number of DNS records
* @param address On success, destination for the host SocketAddress.
*/
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address)> hostbyname_cb_t;
typedef mbed::Callback<void (nsapi_value_or_error_t result, SocketAddress *address)> hostbyname_cb_t;
/** Translate a hostname to an IP address (asynchronous)
*
@ -83,6 +101,29 @@ public:
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version = NSAPI_UNSPEC,
const char *interface_name = NULL) = 0;
/** Translate a hostname to the multiple IP addresses (asynchronous)
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolved using a UDP socket on the stack.
*
* The call is non-blocking. Result of the DNS operation is returned by the callback.
* If this function returns failure, callback will not be called. In case that
* IP addresses are found from DNS cache, callback will be called before function returns.
*
* @param hostname Hostname to resolve.
* @param hints Pointer to a SocketAddress with query parameters.
* @param callback Callback that is called to return the result.
* @param interface_name Network interface name
* @return NSAPI_ERROR_OK on immediate success,
* negative error code on immediate failure or
* a positive unique ID that represents the hostname translation operation
* and can be passed to cancel.
*/
virtual nsapi_value_or_error_t getaddrinfo_async(const char *hostname, SocketAddress *hints, hostbyname_cb_t callback, const char *interface_name = NULL) = 0;
/** Cancel asynchronous hostname translation.
*
* When translation is canceled, callback is not called.

View File

@ -96,11 +96,21 @@ nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *a
return get_stack()->gethostbyname(name, address, version, interface_name);
}
nsapi_value_or_error_t NetworkInterface::getaddrinfo(const char *hostname, SocketAddress *hints, SocketAddress **res, const char *interface_name)
{
return get_stack()->getaddrinfo(hostname, hints, res, interface_name);
}
nsapi_value_or_error_t NetworkInterface::gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version, const char *interface_name)
{
return get_stack()->gethostbyname_async(host, callback, version, interface_name);
}
nsapi_value_or_error_t NetworkInterface::getaddrinfo_async(const char *hostname, SocketAddress *hints, hostbyname_cb_t callback, const char *interface_name)
{
return get_stack()->getaddrinfo_async(hostname, hints, callback, interface_name);
}
nsapi_error_t NetworkInterface::gethostbyname_async_cancel(int id)
{
return get_stack()->gethostbyname_async_cancel(id);

View File

@ -237,6 +237,22 @@ public:
virtual nsapi_error_t gethostbyname(const char *host,
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC, const char *interface_name = NULL);
/** Translate a hostname to the multiple IP addresses with specific version using network interface name.
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolve using a UDP socket on the stack.
*
* @param hostname Hostname to resolve.
* @param hints Pointer to a SocketAddress with query parameters.
* @param res Pointer to a SocketAddress array to store the result..
* @param interface_name Network interface name
* @return number of results on success, negative error code on failure.
*/
virtual nsapi_value_or_error_t getaddrinfo(const char *hostname, SocketAddress *hints, SocketAddress **res, const char *interface_name = NULL);
/** Hostname translation callback (for use with gethostbyname_async()).
*
* Callback will be called after DNS resolution completes or a failure occurs.
@ -247,10 +263,11 @@ public:
* The callback should not perform expensive operations such as socket recv/send
* calls or blocking operations.
*
* @param result NSAPI_ERROR_OK on success, negative error code on failure.
* @param result Negative error code on failure or
* value that represents the number of DNS records
* @param address On success, destination for the host SocketAddress.
*/
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address)> hostbyname_cb_t;
typedef mbed::Callback<void (nsapi_value_or_error_t result, SocketAddress *address)> hostbyname_cb_t;
/** Translate a hostname to an IP address (asynchronous) using network interface name.
*
@ -278,6 +295,30 @@ public:
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version = NSAPI_UNSPEC,
const char *interface_name = NULL);
/** Translate a hostname to the multiple IP addresses (asynchronous) using network interface name.
*
* The hostname may be either a domain name or a dotted IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolve using a UDP socket on the stack.
*
* Call is non-blocking. Result of the DNS operation is returned by the callback.
* If this function returns failure, callback will not be called. In case result
* is success (IP address was found from DNS cache), callback will be called
* before function returns.
*
* @param hostname Hostname to resolve.
* @param hints Pointer to a SocketAddress with query parameters.
* @param callback Callback that is called for result.
* @param interface_name Network interface name
* @return 0 on immediate success,
* negative error code on immediate failure or
* a positive unique id that represents the hostname translation operation
* and can be passed to cancel.
*/
virtual nsapi_value_or_error_t getaddrinfo_async(const char *hostname, SocketAddress *hints, hostbyname_cb_t callback, const char *interface_name = NULL);
/** Cancel asynchronous hostname translation.
*
* When translation is cancelled, callback will not be called.

View File

@ -76,6 +76,40 @@ nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *addre
return nsapi_dns_query(this, name, address, interface_name, version);
}
nsapi_value_or_error_t NetworkStack::getaddrinfo(const char *hostname, SocketAddress *hints, SocketAddress **res, const char *interface_name)
{
int i;
if (hostname[0] == '\0') {
return NSAPI_ERROR_PARAMETER;
}
nsapi_version_t version = hints->get_ip_version();
// if the version is unspecified, try to guess the version from the
// ip address of the underlying stack
if (version == NSAPI_UNSPEC) {
SocketAddress testaddress;
if (testaddress.set_ip_address(this->get_ip_address())) {
version = testaddress.get_ip_version();
}
}
SocketAddress *temp = new (std::nothrow) SocketAddress [MBED_CONF_NSAPI_DNS_ADDRESSES_LIMIT];
if (!temp) {
return NSAPI_ERROR_NO_MEMORY;
}
int adr_cnt = nsapi_dns_query_multiple(this, hostname, temp, MBED_CONF_NSAPI_DNS_ADDRESSES_LIMIT, interface_name, version);
if (adr_cnt > 0) {
*res = new (std::nothrow) SocketAddress [adr_cnt];
for (i = 0; i < adr_cnt; i++) {
(*res)[i] = temp[i];
}
}
delete[] temp;
return adr_cnt;
}
nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version, const char *interface_name)
{
SocketAddress address;
@ -90,7 +124,7 @@ nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *name, hostb
return NSAPI_ERROR_DNS_FAILURE;
}
callback(NSAPI_ERROR_OK, &address);
callback(1, &address);
return NSAPI_ERROR_OK;
}
@ -108,6 +142,27 @@ nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *name, hostb
return nsapi_dns_query_async(this, name, callback, call_in_cb, interface_name, version);
}
nsapi_value_or_error_t NetworkStack::getaddrinfo_async(const char *hostname, SocketAddress *hints, hostbyname_cb_t callback, const char *interface_name)
{
SocketAddress address;
if (hostname[0] == '\0') {
return NSAPI_ERROR_PARAMETER;
}
nsapi_version_t version = hints->get_ip_version();
// if the version is unspecified, try to guess the version from the
// ip address of the underlying stack
if (version == NSAPI_UNSPEC) {
SocketAddress testaddress;
if (testaddress.set_ip_address(this->get_ip_address())) {
version = testaddress.get_ip_version();
}
}
call_in_callback_cb_t call_in_cb = get_call_in_callback();
return nsapi_dns_query_multiple_async(this, hostname, callback, MBED_CONF_NSAPI_DNS_ADDRESSES_LIMIT, call_in_cb, interface_name, version);
}
nsapi_error_t NetworkStack::gethostbyname_async_cancel(int id)
{
return nsapi_dns_query_async_cancel(id);

View File

@ -98,6 +98,22 @@ public:
virtual nsapi_error_t gethostbyname(const char *host,
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC, const char *interface_name = NULL);
/** Translate a hostname to the multiple IP addresses with specific version using network interface name.
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolve using a UDP socket on the stack.
*
* @param hostname Hostname to resolve.
* @param hints Pointer to a SocketAddress with query parameters.
* @param res Pointer to a SocketAddress array to store the result..
* @param interface_name Network interface name
* @return number of results on success, negative error code on failure.
*/
virtual nsapi_value_or_error_t getaddrinfo(const char *hostname, SocketAddress *hints, SocketAddress **res, const char *interface_name = NULL);
/** Hostname translation callback (asynchronous)
*
* Callback will be called after DNS resolution completes or a failure occurs.
@ -108,12 +124,13 @@ public:
* The callback should not perform expensive operations such as socket recv/send
* calls or blocking operations.
*
* @param status NSAPI_ERROR_OK on success, negative error code on failure
* @param result Negative error code on failure or
* value that represents the number of DNS records
* @param address On success, destination for the host SocketAddress
*/
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address)> hostbyname_cb_t;
typedef mbed::Callback<void (nsapi_value_or_error_t result, SocketAddress *address)> hostbyname_cb_t;
/** Translates a hostname to an IP address (asynchronous)
/** Translates a hostname to multiple IP addresses (asynchronous)
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
@ -139,6 +156,29 @@ public:
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version = NSAPI_UNSPEC,
const char *interface_name = NULL);
/** Translates a hostname to the multiple IP addresses (asynchronous)
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolve using a UDP socket on the stack.
*
* The call is non-blocking. Result of the DNS operation is returned by the callback.
* If this function returns failure, callback will not be called. In case that
* IP addresses are found from DNS cache, callback will be called before function returns.
*
* @param hostname Hostname to resolve
* @param hints Pointer to a SocketAddress with query parameters.
* @param callback Callback that is called for result
* @param interface_name Network interface_name
* @return 0 on immediate success,
* negative error code on immediate failure or
* a positive unique id that represents the hostname translation operation
* and can be passed to cancel
*/
virtual nsapi_value_or_error_t getaddrinfo_async(const char *hostname, SocketAddress *hints, hostbyname_cb_t callback, const char *interface_name = NULL);
/** Cancels asynchronous hostname translation
*
* When translation is cancelled, callback will not be called.

View File

@ -58,6 +58,10 @@
"help": "Number of cached host name resolutions",
"value": 3
},
"dns-addresses-limit": {
"help": "Max number IP addresses returned by multiple DNS query",
"value": 10
},
"socket-stats-enabled": {
"help": "Enable network socket statistics",
"value": false

View File

@ -44,12 +44,16 @@
#define DNS_QUERY_QUEUE_SIZE 5
#define DNS_HOST_NAME_MAX_LEN 255
#define DNS_TIMER_TIMEOUT 100
#if !defined(MIN)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
struct DNS_CACHE {
nsapi_addr_t address;
nsapi_addr_t *address;
char *host;
uint64_t expires; /*!< time to live in milliseconds */
uint64_t accessed; /*!< last accessed */
uint8_t count; /*!< number of IP addresses */
};
struct SOCKET_CB_DATA {
@ -88,7 +92,7 @@ struct DNS_QUERY {
dns_state state;
};
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, uint8_t count);
static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address);
static void nsapi_dns_cache_reset();
@ -319,7 +323,7 @@ static int dns_scan_response(const uint8_t *ptr, uint16_t exp_id, uint32_t *ttl,
return count;
}
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, uint8_t count)
{
#if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0)
// RFC 1034: if TTL is zero, entry is not added to cache
@ -358,10 +362,15 @@ static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_
dns_cache[index] = new (std::nothrow) DNS_CACHE;
} else {
delete dns_cache[index]->host;
delete dns_cache[index]->address;
}
if (dns_cache[index]) {
dns_cache[index]->address = *address;
dns_cache[index]->address = new (std::nothrow) nsapi_addr_t[count];
for (int i = 0; i < count; i++) {
dns_cache[index]->address[i] = address[i];
}
dns_cache[index]->count = count;
dns_cache[index]->host = new (std::nothrow) char[strlen(host) + 1];
strcpy(dns_cache[index]->host, host);
uint64_t ms_count = rtos::Kernel::get_ms_count();
@ -373,7 +382,7 @@ static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_
#endif
}
static nsapi_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)
{
nsapi_error_t ret_val = NSAPI_ERROR_NO_ADDRESS;
@ -388,13 +397,17 @@ static nsapi_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t vers
delete dns_cache[i]->host;
delete dns_cache[i];
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[0].version) && //only first IP address version check, others have the same version
strcmp(dns_cache[i]->host, host) == 0) {
if (address) {
*address = dns_cache[i]->address;
ret_val = 0;
for (int count = 0; count < dns_cache[i]->count; count++) {
address[count] = dns_cache[i]->address[count];
ret_val++;
}
}
dns_cache[i]->accessed = ms_count;
ret_val = NSAPI_ERROR_OK;
}
}
}
@ -413,6 +426,7 @@ static void nsapi_dns_cache_reset()
if (dns_cache[i]) {
delete[] dns_cache[i]->host;
dns_cache[i]->host = NULL;
delete[] dns_cache[i]->address;
delete dns_cache[i];
dns_cache[i] = NULL;
}
@ -468,10 +482,16 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
}
// check cache
if (nsapi_dns_cache_find(host, version, addr) == NSAPI_ERROR_OK) {
return 1;
nsapi_addr *tmp = new (std::nothrow) nsapi_addr_t [MBED_CONF_NSAPI_DNS_ADDRESSES_LIMIT];
int cached = nsapi_dns_cache_find(host, version, tmp);
if (cached > 0) {
for (int i = 0; i < MIN(cached, addr_count); i++) {
addr[i] = tmp[i];
}
delete [] tmp;
return MIN(cached, addr_count);
}
delete [] tmp;
// create a udp socket
UDPSocket socket;
int err = socket.open(stack);
@ -549,7 +569,7 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
uint32_t ttl;
int resp = dns_scan_response(response, 1, &ttl, addr, addr_count);
if (resp > 0) {
nsapi_dns_cache_add(host, addr, ttl);
nsapi_dns_cache_add(host, addr, ttl, resp);
result = resp;
} else if (resp < 0) {
continue;
@ -584,6 +604,11 @@ nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *
SocketAddress *addresses, nsapi_size_t addr_count, const char *interface_name, nsapi_version_t version)
{
nsapi_addr_t *addrs = new (std::nothrow) nsapi_addr_t[addr_count];
if (!addrs) {
return NSAPI_ERROR_NO_MEMORY;
}
nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, addrs, addr_count, interface_name, version);
if (result > 0) {
@ -675,14 +700,32 @@ nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const
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;
}
nsapi_addr *address = new (std::nothrow) nsapi_addr_t [MBED_CONF_NSAPI_DNS_ADDRESSES_LIMIT];
int cached = nsapi_dns_cache_find(host, version, address);
if (!addr_count) {
if (cached > 0) {
SocketAddress addr(*address);
dns_mutex->unlock();
callback(1, &addr);
delete[] address;
return NSAPI_ERROR_OK;
}
} else {
if (cached > 0) {
SocketAddress *addr = new (std::nothrow) SocketAddress [cached];
for (int i = 0; i < cached; i++) {
addr[i].set_addr(address[i]);
}
dns_mutex->unlock();
callback(cached, addr);
delete[] address;
delete[] addr;
return cached;
}
}
delete[] address;
int index = -1;
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
@ -1197,12 +1240,8 @@ static void nsapi_dns_query_async_response(void *ptr)
}
// Adds address to cache
nsapi_dns_cache_add(query->host, &(query->addrs[0]), query->ttl);
status = NSAPI_ERROR_OK;
if (query->addr_count > 0) {
status = query->count;
}
nsapi_dns_cache_add(query->host, &(query->addrs[0]), query->ttl, query->count);
status = query->count;
}
nsapi_dns_query_async_resp(query, status, addresses);