Skip to content

Instantly share code, notes, and snippets.

@dimaqq
Created December 4, 2017 08:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dimaqq/397682b68cdc0992a5d314c53e8ecf86 to your computer and use it in GitHub Desktop.
Save dimaqq/397682b68cdc0992a5d314c53e8ecf86 to your computer and use it in GitHub Desktop.
diff --git a/Makefile.inc b/Makefile.inc
index 6a68fce..acfd282 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -16,6 +16,7 @@ CSOURCES = ares__close_sockets.c \
ares_getnameinfo.c \
ares_getsock.c \
ares_init.c \
+ ares_reinit.c \
ares_library_init.c \
ares_llist.c \
ares_mkquery.c \
diff --git a/ares.h b/ares.h
index 9456a14..3436237 100644
--- a/ares.h
+++ b/ares.h
@@ -306,6 +306,8 @@ CARES_EXTERN int ares_save_options(ares_channel channel,
CARES_EXTERN void ares_destroy_options(struct ares_options *options);
+CARES_EXTERN int ares_reinit(ares_channel channel);
+
CARES_EXTERN int ares_dup(ares_channel *dest,
ares_channel src);
diff --git a/ares_gethostbyaddr.c b/ares_gethostbyaddr.c
index 0de2cf2..b2284bb 100644
--- a/ares_gethostbyaddr.c
+++ b/ares_gethostbyaddr.c
@@ -72,6 +72,8 @@ void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
{
struct addr_query *aquery;
+ ares__maybe_reinit(channel);
+
if (family != AF_INET && family != AF_INET6)
{
callback(arg, ARES_ENOTIMP, 0, NULL);
diff --git a/ares_gethostbyname.c b/ares_gethostbyname.c
index 4469ffe..2c3578a 100644
--- a/ares_gethostbyname.c
+++ b/ares_gethostbyname.c
@@ -88,6 +88,8 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
{
struct host_query *hquery;
+ ares__maybe_reinit(channel);
+
/* Right now we only know how to look up Internet addresses - and unspec
means try both basically. */
switch (family) {
diff --git a/ares_init.c b/ares_init.c
index d2f4a72..fe31ce8 100644
--- a/ares_init.c
+++ b/ares_init.c
@@ -176,6 +176,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
channel->last_server = 0;
channel->last_timeout_processed = (time_t)now.tv_sec;
+ channel->last_reinit = (time_t)now.tv_sec;
memset(&channel->local_dev_name, 0, sizeof(channel->local_dev_name));
channel->local_ip4 = 0;
diff --git a/ares_private.h b/ares_private.h
index bf21abd..6c795bf 100644
--- a/ares_private.h
+++ b/ares_private.h
@@ -300,6 +300,8 @@ struct ares_channeldata {
ares_sock_create_callback sock_create_cb;
void *sock_create_cb_data;
+
+ time_t last_reinit;
};
/* return true if now is exactly check time or later */
@@ -327,6 +329,7 @@ int ares__expand_name_for_response(const unsigned char *encoded,
char **s, long *enclen);
void ares__init_servers_state(ares_channel channel);
void ares__destroy_servers_state(ares_channel channel);
+int ares__maybe_reinit(ares_channel channel);
#if 0 /* Not used */
long ares__tvdiff(struct timeval t1, struct timeval t2);
#endif
diff --git a/ares_reinit.3 b/ares_reinit.3
index e69de29..775b2df 100644
--- a/ares_reinit.3
+++ b/ares_reinit.3
@@ -0,0 +1,23 @@
+.TH ARES_REINIT 3 "11 February 2011"
+.SH NAME
+ares_reinit \- Reinitialize a resolver channel
+.SH SYNOPSIS
+.nf
+.B #include <ares.h>
+.PP
+.B int ares_reinit(ares_channel \fIchannel\fP)
+.fi
+.SH DESCRIPTION
+The \fBares_reinit\fP function checks if configuration files have changed and
+if so reads configuration files to get default domain name, search order and
+name server address(es).
+.PP
+The \fBares_reinit\fP function may cancel all lookups/requests made on the the
+name service channel identified by \fIchannel\fP.
+.SH SEE ALSO
+.BR ares_init (3)
+.BR ares_cancel (3)
+.SH NOTES
+This function was added in c-ares 1.7.5
+.SH AUTHOR
+Dima Tisnek
diff --git a/ares_reinit.c b/ares_reinit.c
index e69de29..7bf2d24 100644
--- a/ares_reinit.c
+++ b/ares_reinit.c
@@ -0,0 +1,123 @@
+#include "ares_setup.h"
+#include "ares.h"
+#include "ares_private.h"
+#include "bitncmp.h"
+
+static int apatterncmp(struct apattern* a, struct apattern* b);
+static int addrcmp(struct ares_addr* a, struct ares_addr* b);
+
+int ares__maybe_reinit(ares_channel channel)
+{
+ struct timeval now;
+ now = ares__tvnow();
+ /* only 1-second granularity here
+ * could use timeval in channel for better precision */
+ if (now.tv_sec > channel->last_reinit + channel->timeout/1000)
+ return ares_reinit(channel);
+}
+
+int apatterncmp(struct apattern* a, struct apattern* b)
+{
+ if (a->type != b->type) return a->type - b->type;
+ if (a->family != b-> family) return a->family - b->family;
+ switch (a->type) {
+ case PATTERN_MASK:
+ /* masks only valid for ipv4 */
+ return memcmp(&a->addrV4, &b->addrV4, sizeof(a->addrV4));
+ case PATTERN_CIDR:
+ if (a->mask.bits != b->mask.bits) return a->mask.bits - b->mask.bits;
+ return ares_bitncmp(&a->addr, &b->addr, a->mask.bits);
+ }
+ return 0;
+}
+
+int addrcmp(struct ares_addr* a, struct ares_addr* b)
+{
+ if (a->family != b->family) return a->family - b->family;
+ switch (a->family) {
+ case AF_INET: return memcmp(&a->addrV4, &b->addrV4, sizeof(a->addrV4));
+ case AF_INET6: return memcmp(&a->addrV6, &b->addrV6, sizeof(a->addrV6));
+ }
+ return 0;
+}
+
+int ares_reinit(ares_channel channel)
+{
+ ares_channel another=0;
+ int i, rv, diff=0;
+ int nservers, nsort, ndomains;
+ char **domains;
+ struct apattern *sortlist;
+ char *lookups;
+ struct server_state *servers;
+ struct timeval now;
+ rv = ares_init(&another);
+ if (rv != ARES_SUCCESS) return rv;
+
+ if (channel->ndots != another->ndots) diff = 1;
+ if (channel->timeout != another->timeout) diff = 1;
+ if (channel->tries != another->tries) diff = 1;
+ if (channel->rotate != another->rotate) diff = 1;
+
+ if (channel->nservers != another->nservers) diff = 1;
+ for (i=0; !diff && i < channel->nservers; i++)
+ if (addrcmp(&channel->servers[i].addr, &another->servers[i].addr))
+ diff = 1;
+
+ if (channel->nsort != another->nsort) diff = 1;
+ for (i=0; !diff && i < channel->nsort; i++)
+ if (apatterncmp(&channel->sortlist[i], &another->sortlist[i]))
+ diff = 1;
+
+ if (channel->ndomains != another->ndomains) diff = 1;
+ for (i=0; !diff && i < channel->ndomains; i++)
+ if (strcmp(channel->domains[i], another->domains[i]))
+ diff = 1;
+
+ if (!!channel->lookups != !!another->lookups) diff = 1;
+ if (channel->lookups && strcmp(channel->lookups, another->lookups)) diff = 1;
+
+ if (diff)
+ {
+ ares_cancel(channel);
+
+ channel->ndots = another->ndots;
+ channel->timeout = another->timeout;
+ channel->tries = another->tries;
+ channel->rotate = another->rotate;
+ channel->last_server = 0;
+
+ nservers = channel->nservers;
+ servers = channel->servers;
+ channel->nservers = another->nservers;
+ channel->servers = another->servers;
+ another->nservers = nservers;
+ another->servers = servers;
+ for (i=0; i<channel->nservers; i++) channel->servers[i].channel = channel;
+ for (i=0; i<another->nservers; i++) another->servers[i].channel = another;
+
+ nsort = channel->nsort;
+ sortlist = channel->sortlist;
+ channel->nsort = another->nsort;
+ channel->sortlist = another->sortlist;
+ another->nsort = nsort;
+ another->sortlist = sortlist;
+
+ ndomains = channel->ndomains;
+ domains = channel->domains;
+ channel->ndomains = another->ndomains;
+ channel->domains = another->domains;
+ another->ndomains = ndomains;
+ another->domains = domains;
+
+ lookups = channel->lookups;
+ channel->lookups = another->lookups;
+ another->lookups = lookups;
+ }
+
+ now = ares__tvnow();
+ channel->last_reinit = (time_t)now.tv_sec;
+
+ ares_destroy(another);
+ return rv;
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment