* 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
#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)
int writable);
#endif
+struct apattern;
+
struct ares_options {
int flags;
int timeout;
char *lookups;
ares_sock_state_cb sock_state_cb;
void *sock_state_cb_data;
+ struct apattern *sortlist;
+ int nsort;
};
struct hostent;
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,
#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);
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);
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;
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;
}
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)