mirror of https://github.com/ARMmbed/mbed-os.git
Added non-blocking DNS functionality to network interface
- Added non-blocking DNS interface to network interface and network stack. - Added caching of DNS replies. - Added a network stack function to get DNS addresses from stack. - Added call and call_in hooks to onboard network stack to allow calling functions from onboard stack context. - Added support to call and call_in functions to LWIP and Nanostack. - Disabled LWIP DNS translator with the exception of DNS address storage used in DNS address get.pull/6847/head
parent
bad530ab0d
commit
b7e8400c2c
|
|
@ -33,6 +33,7 @@
|
|||
#include "lwip/dns.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/lwip_errno.h"
|
||||
#include "lwip-sys/arch/sys_arch.h"
|
||||
|
||||
#include "LWIPStack.h"
|
||||
|
||||
|
|
@ -47,10 +48,10 @@ void LWIP::socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len)
|
|||
return;
|
||||
}
|
||||
|
||||
sys_prot_t prot = sys_arch_protect();
|
||||
|
||||
LWIP &lwip = LWIP::get_instance();
|
||||
|
||||
lwip.adaptation.lock();
|
||||
|
||||
for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
|
||||
if (lwip.arena[i].in_use
|
||||
&& lwip.arena[i].conn == nc
|
||||
|
|
@ -59,7 +60,7 @@ void LWIP::socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len)
|
|||
}
|
||||
}
|
||||
|
||||
sys_arch_unprotect(prot);
|
||||
lwip.adaptation.unlock();
|
||||
}
|
||||
|
||||
#if !LWIP_IPV4 || !LWIP_IPV6
|
||||
|
|
@ -149,6 +150,7 @@ void LWIP::tcpip_init_irq(void *eh)
|
|||
{
|
||||
LWIP *lwip = static_cast<LWIP *>(eh);
|
||||
lwip->tcpip_inited.release();
|
||||
sys_tcpip_thread_set();
|
||||
}
|
||||
|
||||
/* LWIP network stack implementation */
|
||||
|
|
@ -173,80 +175,84 @@ LWIP::LWIP()
|
|||
arena_init();
|
||||
}
|
||||
|
||||
nsapi_error_t LWIP::gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version)
|
||||
nsapi_error_t LWIP::get_dns_server(int index, SocketAddress *address)
|
||||
{
|
||||
ip_addr_t lwip_addr;
|
||||
int dns_entries = 0;
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
u8_t addr_type;
|
||||
if (version == NSAPI_UNSPEC) {
|
||||
const ip_addr_t *ip_addr = NULL;
|
||||
if (default_interface) {
|
||||
ip_addr = get_ip_addr(true, &default_interface->netif);
|
||||
}
|
||||
// Prefer IPv6
|
||||
if (IP_IS_V6(ip_addr)) {
|
||||
// If IPv4 is available use it as backup
|
||||
if (get_ipv4_addr(&default_interface->netif)) {
|
||||
addr_type = NETCONN_DNS_IPV6_IPV4;
|
||||
} else {
|
||||
addr_type = NETCONN_DNS_IPV6;
|
||||
}
|
||||
// Prefer IPv4
|
||||
} else {
|
||||
// If IPv6 is available use it as backup
|
||||
if (get_ipv6_addr(&default_interface->netif)) {
|
||||
addr_type = NETCONN_DNS_IPV4_IPV6;
|
||||
} else {
|
||||
addr_type = NETCONN_DNS_IPV4;
|
||||
for (int i = 0; i < DNS_MAX_SERVERS; i++) {
|
||||
const ip_addr_t *ip_addr = dns_getserver(i);
|
||||
if (!ip_addr_isany(ip_addr)) {
|
||||
if (index == dns_entries) {
|
||||
nsapi_addr_t addr;
|
||||
convert_lwip_addr_to_mbed(&addr, ip_addr);
|
||||
address->set_addr(addr);
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
dns_entries++;
|
||||
}
|
||||
} else if (version == NSAPI_IPv4) {
|
||||
addr_type = NETCONN_DNS_IPV4;
|
||||
} else if (version == NSAPI_IPv6) {
|
||||
addr_type = NETCONN_DNS_IPV6;
|
||||
} else {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
err_t err = netconn_gethostbyname_addrtype(host, &lwip_addr, addr_type);
|
||||
#elif LWIP_IPV4
|
||||
if (version != NSAPI_IPv4 && version != NSAPI_UNSPEC) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
err_t err = netconn_gethostbyname(host, &lwip_addr);
|
||||
#elif LWIP_IPV6
|
||||
if (version != NSAPI_IPv6 && version != NSAPI_UNSPEC) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
err_t err = netconn_gethostbyname(host, &lwip_addr);
|
||||
#endif
|
||||
|
||||
if (err != ERR_OK) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
nsapi_addr_t addr;
|
||||
convert_lwip_addr_to_mbed(&addr, &lwip_addr);
|
||||
address->set_addr(addr);
|
||||
|
||||
return 0;
|
||||
return NSAPI_ERROR_NO_ADDRESS;
|
||||
}
|
||||
|
||||
nsapi_error_t LWIP::add_dns_server(const SocketAddress &address)
|
||||
void LWIP::tcpip_thread_callback(void *ptr)
|
||||
{
|
||||
// Shift all dns servers down to give precedence to new server
|
||||
for (int i = DNS_MAX_SERVERS-1; i > 0; i--) {
|
||||
dns_setserver(i, dns_getserver(i-1));
|
||||
lwip_callback *cb = static_cast<lwip_callback *>(ptr);
|
||||
|
||||
if (cb->delay) {
|
||||
sys_timeout(cb->delay, LWIP::tcpip_thread_callback, ptr);
|
||||
cb->delay = 0;
|
||||
} else {
|
||||
cb->callback();
|
||||
delete cb;
|
||||
}
|
||||
}
|
||||
|
||||
nsapi_error_t LWIP::call(mbed::Callback<void()> func)
|
||||
{
|
||||
return call_in(0, func);
|
||||
}
|
||||
|
||||
nsapi_error_t LWIP::call_in(int delay, mbed::Callback<void()> func)
|
||||
{
|
||||
lwip_callback *cb = new lwip_callback;
|
||||
if (!cb) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
nsapi_addr_t addr = address.get_addr();
|
||||
ip_addr_t ip_addr;
|
||||
if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
cb->delay = delay;
|
||||
cb->callback = func;
|
||||
|
||||
if (tcpip_callback_with_block(LWIP::tcpip_thread_callback, cb, 1) != ERR_OK) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
dns_setserver(0, &ip_addr);
|
||||
return 0;
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
const char *LWIP::get_ip_address()
|
||||
{
|
||||
if (!default_interface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const ip_addr_t *addr = get_ip_addr(true, &default_interface->netif);
|
||||
|
||||
if (!addr) {
|
||||
return NULL;
|
||||
}
|
||||
#if LWIP_IPV6
|
||||
if (IP_IS_V6(addr)) {
|
||||
return ip6addr_ntoa_r(ip_2_ip6(addr), ip_address, sizeof(ip_address));
|
||||
}
|
||||
#endif
|
||||
#if LWIP_IPV4
|
||||
if (IP_IS_V4(addr)) {
|
||||
return ip4addr_ntoa_r(ip_2_ip4(addr), ip_address, sizeof(ip_address));
|
||||
}
|
||||
#endif
|
||||
#if LWIP_IPV6 && LWIP_IPV4
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsapi_error_t LWIP::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto)
|
||||
|
|
@ -439,6 +445,7 @@ nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAdd
|
|||
}
|
||||
|
||||
struct netbuf *buf = netbuf_new();
|
||||
|
||||
err_t err = netbuf_ref(buf, data, (u16_t)size);
|
||||
if (err != ERR_OK) {
|
||||
netbuf_free(buf);
|
||||
|
|
@ -588,7 +595,7 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
|
|||
|
||||
member_pair_index = next_free_multicast_member(s, 0);
|
||||
|
||||
sys_prot_t prot = sys_arch_protect();
|
||||
adaptation.lock();
|
||||
|
||||
#if LWIP_IPV4
|
||||
if (IP_IS_V4(&if_addr)) {
|
||||
|
|
@ -601,7 +608,7 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
|
|||
}
|
||||
#endif
|
||||
|
||||
sys_arch_unprotect(prot);
|
||||
adaptation.unlock();
|
||||
|
||||
if (igmp_err == ERR_OK) {
|
||||
set_multicast_member_registry_bit(s, member_pair_index);
|
||||
|
|
@ -616,7 +623,7 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
|
|||
clear_multicast_member_registry_bit(s, member_pair_index);
|
||||
s->multicast_memberships_count--;
|
||||
|
||||
sys_prot_t prot = sys_arch_protect();
|
||||
adaptation.lock();
|
||||
|
||||
#if LWIP_IPV4
|
||||
if (IP_IS_V4(&if_addr)) {
|
||||
|
|
@ -629,7 +636,7 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
|
|||
}
|
||||
#endif
|
||||
|
||||
sys_arch_unprotect(prot);
|
||||
adaptation.unlock();
|
||||
}
|
||||
|
||||
return err_remap(igmp_err);
|
||||
|
|
|
|||
|
|
@ -198,29 +198,44 @@ public:
|
|||
*/
|
||||
nsapi_error_t _add_ppp_interface(void *pcb, bool default_if, LWIP::Interface **interface_out);
|
||||
|
||||
/** Translates a hostname to an IP address with specific version
|
||||
/** Get a domain name server from a list of servers to query
|
||||
*
|
||||
* 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 host Hostname to resolve
|
||||
* @param address Destination for the host SocketAddress
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC)
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t gethostbyname(const char *host,
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
|
||||
|
||||
/** Add a domain name server to list of servers to query
|
||||
* Returns a DNS server address for a index. 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 add_dns_server(const SocketAddress &address);
|
||||
virtual nsapi_error_t get_dns_server(int index, SocketAddress *address);
|
||||
|
||||
/** Call a callback
|
||||
*
|
||||
* Call a callback from the network stack context. If returns error
|
||||
* callback will not be called.
|
||||
*
|
||||
* @param func Callback to be called
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t call(mbed::Callback<void()> func);
|
||||
|
||||
/** Call a callback after a delay
|
||||
*
|
||||
* Call a callback from the network stack context after a delay. If
|
||||
* returns error callback will not be called.
|
||||
*
|
||||
* @param delay Delay in milliseconds
|
||||
* @param func Callback to be called
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t call_in(int delay, mbed::Callback<void()> func);
|
||||
|
||||
/** Get the local IP address
|
||||
*
|
||||
* @return Null-terminated representation of the local IP address
|
||||
* or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address();
|
||||
|
||||
protected:
|
||||
LWIP();
|
||||
|
|
@ -439,6 +454,11 @@ private:
|
|||
uint32_t multicast_memberships_registry;
|
||||
};
|
||||
|
||||
struct lwip_callback {
|
||||
unsigned int delay;
|
||||
mbed::Callback<void()> callback;
|
||||
};
|
||||
|
||||
static nsapi_error_t err_remap(err_t err);
|
||||
static bool is_local_addr(const ip_addr_t *ip_addr);
|
||||
static const ip_addr_t *get_ip_addr(bool any_addr, const struct netif *netif);
|
||||
|
|
@ -475,9 +495,14 @@ private:
|
|||
static void socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len);
|
||||
|
||||
static void tcpip_init_irq(void *handle);
|
||||
static void tcpip_thread_callback(void *ptr);
|
||||
|
||||
char ip_address[40];
|
||||
rtos::Semaphore tcpip_inited;
|
||||
Interface *default_interface;
|
||||
LWIPMemoryManager memory_manager;
|
||||
osThreadId tcpip_thread_id;
|
||||
rtos::Mutex adaptation;
|
||||
};
|
||||
|
||||
#endif /* LWIPSTACK_H_ */
|
||||
|
|
|
|||
|
|
@ -480,6 +480,24 @@ void sys_msleep(u32_t ms) {
|
|||
osDelay(ms);
|
||||
}
|
||||
|
||||
osThreadId_t lwip_tcpip_thread_id = 0;
|
||||
|
||||
bool sys_tcpip_thread_set(void)
|
||||
{
|
||||
lwip_tcpip_thread_id = osThreadGetId();
|
||||
}
|
||||
|
||||
bool sys_tcpip_thread_check(void)
|
||||
{
|
||||
osThreadId_t thread_id = osThreadGetId();
|
||||
|
||||
if (thread_id == lwip_tcpip_thread_id) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a pool of thread structures
|
||||
static int thread_pool_index = 0;
|
||||
static sys_thread_data_t thread_pool[SYS_THREAD_POOL_N];
|
||||
|
|
|
|||
|
|
@ -85,6 +85,9 @@ typedef sys_thread_data_t* sys_thread_t;
|
|||
// === PROTECTION ===
|
||||
typedef int sys_prot_t;
|
||||
|
||||
bool sys_tcpip_thread_set(void);
|
||||
bool sys_tcpip_thread_check(void);
|
||||
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -102,11 +102,18 @@ netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
|
|||
apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
|
||||
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
||||
|
||||
err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
|
||||
if (err == ERR_OK) {
|
||||
return apimsg->err;
|
||||
if (sys_tcpip_thread_check()) {
|
||||
fn(apimsg);
|
||||
return ERR_OK;
|
||||
} else {
|
||||
err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
|
||||
|
||||
if (err == ERR_OK) {
|
||||
return apimsg->err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -283,16 +283,18 @@ static void dns_init_local(void);
|
|||
static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype));
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
|
||||
|
||||
#if LWIP_FULL_DNS
|
||||
/* forward declarations */
|
||||
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
|
||||
static void dns_check_entries(void);
|
||||
static void dns_call_found(u8_t idx, ip_addr_t* addr);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Globals
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#if LWIP_FULL_DNS
|
||||
/* DNS variables */
|
||||
static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS];
|
||||
#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
|
||||
|
|
@ -301,6 +303,7 @@ static u8_t dns_last_pcb_idx;
|
|||
static u8_t dns_seqno;
|
||||
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
|
||||
static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
|
||||
#endif
|
||||
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
|
||||
|
||||
#if LWIP_IPV4
|
||||
|
|
@ -324,6 +327,7 @@ dns_init(void)
|
|||
dns_setserver(0, &dnsserver);
|
||||
#endif /* DNS_SERVER_ADDRESS */
|
||||
|
||||
#if LWIP_FULL_DNS
|
||||
LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY",
|
||||
sizeof(struct dns_query) == SIZEOF_DNS_QUERY);
|
||||
LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER",
|
||||
|
|
@ -351,6 +355,7 @@ dns_init(void)
|
|||
#if DNS_LOCAL_HOSTLIST
|
||||
dns_init_local();
|
||||
#endif
|
||||
#endif /* LWIP_FULL_DNS */
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -397,10 +402,14 @@ dns_getserver(u8_t numdns)
|
|||
void
|
||||
dns_tmr(void)
|
||||
{
|
||||
#if LWIP_FULL_DNS
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
|
||||
dns_check_entries();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LWIP_FULL_DNS
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
static void
|
||||
dns_init_local(void)
|
||||
|
|
@ -1570,4 +1579,6 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call
|
|||
LWIP_DNS_ISMDNS_ARG(is_mdns));
|
||||
}
|
||||
|
||||
#endif /* LWIP_FULL_DNS */
|
||||
|
||||
#endif /* LWIP_DNS */
|
||||
|
|
|
|||
|
|
@ -290,8 +290,8 @@ struct netconn {
|
|||
/** @ingroup netconn_common
|
||||
* Create new netconn connection
|
||||
* @param t @ref netconn_type */
|
||||
#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
|
||||
#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
|
||||
#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
|
||||
#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
|
||||
struct netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
|
||||
netconn_callback callback);
|
||||
err_t netconn_delete(struct netconn *conn);
|
||||
|
|
|
|||
|
|
@ -157,19 +157,22 @@ void LWIP::arena_init(void)
|
|||
|
||||
struct LWIP::mbed_lwip_socket *LWIP::arena_alloc()
|
||||
{
|
||||
sys_prot_t prot = sys_arch_protect();
|
||||
LWIP &lwip = LWIP::get_instance();
|
||||
|
||||
lwip.adaptation.lock();
|
||||
|
||||
for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
|
||||
if (!arena[i].in_use) {
|
||||
struct mbed_lwip_socket *s = &arena[i];
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->in_use = true;
|
||||
sys_arch_unprotect(prot);
|
||||
lwip.adaptation.unlock();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
sys_arch_unprotect(prot);
|
||||
lwip.adaptation.unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -213,6 +213,8 @@
|
|||
#endif
|
||||
|
||||
#define LWIP_DNS 1
|
||||
// Only DNS address storage is enabled
|
||||
#define LWIP_FULL_DNS 0
|
||||
#define LWIP_SOCKET 0
|
||||
|
||||
#define SO_REUSE 1
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "ns_address.h"
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "eventOS_scheduler.h"
|
||||
#include "eventOS_event_timer.h"
|
||||
#include "randLIB.h"
|
||||
#include "ip6string.h"
|
||||
|
||||
|
|
@ -57,6 +58,7 @@ enum socket_mode_t {
|
|||
SOCKET_MODE_LISTENING, // Socket is listening for connections
|
||||
};
|
||||
|
||||
#define CALL_EVENT 0x12
|
||||
|
||||
class NanostackSocket {
|
||||
public:
|
||||
|
|
@ -444,6 +446,65 @@ void NanostackSocket::event_connection_reset(socket_callback_t *sock_cb)
|
|||
close();
|
||||
}
|
||||
|
||||
Nanostack::Nanostack()
|
||||
: call_event_tasklet(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Nanostack::call_event_tasklet_main(arm_event_s *event)
|
||||
{
|
||||
if (event->event_id == CALL_EVENT) {
|
||||
nanostack_callback *cb = static_cast<nanostack_callback *>(event->data_ptr);
|
||||
cb->callback();
|
||||
delete cb;
|
||||
}
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::call(mbed::Callback<void()> func)
|
||||
{
|
||||
return call_in(0, func);
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::call_in(int delay, mbed::Callback<void()> func)
|
||||
{
|
||||
if (call_event_tasklet < 0) {
|
||||
call_event_tasklet = eventOS_event_handler_create(&call_event_tasklet_main, 0);
|
||||
if (call_event_tasklet < 0) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
nanostack_callback *cb = new nanostack_callback;
|
||||
if (!cb) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
cb->callback = func;
|
||||
|
||||
arm_event_s event;
|
||||
|
||||
event.sender = call_event_tasklet,
|
||||
event.event_id = CALL_EVENT,
|
||||
event.receiver = call_event_tasklet,
|
||||
event.data_ptr = cb;
|
||||
event.event_type = APPLICATION_EVENT;
|
||||
event.priority = ARM_LIB_LOW_PRIORITY_EVENT;
|
||||
|
||||
if (delay) {
|
||||
uint32_t ticks = eventOS_event_timer_ms_to_ticks(delay);
|
||||
if (!eventOS_event_send_in(&event, ticks)) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
} else {
|
||||
if (eventOS_event_send(&event) < 0) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
const char * Nanostack::get_ip_address()
|
||||
{
|
||||
NanostackLockGuard lock;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "NanostackMemoryManager.h"
|
||||
#include "MeshInterface.h"
|
||||
#include "mesh_interface_types.h"
|
||||
#include "eventOS_event.h"
|
||||
|
||||
struct ns_address;
|
||||
|
||||
|
|
@ -43,8 +44,31 @@ public:
|
|||
/* Local variant with stronger typing and manual address specification */
|
||||
nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Nanostack::EthernetInterface **interface_out, const uint8_t *mac_addr = NULL);
|
||||
|
||||
/** Call a callback
|
||||
*
|
||||
* Call a callback from the network stack context. If returns error
|
||||
* callback will not be called.
|
||||
*
|
||||
* @param func Callback to be called
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t call(mbed::Callback<void()> func);
|
||||
|
||||
/** Call a callback after a delay
|
||||
*
|
||||
* Call a callback from the network stack context after a delay. If
|
||||
* returns error callback will not be called.
|
||||
*
|
||||
* @param delay Delay in milliseconds
|
||||
* @param func Callback to be called
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t call_in(int delay, mbed::Callback<void()> func);
|
||||
|
||||
protected:
|
||||
|
||||
Nanostack();
|
||||
|
||||
/** Get the local IP address
|
||||
*
|
||||
* @return Null-terminated representation of the local IP address
|
||||
|
|
@ -242,9 +266,15 @@ protected:
|
|||
virtual nsapi_error_t getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen);
|
||||
|
||||
private:
|
||||
struct nanostack_callback {
|
||||
mbed::Callback<void()> callback;
|
||||
};
|
||||
|
||||
nsapi_size_or_error_t do_sendto(void *handle, const struct ns_address *address, const void *data, nsapi_size_t size);
|
||||
static void call_event_tasklet_main(arm_event_s *event);
|
||||
char text_ip_address[40];
|
||||
NanostackMemoryManager memory_manager;
|
||||
int8_t call_event_tasklet;
|
||||
};
|
||||
|
||||
nsapi_error_t map_mesh_error(mesh_error_t err);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,11 @@ nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *a
|
|||
return get_stack()->gethostbyname(name, address, version);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkInterface::gethostbyname_async(const char *host, hostbyname_cb_t callback, void *data, nsapi_version_t version)
|
||||
{
|
||||
return get_stack()->gethostbyname_async(host, callback, data, version);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address)
|
||||
{
|
||||
return get_stack()->add_dns_server(address);
|
||||
|
|
|
|||
|
|
@ -127,6 +127,38 @@ public:
|
|||
virtual nsapi_error_t gethostbyname(const char *host,
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
|
||||
|
||||
/** Hostname translation callback (asynchronous)
|
||||
*
|
||||
* Callback will be called after DNS resolution completes or a failure
|
||||
* occurs.
|
||||
*
|
||||
* @param status 0 on success, negative error code on failure
|
||||
* @param address On success, destination for the host SocketAddress
|
||||
* @param data Caller defined data
|
||||
*/
|
||||
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address, void *data)> hostbyname_cb_t;
|
||||
|
||||
/** Translates a hostname to an IP address (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.
|
||||
*
|
||||
* Call is non-blocking. Result of the DNS operation is returned by the callback.
|
||||
* If this function returns failure, callback will not be called.
|
||||
*
|
||||
* @param host Hostname to resolve
|
||||
* @param callback Callback that is called for result
|
||||
* @param data Caller defined data returned in callback
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC)
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, void *data,
|
||||
nsapi_version_t version = NSAPI_UNSPEC);
|
||||
|
||||
/** Add a domain name server to list of servers to query
|
||||
*
|
||||
* @param address Destination for the host address
|
||||
|
|
|
|||
|
|
@ -49,11 +49,41 @@ nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *addre
|
|||
return nsapi_dns_query(this, name, address, version);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::gethostbyname_async(const char *name, hostbyname_cb_t callback, void *data, nsapi_version_t version)
|
||||
{
|
||||
SocketAddress address;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
return nsapi_dns_query_async(this, name, callback, data, version);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address)
|
||||
{
|
||||
return nsapi_dns_add_server(address);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::get_dns_server(int index, SocketAddress *address)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include "netsocket/SocketAddress.h"
|
||||
#include "netsocket/NetworkInterface.h"
|
||||
|
||||
// Predeclared classes
|
||||
class OnboardNetworkStack;
|
||||
|
||||
/** NetworkStack class
|
||||
*
|
||||
|
|
@ -37,13 +39,10 @@ public:
|
|||
virtual ~NetworkStack() {};
|
||||
|
||||
/** Get the local IP address
|
||||
* @deprecated
|
||||
*
|
||||
* @return Null-terminated representation of the local IP address
|
||||
* or null if not yet connected
|
||||
*/
|
||||
MBED_DEPRECATED_SINCE("mbed-os-5.7",
|
||||
"Use NetworkInterface::get_ip_address()")
|
||||
virtual const char *get_ip_address();
|
||||
|
||||
/** Translates a hostname to an IP address with specific version
|
||||
|
|
@ -63,6 +62,38 @@ public:
|
|||
virtual nsapi_error_t gethostbyname(const char *host,
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
|
||||
|
||||
/** Hostname translation callback (asynchronous)
|
||||
*
|
||||
* Callback will be called after DNS resolution completes or a failure
|
||||
* occurs.
|
||||
*
|
||||
* @param status 0 on success, negative error code on failure
|
||||
* @param address On success, destination for the host SocketAddress
|
||||
* @param data Caller defined data
|
||||
*/
|
||||
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address, void *data)> hostbyname_cb_t;
|
||||
|
||||
/** Translates a hostname to an IP address (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.
|
||||
*
|
||||
* Call is non-blocking. Result of the DNS operation is returned by the callback.
|
||||
* If this function returns failure, callback will not be called.
|
||||
*
|
||||
* @param host Hostname to resolve
|
||||
* @param callback Callback that is called for result
|
||||
* @param data Caller defined data returned in callback
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC)
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, void *data,
|
||||
nsapi_version_t version = NSAPI_UNSPEC);
|
||||
|
||||
/** Add a domain name server to list of servers to query
|
||||
*
|
||||
* @param address Destination for the host address
|
||||
|
|
@ -70,6 +101,17 @@ public:
|
|||
*/
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address);
|
||||
|
||||
/** Get a domain name server from a list of servers to query
|
||||
*
|
||||
* Returns a DNS server address for a index. 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);
|
||||
|
||||
/* Set stack options
|
||||
*
|
||||
* setstackopt allows an application to pass stack-specific options
|
||||
|
|
@ -101,6 +143,9 @@ public:
|
|||
*/
|
||||
virtual nsapi_error_t getstackopt(int level, int optname, void *optval, unsigned *optlen);
|
||||
|
||||
/** Dynamic downcast to a OnboardNetworkStack */
|
||||
virtual OnboardNetworkStack *onboardNetworkStack() { return 0; }
|
||||
|
||||
protected:
|
||||
friend class Socket;
|
||||
friend class UDPSocket;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ public:
|
|||
*/
|
||||
static OnboardNetworkStack &get_default_instance();
|
||||
|
||||
virtual OnboardNetworkStack *onboardNetworkStack() { return this; }
|
||||
|
||||
/** Representation of a stack's view of an interface.
|
||||
*
|
||||
* Provides facilities required by a driver to implement the application
|
||||
|
|
@ -121,6 +123,26 @@ public:
|
|||
virtual char *get_gateway(char *buf, nsapi_size_t buflen) = 0;
|
||||
};
|
||||
|
||||
/** Call a callback
|
||||
*
|
||||
* Call a callback from the network stack context. If returns error
|
||||
* callback will not be called.
|
||||
*
|
||||
* @param func Callback to be called
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t call(mbed::Callback<void()> func) = 0;
|
||||
|
||||
/** Call a callback after a delay
|
||||
*
|
||||
* Call a callback from the network stack context after a delay. If
|
||||
* returns error callback will not be called.
|
||||
*
|
||||
* @param delay Delay in milliseconds
|
||||
* @param func Callback to be called
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t call_in(int delay, mbed::Callback<void()> func) = 0;
|
||||
|
||||
/** Register a network interface with the IP stack
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "mbed_shared_queues.h"
|
||||
#include "EventQueue.h"
|
||||
#include "OnboardNetworkStack.h"
|
||||
#include "Kernel.h"
|
||||
|
||||
#define CLASS_IN 1
|
||||
|
||||
|
|
@ -29,8 +33,51 @@
|
|||
#define DNS_BUFFER_SIZE 512
|
||||
#define DNS_TIMEOUT 5000
|
||||
#define DNS_SERVERS_SIZE 5
|
||||
#define DNS_RESPONSE_MIN_SIZE 12
|
||||
#define DNS_MAX_TTL 604800
|
||||
#define DNS_CACHE_SIZE 3
|
||||
#define DNS_STACK_SERVERS_NUM 5
|
||||
#define DNS_QUERY_QUEUE_SIZE 5
|
||||
|
||||
nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
|
||||
struct DNS_CACHE {
|
||||
SocketAddress address;
|
||||
char host[128];
|
||||
uint64_t expires; /*!< time to live in milliseconds */
|
||||
uint64_t accessed; /*!< last accessed */
|
||||
};
|
||||
|
||||
struct DNS_QUERY {
|
||||
int unique_id;
|
||||
NetworkStack *stack;
|
||||
char host[128];
|
||||
NetworkStack::hostbyname_cb_t callback;
|
||||
void *cb_data;
|
||||
nsapi_size_t addr_count;
|
||||
nsapi_version_t version;
|
||||
UDPSocket *socket;
|
||||
int dns_server;
|
||||
int retries;
|
||||
int dns_message_id;
|
||||
};
|
||||
|
||||
typedef nsapi_error_t (*nsapi_dns_call_t)(mbed::Callback<void()> func);
|
||||
typedef nsapi_error_t (*nsapi_dns_call_in_t)(int delay, mbed::Callback<void()> func);
|
||||
|
||||
static void nsapi_dns_cache_add(const char *host, SocketAddress *address, uint32_t ttl);
|
||||
static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, SocketAddress *address);
|
||||
|
||||
static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, int *index, SocketAddress *dns_addr);
|
||||
|
||||
static void nsapi_dns_query_async_create(DNS_QUERY *query);
|
||||
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_socket_callback(NetworkStack *stack);
|
||||
static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack);
|
||||
|
||||
static nsapi_error_t nsapi_dns_call_default(mbed::Callback<void()> func);
|
||||
static nsapi_error_t nsapi_dns_call_in_default(int delay, mbed::Callback<void()> func);
|
||||
|
||||
static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
|
||||
{NSAPI_IPv4, {8, 8, 8, 8}}, // Google
|
||||
{NSAPI_IPv4, {209, 244, 0, 3}}, // Level 3
|
||||
{NSAPI_IPv4, {84, 200, 69, 80}}, // DNS.WATCH
|
||||
|
|
@ -40,6 +87,14 @@ nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
|
|||
0,0, 0,0, 0x1c,0x04, 0xb1,0x2f}},
|
||||
};
|
||||
|
||||
static DNS_CACHE *dns_cache[DNS_CACHE_SIZE];
|
||||
static uint16_t dns_message_id = 0;
|
||||
static int dns_unique_id = 0;
|
||||
static DNS_QUERY *dns_query_queue[DNS_QUERY_QUEUE_SIZE];
|
||||
static rtos::Mutex dns_cache_mutex;
|
||||
static nsapi_dns_call_t dns_call = nsapi_dns_call_default;
|
||||
static nsapi_dns_call_in_t dns_call_in = nsapi_dns_call_in_default;
|
||||
|
||||
// DNS server configuration
|
||||
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr)
|
||||
{
|
||||
|
|
@ -83,11 +138,23 @@ static uint16_t dns_scan_word(const uint8_t **p)
|
|||
return (a << 8) | b;
|
||||
}
|
||||
|
||||
|
||||
static void dns_append_question(uint8_t **p, const char *host, nsapi_version_t version)
|
||||
static uint32_t dns_scan_word32(const uint8_t **p)
|
||||
{
|
||||
uint32_t value = dns_scan_byte(p) << 24;
|
||||
value |= dns_scan_byte(p) << 16;
|
||||
value |= dns_scan_byte(p) << 8;
|
||||
value |= dns_scan_byte(p);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int dns_append_question(uint8_t *ptr, uint16_t id, const char *host, nsapi_version_t version)
|
||||
{
|
||||
uint8_t *s_ptr = ptr;
|
||||
uint8_t **p = &ptr;
|
||||
|
||||
// fill the header
|
||||
dns_append_word(p, 1); // id = 1
|
||||
dns_append_word(p, id); // id = 1
|
||||
dns_append_word(p, 0x0100); // flags = recursion required
|
||||
dns_append_word(p, 1); // qdcount = 1
|
||||
dns_append_word(p, 0); // ancount = 0
|
||||
|
|
@ -110,10 +177,14 @@ static void dns_append_question(uint8_t **p, const char *host, nsapi_version_t v
|
|||
dns_append_word(p, RR_AAAA); // qtype = ipv6
|
||||
}
|
||||
dns_append_word(p, CLASS_IN);
|
||||
|
||||
return *p - s_ptr;
|
||||
}
|
||||
|
||||
static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned addr_count)
|
||||
static int dns_scan_response(const uint8_t *ptr, uint16_t exp_id, uint32_t *ttl, nsapi_addr_t *addr, unsigned addr_count)
|
||||
{
|
||||
const uint8_t **p = &ptr;
|
||||
|
||||
// scan header
|
||||
uint16_t id = dns_scan_word(p);
|
||||
uint16_t flags = dns_scan_word(p);
|
||||
|
|
@ -127,7 +198,7 @@ static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned add
|
|||
dns_scan_word(p); // arcount
|
||||
|
||||
// verify header is response to query
|
||||
if (!(id == 1 && qr && opcode == 0 && rcode == 0)) {
|
||||
if (!(id == exp_id && qr && opcode == 0 && rcode == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -162,10 +233,18 @@ static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned add
|
|||
*p += len;
|
||||
}
|
||||
|
||||
uint16_t rtype = dns_scan_word(p); // rtype
|
||||
uint16_t rclass = dns_scan_word(p); // rclass
|
||||
*p += 4; // ttl
|
||||
uint16_t rdlength = dns_scan_word(p); // rdlength
|
||||
uint16_t rtype = dns_scan_word(p); // rtype
|
||||
uint16_t rclass = dns_scan_word(p); // rclass
|
||||
uint32_t ttl_val = dns_scan_word32(p); // ttl
|
||||
uint16_t rdlength = dns_scan_word(p); // rdlength
|
||||
|
||||
if (i == 0) {
|
||||
// Is interested only on first address that is stored to cache
|
||||
if (ttl_val > DNS_MAX_TTL) {
|
||||
ttl_val = DNS_MAX_TTL;
|
||||
}
|
||||
*ttl = ttl_val;
|
||||
}
|
||||
|
||||
if (rtype == RR_A && rclass == CLASS_IN && rdlength == NSAPI_IPv4_BYTES) {
|
||||
// accept A record
|
||||
|
|
@ -194,6 +273,109 @@ static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned add
|
|||
return count;
|
||||
}
|
||||
|
||||
static void nsapi_dns_cache_add(const char *host, SocketAddress *address, uint32_t ttl)
|
||||
{
|
||||
// RFC 1034: if TTL is zero, entry is not added to cache
|
||||
if (!ttl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks if already cached
|
||||
if (nsapi_dns_cache_find(host, address->get_ip_version(), NULL) == NSAPI_ERROR_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
dns_cache_mutex.lock();
|
||||
|
||||
int index = -1;
|
||||
uint64_t accessed = -1;
|
||||
|
||||
// Finds free or last accessed entry
|
||||
for (int i = 0; i < DNS_CACHE_SIZE; i++) {
|
||||
if (!dns_cache[i]) {
|
||||
index = i;
|
||||
break;
|
||||
} else if (dns_cache[i]->accessed <= accessed) {
|
||||
accessed = dns_cache[i]->accessed;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocates in case entry is free, otherwise reuses
|
||||
if (!dns_cache[index]) {
|
||||
dns_cache[index] = new DNS_CACHE;
|
||||
}
|
||||
|
||||
if (dns_cache[index]) {
|
||||
dns_cache[index]->address = *address;
|
||||
strncpy(dns_cache[index]->host, host, 127);
|
||||
uint64_t ms_count = rtos::Kernel::get_ms_count();
|
||||
dns_cache[index]->expires = ms_count + ttl * 1000;
|
||||
dns_cache[index]->accessed = ms_count;
|
||||
}
|
||||
|
||||
dns_cache_mutex.unlock();
|
||||
}
|
||||
|
||||
static nsapi_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, SocketAddress *address)
|
||||
{
|
||||
nsapi_error_t ret_val = NSAPI_ERROR_NO_ADDRESS;
|
||||
|
||||
dns_cache_mutex.lock();
|
||||
|
||||
for (int i = 0; i < DNS_CACHE_SIZE; i++) {
|
||||
if (dns_cache[i]) {
|
||||
uint64_t ms_count = rtos::Kernel::get_ms_count();
|
||||
// Checks all entries for expired entries
|
||||
if (ms_count > dns_cache[i]->expires) {
|
||||
delete dns_cache[i];
|
||||
dns_cache[i] = NULL;
|
||||
} else if (((version == NSAPI_UNSPEC) || (version == dns_cache[i]->address.get_ip_version())) &&
|
||||
(strncmp(dns_cache[i]->host, host, 127) == 0)) {
|
||||
if (address) {
|
||||
*address = dns_cache[i]->address;
|
||||
}
|
||||
dns_cache[i]->accessed = ms_count;
|
||||
ret_val = NSAPI_ERROR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dns_cache_mutex.unlock();
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, int *index, SocketAddress *dns_addr)
|
||||
{
|
||||
bool dns_addr_set = false;
|
||||
|
||||
if (*index >= DNS_SERVERS_SIZE + DNS_STACK_SERVERS_NUM) {
|
||||
return NSAPI_ERROR_NO_ADDRESS;
|
||||
}
|
||||
|
||||
if (*index < DNS_STACK_SERVERS_NUM) {
|
||||
nsapi_error_t ret = stack->get_dns_server(*index, dns_addr);
|
||||
if (ret < 0) {
|
||||
*index = DNS_STACK_SERVERS_NUM;
|
||||
} else {
|
||||
dns_addr_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dns_addr_set) {
|
||||
dns_addr->set_addr(dns_servers[*index - DNS_STACK_SERVERS_NUM]);
|
||||
}
|
||||
|
||||
dns_addr->set_port(53);
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
// core query function
|
||||
static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host,
|
||||
nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version)
|
||||
|
|
@ -204,6 +386,13 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
|
|||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
// check cache
|
||||
SocketAddress address;
|
||||
if (nsapi_dns_cache_find(host, version, &address) == NSAPI_ERROR_OK) {
|
||||
*addr = address.get_addr();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// create a udp socket
|
||||
UDPSocket socket;
|
||||
int err = socket.open(stack);
|
||||
|
|
@ -221,21 +410,41 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
|
|||
|
||||
nsapi_size_or_error_t result = NSAPI_ERROR_DNS_FAILURE;
|
||||
|
||||
// check against each dns server
|
||||
for (unsigned i = 0; i < DNS_SERVERS_SIZE; i++) {
|
||||
// send the question
|
||||
uint8_t *question = packet;
|
||||
dns_append_question(&question, host, version);
|
||||
bool retry = false;
|
||||
|
||||
err = socket.sendto(SocketAddress(dns_servers[i], 53), packet, question - packet);
|
||||
int index = 0;
|
||||
|
||||
// check against each dns server
|
||||
while (true) {
|
||||
SocketAddress dns_addr;
|
||||
err = nsapi_dns_get_server_addr(stack, &index, &dns_addr);
|
||||
if (err != NSAPI_ERROR_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
// send the question
|
||||
int len = dns_append_question(packet, 1, host, version);
|
||||
|
||||
err = socket.sendto(dns_addr, packet, len);
|
||||
// send may fail for various reasons, including wrong address type - move on
|
||||
if (err < 0) {
|
||||
// goes to next dns server
|
||||
retry = false;
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// recv the response
|
||||
err = socket.recvfrom(NULL, packet, DNS_BUFFER_SIZE);
|
||||
if (err == NSAPI_ERROR_WOULD_BLOCK) {
|
||||
if (!retry) {
|
||||
// retries once
|
||||
retry = true;
|
||||
} else {
|
||||
// goes to next dns server
|
||||
retry = false;
|
||||
index++;
|
||||
}
|
||||
continue;
|
||||
} else if (err < 0) {
|
||||
result = err;
|
||||
|
|
@ -243,8 +452,13 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
|
|||
}
|
||||
|
||||
const uint8_t *response = packet;
|
||||
int count = dns_scan_response(&response, addr, addr_count);
|
||||
uint32_t ttl;
|
||||
int count = dns_scan_response(response, 1, &ttl, addr, addr_count);
|
||||
if (count > 0) {
|
||||
// Adds address to cache
|
||||
SocketAddress address(*addr);
|
||||
nsapi_dns_cache_add(host, &address, ttl);
|
||||
|
||||
result = count;
|
||||
}
|
||||
|
||||
|
|
@ -305,3 +519,337 @@ nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
|
|||
address->set_addr(addr);
|
||||
return (nsapi_error_t)((result > 0) ? 0 : result);
|
||||
}
|
||||
|
||||
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, void *data, nsapi_version_t version)
|
||||
{
|
||||
nsapi_size_or_error_t result = nsapi_dns_query_multiple_async(stack, host, callback, data, 1, version);
|
||||
return (nsapi_error_t)((result > 0) ? 0 : result);
|
||||
}
|
||||
|
||||
static nsapi_error_t nsapi_dns_call_default(mbed::Callback<void()> func)
|
||||
{
|
||||
events::EventQueue *event_queue = mbed::mbed_event_queue();
|
||||
if (!event_queue) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
if (event_queue->call(func) == 0) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
return NSAPI_ERROR_OK ;
|
||||
}
|
||||
|
||||
static nsapi_error_t nsapi_dns_call_in_default(int delay, mbed::Callback<void()> func)
|
||||
{
|
||||
events::EventQueue *event_queue = mbed::mbed_event_queue();
|
||||
if (!event_queue) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
if (event_queue->call_in(delay, func) == 0) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
return NSAPI_ERROR_OK ;
|
||||
}
|
||||
|
||||
void nsapi_dns_call_set(nsapi_dns_call_t callback)
|
||||
{
|
||||
dns_call = callback;
|
||||
}
|
||||
|
||||
void nsapi_dns_call_in_set(nsapi_dns_call_in_t callback)
|
||||
{
|
||||
dns_call_in = callback;
|
||||
}
|
||||
|
||||
static nsapi_error_t nsapi_dns_call(NetworkStack *stack, mbed::Callback<void()> func)
|
||||
{
|
||||
if (stack->onboardNetworkStack()) {
|
||||
OnboardNetworkStack *onboard_stack = reinterpret_cast<OnboardNetworkStack *>(stack);
|
||||
return onboard_stack->call(func);
|
||||
} else {
|
||||
dns_call(func);
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
static nsapi_error_t nsapi_dns_call_in(NetworkStack *stack, int delay, mbed::Callback<void()> func)
|
||||
{
|
||||
if (stack->onboardNetworkStack()) {
|
||||
OnboardNetworkStack *onboard_stack = reinterpret_cast<OnboardNetworkStack *>(stack);
|
||||
return onboard_stack->call_in(delay, func);
|
||||
} else {
|
||||
dns_call_in(delay, func);
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, void *data, nsapi_size_t addr_count, nsapi_version_t version)
|
||||
{
|
||||
if (!stack) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
// check for valid host name
|
||||
int host_len = host ? strlen(host) : 0;
|
||||
if (host_len > 128 || host_len == 0) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
DNS_QUERY *query = new DNS_QUERY;
|
||||
|
||||
if (!query) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
query->unique_id = 0;
|
||||
strcpy(query->host, host);
|
||||
query->callback = callback;
|
||||
query->cb_data = data;
|
||||
query->stack = stack;
|
||||
query->addr_count = addr_count;
|
||||
query->version = version;
|
||||
query->socket = NULL;
|
||||
query->dns_server = 0;
|
||||
query->retries = 2;
|
||||
query->dns_message_id = -1;
|
||||
|
||||
if (nsapi_dns_call(stack, mbed::callback(nsapi_dns_query_async_create, query)) != NSAPI_ERROR_OK) {
|
||||
delete query;
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_IN_PROGRESS ;
|
||||
}
|
||||
|
||||
static void nsapi_dns_query_async_create(DNS_QUERY *query)
|
||||
{
|
||||
SocketAddress address;
|
||||
if (nsapi_dns_cache_find(query->host, query->version, &address) == NSAPI_ERROR_OK) {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_OK, &address);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = -1;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (dns_query_queue[i]) {
|
||||
if (dns_query_queue[i]->stack == query->stack) {
|
||||
query->socket = dns_query_queue[i]->socket;
|
||||
}
|
||||
} else if (index < 0) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
UDPSocket *socket;
|
||||
|
||||
if (query->socket) {
|
||||
socket = query->socket;
|
||||
} else {
|
||||
socket = new UDPSocket;
|
||||
if (!socket) {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
int err = socket->open(query->stack);
|
||||
if (err) {
|
||||
delete socket;
|
||||
nsapi_dns_query_async_resp(query, err, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
socket->set_timeout(0);
|
||||
socket->sigio(mbed::callback(nsapi_dns_query_async_socket_callback, query->stack));
|
||||
|
||||
query->socket = socket;
|
||||
}
|
||||
|
||||
query->unique_id = dns_unique_id++;
|
||||
|
||||
dns_query_queue[index] = query;
|
||||
|
||||
nsapi_dns_query_async_send(reinterpret_cast<void *>(query->unique_id));
|
||||
}
|
||||
|
||||
|
||||
static void nsapi_dns_query_async_delete(DNS_QUERY *query)
|
||||
{
|
||||
int index = -1;
|
||||
bool close_socket = true;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (dns_query_queue[i]) {
|
||||
if (dns_query_queue[i] == query) {
|
||||
index = i;
|
||||
} else if (dns_query_queue[i]->stack == query->stack) {
|
||||
close_socket = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (close_socket) {
|
||||
query->socket->close();
|
||||
delete query->socket;
|
||||
}
|
||||
|
||||
dns_query_queue[index] = NULL;
|
||||
delete query;
|
||||
}
|
||||
|
||||
static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address)
|
||||
{
|
||||
query->callback(status, address, query->cb_data);
|
||||
nsapi_dns_query_async_delete(query);
|
||||
}
|
||||
|
||||
static void nsapi_dns_query_async_send(void *ptr)
|
||||
{
|
||||
int unique_id = reinterpret_cast<int>(ptr);
|
||||
|
||||
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];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (query->retries) {
|
||||
query->retries--;
|
||||
} else {
|
||||
query->dns_server++;
|
||||
query->retries = 1;
|
||||
}
|
||||
|
||||
query->dns_message_id = dns_message_id++;
|
||||
|
||||
// create network packet
|
||||
uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE);
|
||||
if (!packet) {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_NO_MEMORY, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// send the question
|
||||
int len = dns_append_question(packet, query->dns_message_id, query->host, query->version);
|
||||
|
||||
while (true) {
|
||||
SocketAddress dns_addr;
|
||||
nsapi_size_or_error_t err = nsapi_dns_get_server_addr(query->stack, &(query->dns_server), &dns_addr);
|
||||
if (err != NSAPI_ERROR_OK) {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_DNS_FAILURE, NULL);
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
err = query->socket->sendto(dns_addr, packet, len);
|
||||
|
||||
if (err < 0) {
|
||||
query->dns_server++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(packet);
|
||||
|
||||
if (nsapi_dns_call_in(query->stack, DNS_TIMEOUT,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void nsapi_dns_query_async_socket_callback(NetworkStack *stack)
|
||||
{
|
||||
nsapi_dns_call(stack, mbed::callback(nsapi_dns_query_async_socket_callback_handle, stack));
|
||||
}
|
||||
|
||||
static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack)
|
||||
{
|
||||
UDPSocket *socket = NULL;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (dns_query_queue[i] && dns_query_queue[i]->stack == stack) {
|
||||
socket = dns_query_queue[i]->socket;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (socket) {
|
||||
// create network packet
|
||||
uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE);
|
||||
if (!packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
// recv the response
|
||||
nsapi_size_or_error_t size = socket->recvfrom(NULL, packet, DNS_BUFFER_SIZE);
|
||||
|
||||
if (size < DNS_RESPONSE_MIN_SIZE) {
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
// gets id from response to associate with correct query
|
||||
uint16_t id = (*packet << 8) | *(packet + 1);
|
||||
|
||||
DNS_QUERY *query = NULL;
|
||||
|
||||
for (int i = 0; i < DNS_QUERY_QUEUE_SIZE; i++) {
|
||||
if (dns_query_queue[i] && dns_query_queue[i]->dns_message_id == id) {
|
||||
query = dns_query_queue[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
nsapi_addr_t *addrs = new nsapi_addr_t[query->addr_count];
|
||||
|
||||
uint32_t ttl;
|
||||
int count = dns_scan_response((const uint8_t *) packet, id, &ttl, addrs, query->addr_count);
|
||||
|
||||
free(packet);
|
||||
|
||||
if (count > 0) {
|
||||
SocketAddress *addresses = new SocketAddress[count];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
addresses[i].set_addr(addrs[i]);
|
||||
}
|
||||
|
||||
// Adds address to cache
|
||||
nsapi_dns_cache_add(query->host, addresses, ttl);
|
||||
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_OK, addresses);
|
||||
|
||||
delete[] addresses;
|
||||
} else {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_DNS_FAILURE, NULL);
|
||||
}
|
||||
|
||||
delete[] addrs;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,19 @@ nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
|
|||
SocketAddress *addr, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for an IP address of a given hostname
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
* @param host Hostname to resolve
|
||||
* @param callback Callback that is called for result*
|
||||
* @param data Caller defined data returned in callback
|
||||
* @param version IP version to resolve (defaults to NSAPI_IPv4)
|
||||
* @return 0 on success, negative error code on failure
|
||||
* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
|
||||
*/
|
||||
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, void *data, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for an IP address of a given hostname (asynchronous)
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
* @param host Hostname to resolve
|
||||
|
|
@ -117,6 +130,20 @@ nsapi_error_t nsapi_dns_query(S *stack, const char *host,
|
|||
nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host,
|
||||
SocketAddress *addr, nsapi_size_t addr_count, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for an IP address of a given hostname (asynchronous)
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
* @param host Hostname to resolve
|
||||
* @param callback Callback that is called for result
|
||||
* @param data Caller defined data returned in callback
|
||||
* @param addr_count Number of addresses allocated in the array
|
||||
* @param version IP version to resolve (defaults to NSAPI_IPv4)
|
||||
* @return 0 on success, negative error code on failure
|
||||
* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
|
||||
*/
|
||||
nsapi_size_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, void *data, nsapi_size_t addr_count, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for multiple IP address of a given hostname
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
|
|
@ -130,6 +157,7 @@ nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *
|
|||
extern "C" nsapi_size_or_error_t nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host,
|
||||
nsapi_addr_t *addr, nsapi_size_t addr_count, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
|
||||
/** Query a domain name server for multiple IP address of a given hostname
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
|
|
|
|||
Loading…
Reference in New Issue