diff --git a/include/nuttx/net/dns.h b/include/nuttx/net/dns.h index c0a87223d29..a04f7289478 100644 --- a/include/nuttx/net/dns.h +++ b/include/nuttx/net/dns.h @@ -227,6 +227,26 @@ int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen); int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg); +/**************************************************************************** + * Name: dns_register_notify + * + * Description: + * This function is called in order to receive the nameserver change. + * + ****************************************************************************/ + +int dns_register_notify(dns_callback_t callback, FAR void *arg); + +/**************************************************************************** + * Name: dns_unregister_notify + * + * Description: + * This function is called in order to unsubscribe the notification. + * + ****************************************************************************/ + +int dns_unregister_notify(dns_callback_t callback, FAR void *arg); + #undef EXTERN #if defined(__cplusplus) } diff --git a/libs/libc/netdb/Make.defs b/libs/libc/netdb/Make.defs index e29aa1eac31..268596d1f6f 100644 --- a/libs/libc/netdb/Make.defs +++ b/libs/libc/netdb/Make.defs @@ -51,7 +51,7 @@ endif ifeq ($(CONFIG_NETDB_DNSCLIENT),y) CSRCS += lib_dnsinit.c lib_dnsbind.c lib_dnsquery.c lib_dnsaddserver.c -CSRCS += lib_dnsforeach.c +CSRCS += lib_dnsforeach.c lib_dnsnotify.c ifneq ($(CONFIG_NETDB_DNSCLIENT_ENTRIES),0) CSRCS += lib_dnscache.c diff --git a/libs/libc/netdb/lib_dns.h b/libs/libc/netdb/lib_dns.h index 6329dba9d09..58e9ddf165c 100644 --- a/libs/libc/netdb/lib_dns.h +++ b/libs/libc/netdb/lib_dns.h @@ -248,6 +248,12 @@ int dns_find_answer(FAR const char *hostname, FAR union dns_addr_u *addr, FAR int *naddr); #endif +/**************************************************************************** + * Name: dns_notify_nameserver + ****************************************************************************/ + +void dns_notify_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen); + #undef EXTERN #if defined(__cplusplus) } diff --git a/libs/libc/netdb/lib_dnsaddserver.c b/libs/libc/netdb/lib_dnsaddserver.c index 92520eb9e7d..e430d88a526 100644 --- a/libs/libc/netdb/lib_dnsaddserver.c +++ b/libs/libc/netdb/lib_dnsaddserver.c @@ -198,6 +198,7 @@ int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) goto errout; } + dns_notify_nameserver(addr, addrlen); ret = OK; errout: @@ -267,6 +268,7 @@ int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) /* We now have a valid DNS address */ g_dns_address = true; + dns_notify_nameserver(addr, addrlen); return OK; } diff --git a/libs/libc/netdb/lib_dnsinit.c b/libs/libc/netdb/lib_dnsinit.c index 2b15ec15c24..4ff968931f9 100644 --- a/libs/libc/netdb/lib_dnsinit.c +++ b/libs/libc/netdb/lib_dnsinit.c @@ -54,8 +54,9 @@ * Private Data ****************************************************************************/ -static sem_t g_dns_sem; /* Protects g_seqno and DNS cache */ -static bool g_dns_initialized; /* DNS data structures initialized */ +/* Protects g_seqno, DNS cache and notify */ + +static sem_t g_dns_sem = SEM_INITIALIZER(1); /**************************************************************************** * Public Data @@ -92,14 +93,6 @@ static const uint16_t g_ipv6_hostaddr[8] = bool dns_initialize(void) { - /* Have DNS data structures been initialized? */ - - if (!g_dns_initialized) - { - (void)nxsem_init(&g_dns_sem, 0, 1); - g_dns_initialized = true; - } - #ifndef CONFIG_NETDB_RESOLVCONF /* Has the DNS server IP address been assigned? */ diff --git a/libs/libc/netdb/lib_dnsnotify.c b/libs/libc/netdb/lib_dnsnotify.c new file mode 100644 index 00000000000..7a897f18a4b --- /dev/null +++ b/libs/libc/netdb/lib_dnsnotify.c @@ -0,0 +1,150 @@ +/**************************************************************************** + * libs/libc/netdb/lib_dnsnotify.c + * + * Copyright (C) 2019 Pinecone Inc. All rights reserved. + * Author: Xiang Xiao + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "libc.h" +#include "netdb/lib_dns.h" + +#ifdef CONFIG_NETDB_DNSCLIENT + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +struct dns_notify_s +{ + struct dq_entry_s entry; /* Supports a doubly linked list */ + dns_callback_t callback; + FAR void *arg; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static dq_queue_t g_dns_notify; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dns_register_notify + * + * Description: + * This function is called in order to receive the nameserver change. + * + ****************************************************************************/ + +int dns_register_notify(dns_callback_t callback, FAR void *arg) +{ + FAR struct dns_notify_s *notify; + + notify = lib_malloc(sizeof(*notify)); + if (notify == NULL) + { + return -ENOMEM; + } + + notify->callback = callback; + notify->arg = arg; + + dns_semtake(); + dq_addlast(¬ify->entry, &g_dns_notify); + dns_semgive(); + + /* Notify the existed nameserver */ + + dns_foreach_nameserver(callback, arg); + return OK; +} + +/**************************************************************************** + * Name: dns_unregister_notify + * + * Description: + * This function is called in order to unsubscribe the notification. + * + ****************************************************************************/ + +int dns_unregister_notify(dns_callback_t callback, FAR void *arg) +{ + FAR dq_entry_t *entry; + + dns_semtake(); + for (entry = dq_peek(&g_dns_notify); entry; entry = dq_next(entry)) + { + FAR struct dns_notify_s *notify = (FAR struct dns_notify_s *)entry; + + if (notify->callback == callback && notify->arg == arg) + { + dq_rem(¬ify->entry, &g_dns_notify); + dns_semgive(); + lib_free(notify); + return OK; + } + } + + dns_semgive(); + return -EINVAL; +} + +/**************************************************************************** + * Name: dns_notify_nameserver + ****************************************************************************/ + +void dns_notify_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) +{ + FAR dq_entry_t *entry; + + dns_semtake(); + for (entry = dq_peek(&g_dns_notify); entry; entry = dq_next(entry)) + { + FAR struct dns_notify_s *notify = (FAR struct dns_notify_s *)entry; + notify->callback(notify->arg, (FAR struct sockaddr *)addr, addrlen); + } + + dns_semgive(); +} + +#endif /* CONFIG_NETDB_DNSCLIENT */