Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Nanostack DNS cache usage #13733

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions connectivity/nanostack/include/nanostack-interface/Nanostack.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,58 @@ class Nanostack : public OnboardNetworkStack, private mbed::NonCopyable<Nanostac
/** @copydoc NetworkStack::get_ip_address */
nsapi_error_t get_ip_address(SocketAddress *sockAddr) override;

/** Translate a hostname to an IP address 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.
*
* Method first checks Nanostack DNS query result cache. If match is found, then the result is returned immediately.
* Otherwise method calls DNS resolver to find a match.
*
* @param host Hostname to resolve.
* @param address Pointer to a SocketAddress to store the result.
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
* version is chosen by the stack (defaults to NSAPI_UNSPEC).
* @param interface_name Network interface name
* @return NSAPI_ERROR_OK on success, negative error code on failure.
*/
virtual nsapi_error_t gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name);

/** Translate a hostname to an IP address (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.
*
* Method first checks Nanostack DNS query result cache. If match is found, then the result is returned immediately.
*
* 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 host Hostname to resolve.
* @param callback Callback that is called for result.
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
* version is chosen by the stack (defaults to NSAPI_UNSPEC).
* @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 gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version, const char *interface_name);

/** Get a domain name server from a list of servers to query
*
* Returns a DNS server address for a index. DNS servers are queried from Nanostack DNS cache.
* If returns error no more DNS servers to read.
*
* @param index Index of the DNS server, starts from zero
* @param address Destination for the host address
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t get_dns_server(int index, SocketAddress *address, const char *interface_name);

/** Opens a socket
*
* Creates a network socket and stores it in the specified handle.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,19 @@ class WisunBorderRouter {
* */
mesh_error_t validate_radius_timing(ws_br_radius_timing_t *timing);

/**
* \brief Set DNS query result to Nanostack cache.
*
* Function sets DNS query result to Nanostack cache to get distributed to the devices in the Wi-SUN network.
* Function must be called for a running Wi-SUN Border Router instance.
*
* \param address resolved address of domain_name.
* \param domain_name name of the domain. Must be non-NULL.
* \return MESH_ERROR_NONE on success.
* \return error value in case of failure.
* */
mesh_error_t set_dns_query_result(SocketAddress *address, char *domain_name);

private:
mesh_error_t configure();
mesh_error_t apply_configuration(int8_t mesh_if_id);
Expand Down
17 changes: 17 additions & 0 deletions connectivity/nanostack/mbed-mesh-api/source/WisunBorderRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,3 +452,20 @@ mesh_error_t WisunBorderRouter::validate_radius_timing(ws_br_radius_timing_t *ti

return MESH_ERROR_NONE;
}

mesh_error_t WisunBorderRouter::set_dns_query_result(SocketAddress *address, char *domain_name)
{
if (!domain_name || !address) {
return MESH_ERROR_PARAM;
}

if (_mesh_if_id < 0) {
return MESH_ERROR_STATE;
}

if (ws_bbr_dns_query_result_set(_mesh_if_id, (const uint8_t *)address->get_ip_bytes(), domain_name) >= 0) {
return MESH_ERROR_NONE;
}

return MESH_ERROR_UNKNOWN;
}
133 changes: 133 additions & 0 deletions connectivity/nanostack/source/Nanostack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,22 @@
#include "mesh_system.h" // from inside mbed-mesh-api
#include "socket_api.h"
#include "net_interface.h"
#include "nsapi_dns.h"

// Uncomment to enable trace
//#define HAVE_DEBUG
#include "ns_trace.h"
#define TRACE_GROUP "nsif"

//#define NSIF_DEEP_TRACE
#ifdef NSIF_DEEP_TRACE
#define TRACE_DEEP tr_debug
#else
#define TRACE_DEEP(...)
#endif

#define NANOSTACK_ISDIGIT(c) ((c) >= '0' && (c) <= '9')

#define NS_INTERFACE_SOCKETS_MAX 16 //same as NanoStack SOCKET_MAX

#define MALLOC ns_dyn_mem_alloc
Expand Down Expand Up @@ -150,6 +160,51 @@ static int8_t find_interface_by_address(const uint8_t target_addr[16])
return -1;
}

static int8_t nanostack_interface_id_parse(const char *interface_name)
{
int namelen;
int8_t interface_id = -1;

TRACE_DEEP("nanostack_interface_id_parse() %s", interface_name ? interface_name : "null");

if (!interface_name) {
return -1;
}

// parse interface ID from the interface_name
namelen = strlen(interface_name);
if (namelen < 4 || namelen > 5) {
return -1;
}

if ((strncmp("MES", interface_name, 3) == 0) && NANOSTACK_ISDIGIT(interface_name[3])) {
interface_id = atoi(&interface_name[3]);
}

TRACE_DEEP("parsed interfaceID = %d", interface_id);
return interface_id;
}

static int nanostack_dns_query_result_check(const char *domain_name, SocketAddress *address, const char *interface_name)
{
uint8_t dns_query_addr[16] = {0};
int8_t interface_id, ns_query_result;

interface_id = nanostack_interface_id_parse(interface_name);

ns_query_result = arm_net_dns_query_result_get(interface_id, dns_query_addr, (char *)domain_name);

TRACE_DEEP("nanostack_dns_query_result_check(): interface_id=%d, ret=%d, resolved %s to %s",
interface_id, ns_query_result, domain_name, trace_ipv6(dns_query_addr));

if (ns_query_result == 0) {
address->set_ip_bytes(dns_query_addr, NSAPI_IPv6);
return 0;
}

return -1;
}

void *NanostackSocket::operator new (std::size_t sz)
{
return MALLOC(sz);
Expand Down Expand Up @@ -532,6 +587,84 @@ nsapi_error_t Nanostack::get_ip_address(SocketAddress *sockAddr)
return NSAPI_ERROR_NO_ADDRESS;
}

nsapi_error_t Nanostack::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name)
{
if (name[0] == '\0') {
return NSAPI_ERROR_PARAMETER;
}
// check for simple ip addresses
if (address->set_ip_address(name)) {
if (version != NSAPI_UNSPEC && address->get_ip_version() != version) {
return NSAPI_ERROR_DNS_FAILURE;
}
return NSAPI_ERROR_OK;
}

// Nanostack is IPv6 stack
if (version == NSAPI_UNSPEC) {
version = NSAPI_IPv6;
}

// try nanostack DNS cache, if not found then fallback to dns query
if (nanostack_dns_query_result_check(name, address, interface_name) == 0) {
return NSAPI_ERROR_OK;
}

return nsapi_dns_query(this, name, address, interface_name, version);
}

nsapi_value_or_error_t Nanostack::gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version, const char *interface_name)
{
SocketAddress address;

if (name[0] == '\0') {
return NSAPI_ERROR_PARAMETER;
}

// check for simple ip addresses
if (address.set_ip_address(name)) {
if (version != NSAPI_UNSPEC && address.get_ip_version() != version) {
return NSAPI_ERROR_DNS_FAILURE;
}
callback(NSAPI_ERROR_OK, &address);
return NSAPI_ERROR_OK;
}

// Nanostack is IPv6 stack
if (version == NSAPI_UNSPEC) {
version = NSAPI_IPv6;
}

// try nanostack DNS cache, if not found then fallback to dns query
if (nanostack_dns_query_result_check(name, &address, interface_name) == 0) {
// hit found, return result immediately
callback(NSAPI_ERROR_OK, &address);
return NSAPI_ERROR_OK;
}

call_in_callback_cb_t call_in_cb = get_call_in_callback();
return nsapi_dns_query_async(this, name, callback, call_in_cb, interface_name, version);
}

nsapi_error_t Nanostack::get_dns_server(int index, SocketAddress *address, const char *interface_name)
{
uint8_t dns_srv_address[16];
int8_t interface_id;
int8_t ret;

interface_id = nanostack_interface_id_parse(interface_name);

ret = arm_net_dns_server_get(interface_id, dns_srv_address, NULL, 0, index);

if (ret == 0) {
address->set_ip_bytes(dns_srv_address, NSAPI_IPv6);
TRACE_DEEP("get_dns_server(), index=%d, ret=%d, address=%s", index, ret, trace_ipv6((uint8_t *)address->get_ip_bytes()));
return NSAPI_ERROR_OK;
}

return NSAPI_ERROR_NO_ADDRESS;
}

nsapi_error_t Nanostack::socket_open(void **handle, nsapi_protocol_t protocol)
{
// Validate parameters
Expand Down