From 79d59ec97bab50b6227a10b52be868959cafe218 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 30 May 2007 20:49:14 +0000 Subject: [PATCH] Brad House added ares_save_options() and ares_destroy_options() that can be used to keep options for later re-usal when ares_init_options() is used. --- ares/CHANGES | 19 +++++++++ ares/ares.h | 7 ++++ ares/ares_destroy.c | 13 ++++++ ares/ares_init.c | 96 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 133 insertions(+), 2 deletions(-) diff --git a/ares/CHANGES b/ares/CHANGES index 3f607b880..9f0a04422 100644 --- a/ares/CHANGES +++ b/ares/CHANGES @@ -2,6 +2,25 @@ * May 30 2007 +- Brad House added ares_save_options() and ares_destroy_options() that can be + used to keep options for later re-usal when ares_init_options() is used. + + Problem: Calling ares_init() for each lookup can be unnecessarily resource + intensive. On windows, it must LoadLibrary() or search the registry + on each call to ares_init(). On unix, it must read and parse + multiple files to obtain the necessary configuration information. In + a single-threaded environment, it would make sense to only + ares_init() once, but in a heavily multi-threaded environment, it is + undesirable to ares_init() and ares_destroy() for each thread created + and track that. + + Solution: Create ares_save_options() and ares_destroy_options() functions to + retrieve and free options obtained from an initialized channel. The + options populated can be used to pass back into ares_init_options(), + it should populate all needed fields and not retrieve any information + from the system. Probably wise to destroy the cache every minute or + so to prevent the data from becoming stale. + - Daniel S added ares_process_fd() to allow applications to ask for processing on specific sockets and thus avoiding select() and associated functions/macros. This function will be used by upcoming libcurl releases diff --git a/ares/ares.h b/ares/ares.h index 73fc3e6c3..6b942951f 100644 --- a/ares/ares.h +++ b/ares/ares.h @@ -94,6 +94,7 @@ extern "C" { #define ARES_OPT_DOMAINS (1 << 7) #define ARES_OPT_LOOKUPS (1 << 8) #define ARES_OPT_SOCK_STATE_CB (1 << 9) +#define ARES_OPT_SORTLIST (1 << 10) /* Nameinfo flag values */ #define ARES_NI_NOFQDN (1 << 0) @@ -164,6 +165,8 @@ typedef void (*ares_sock_state_cb)(void *data, int writable); #endif +struct apattern; + struct ares_options { int flags; int timeout; @@ -178,6 +181,8 @@ struct ares_options { char *lookups; ares_sock_state_cb sock_state_cb; void *sock_state_cb_data; + struct apattern *sortlist; + int nsort; }; struct hostent; @@ -195,6 +200,8 @@ typedef void (*ares_nameinfo_callback)(void *arg, int status, int ares_init(ares_channel *channelptr); int ares_init_options(ares_channel *channelptr, struct ares_options *options, int optmask); +int ares_save_options(ares_channel channel, struct ares_options *options, int *optmask); +void ares_destroy_options(struct ares_options *options); void ares_destroy(ares_channel channel); void ares_cancel(ares_channel channel); void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, diff --git a/ares/ares_destroy.c b/ares/ares_destroy.c index fd243c30a..8d9bdbc15 100644 --- a/ares/ares_destroy.c +++ b/ares/ares_destroy.c @@ -20,6 +20,19 @@ #include "ares.h" #include "ares_private.h" +void ares_destroy_options(struct ares_options *options) +{ + int i; + + free(options->servers); + for (i = 0; i < options->ndomains; i++) + free(options->domains[i]); + free(options->domains); + if(options->sortlist) + free(options->sortlist); + free(options->lookups); +} + void ares_destroy(ares_channel channel) { int i; diff --git a/ares/ares_init.c b/ares/ares_init.c index bfe6b904c..d384f9401 100644 --- a/ares/ares_init.c +++ b/ares/ares_init.c @@ -61,7 +61,7 @@ #undef WIN32 /* Redefined in MingW/MSVC headers */ #endif -static int init_by_options(ares_channel channel, struct ares_options *options, +static int init_by_options(ares_channel channel, const struct ares_options *options, int optmask); static int init_by_environment(ares_channel channel); static int init_by_resolv_conf(ares_channel channel); @@ -84,6 +84,12 @@ static int config_sortlist(struct apattern **sortlist, int *nsort, static char *try_config(char *s, const char *opt); #endif +#define ARES_CONFIG_CHECK(x) (x->lookups && x->nsort > -1 && \ + x->nservers > -1 && \ + x->ndomains > -1 && \ + x->ndots > -1 && x->timeout > -1 && \ + x->tries > -1) + int ares_init(ares_channel *channelptr) { return ares_init_options(channelptr, NULL, 0); @@ -212,7 +218,76 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, return ARES_SUCCESS; } -static int init_by_options(ares_channel channel, struct ares_options *options, +/* Save options from initialized channel */ +int ares_save_options(ares_channel channel, struct ares_options *options, + int *optmask) +{ + int i; + + /* Zero everything out */ + memset(options, 0, sizeof(struct ares_options)); + + if (!ARES_CONFIG_CHECK(channel)) + return ARES_ENODATA; + + (*optmask) = (ARES_OPT_FLAGS|ARES_OPT_TIMEOUT|ARES_OPT_TRIES|ARES_OPT_NDOTS| + ARES_OPT_UDP_PORT|ARES_OPT_TCP_PORT|ARES_OPT_SOCK_STATE_CB| + ARES_OPT_SERVERS|ARES_OPT_DOMAINS|ARES_OPT_LOOKUPS| + ARES_OPT_SORTLIST); + + /* Copy easy stuff */ + options->flags = channel->flags; + options->timeout = channel->timeout; + options->tries = channel->tries; + options->ndots = channel->ndots; + options->udp_port = channel->udp_port; + options->tcp_port = channel->tcp_port; + options->sock_state_cb = channel->sock_state_cb; + options->sock_state_cb_data = channel->sock_state_cb_data; + + /* Copy servers */ + options->servers = + malloc(channel->nservers * sizeof(struct server_state)); + if (!options->servers && channel->nservers != 0) + return ARES_ENOMEM; + for (i = 0; i < channel->nservers; i++) + options->servers[i] = channel->servers[i].addr; + options->nservers = channel->nservers; + + /* copy domains */ + options->domains = malloc(channel->ndomains * sizeof(char *)); + if (!options->domains) + return ARES_ENOMEM; + for (i = 0; i < channel->ndomains; i++) + { + options->ndomains = i; + options->domains[i] = strdup(channel->domains[i]); + if (!options->domains[i]) + return ARES_ENOMEM; + } + options->ndomains = channel->ndomains; + + /* copy lookups */ + options->lookups = strdup(channel->lookups); + if (!options->lookups) + return ARES_ENOMEM; + + /* copy sortlist */ + options->sortlist = malloc(channel->nsort * sizeof(struct apattern)); + if (!options->sortlist) + return ARES_ENOMEM; + for (i = 0; i < channel->nsort; i++) + { + memcpy(&(options->sortlist[i]), &(channel->sortlist[i]), + sizeof(struct apattern)); + } + options->nsort = channel->nsort; + + return ARES_SUCCESS; +} + +static int init_by_options(ares_channel channel, + const struct ares_options *options, int optmask) { int i; @@ -282,6 +357,19 @@ static int init_by_options(ares_channel channel, struct ares_options *options, return ARES_ENOMEM; } + /* copy sortlist */ + if ((optmask & ARES_OPT_SORTLIST) && channel->nsort == -1) + { + channel->sortlist = malloc(options->nsort * sizeof(struct apattern)); + if (!channel->sortlist) + return ARES_ENOMEM; + for (i = 0; i < options->nsort; i++) + { + memcpy(&(channel->sortlist[i]), &(options->sortlist[i]), sizeof(struct apattern)); + } + channel->nsort = options->nsort; + } + return ARES_SUCCESS; } @@ -615,6 +703,10 @@ DhcpNameServer int linesize; int error; + /* Don't read resolv.conf and friends if we don't have to */ + if (ARES_CONFIG_CHECK(channel)) + return ARES_SUCCESS; + fp = fopen(PATH_RESOLV_CONF, "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)