Created
December 4, 2017 08:52
-
-
Save dimaqq/397682b68cdc0992a5d314c53e8ecf86 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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