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;
 | 
			
		||||
 | 
			
		||||
#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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } 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;
 | 
			
		||||
    }
 | 
			
		||||
    int dns_entries = 0;
 | 
			
		||||
 | 
			
		||||
    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, &lwip_addr);
 | 
			
		||||
                convert_lwip_addr_to_mbed(&addr, ip_addr);
 | 
			
		||||
                address->set_addr(addr);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
                return NSAPI_ERROR_OK;
 | 
			
		||||
            }
 | 
			
		||||
            dns_entries++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    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_addr_t addr = address.get_addr();
 | 
			
		||||
    ip_addr_t ip_addr;
 | 
			
		||||
    if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
 | 
			
		||||
        return NSAPI_ERROR_PARAMETER;
 | 
			
		||||
nsapi_error_t LWIP::call(mbed::Callback<void()> func)
 | 
			
		||||
{
 | 
			
		||||
    return call_in(0, func);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    dns_setserver(0, &ip_addr);
 | 
			
		||||
    return 0;
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cb->delay = delay;
 | 
			
		||||
    cb->callback = func;
 | 
			
		||||
 | 
			
		||||
    if (tcpip_callback_with_block(LWIP::tcpip_thread_callback, cb, 1) != ERR_OK) {
 | 
			
		||||
        return NSAPI_ERROR_NO_MEMORY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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,12 +102,19 @@ 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 */
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create a new netconn (of a specific type) that has a callback function.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -164,9 +235,17 @@ static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned add
 | 
			
		|||
 | 
			
		||||
        uint16_t rtype    = dns_scan_word(p);    // rtype
 | 
			
		||||
        uint16_t rclass   = dns_scan_word(p);    // rclass
 | 
			
		||||
        *p += 4;                              // ttl
 | 
			
		||||
        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
 | 
			
		||||
            addr->version = NSAPI_IPv4;
 | 
			
		||||
| 
						 | 
				
			
			@ -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