mirror of
https://github.com/curl/curl.git
synced 2026-08-24 16:43:34 +03:00
c-ares: really lazy init channel
Only initialize the c-ares channel when we start resolving and not alreads when the application sets `CURLOPT_DNS_SERVERS` and friends. Creating an ares channel takes considerable time and when we have the DNS information for a transfer already cached, we do not need it. Closes #17167
This commit is contained in:
parent
437c72fbba
commit
7bf576064c
4 changed files with 86 additions and 115 deletions
141
lib/asyn-ares.c
141
lib/asyn-ares.c
|
|
@ -113,6 +113,9 @@
|
||||||
|
|
||||||
static int ares_ver = 0;
|
static int ares_ver = 0;
|
||||||
|
|
||||||
|
static CURLcode async_ares_set_dns_servers(struct Curl_easy *data,
|
||||||
|
bool reset_on_null);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_async_global_init() - the generic low-level asynchronous name
|
* Curl_async_global_init() - the generic low-level asynchronous name
|
||||||
* resolve API. Called from curl_global_init() to initialize global resolver
|
* resolve API. Called from curl_global_init() to initialize global resolver
|
||||||
|
|
@ -159,6 +162,8 @@ static CURLcode async_ares_init(struct Curl_easy *data)
|
||||||
int status;
|
int status;
|
||||||
struct ares_options options;
|
struct ares_options options;
|
||||||
int optmask = ARES_OPT_SOCK_STATE_CB;
|
int optmask = ARES_OPT_SOCK_STATE_CB;
|
||||||
|
CURLcode rc = CURLE_OK;
|
||||||
|
|
||||||
options.sock_state_cb = sock_state_cb;
|
options.sock_state_cb = sock_state_cb;
|
||||||
options.sock_state_cb_data = data;
|
options.sock_state_cb_data = data;
|
||||||
|
|
||||||
|
|
@ -181,25 +186,35 @@ static CURLcode async_ares_init(struct Curl_easy *data)
|
||||||
status = ares_init_options(&ares->channel, &options, optmask);
|
status = ares_init_options(&ares->channel, &options, optmask);
|
||||||
if(status != ARES_SUCCESS) {
|
if(status != ARES_SUCCESS) {
|
||||||
ares->channel = NULL;
|
ares->channel = NULL;
|
||||||
if(status == ARES_ENOMEM)
|
rc = (status == ARES_ENOMEM) ?
|
||||||
return CURLE_OUT_OF_MEMORY;
|
CURLE_OUT_OF_MEMORY : CURLE_FAILED_INIT;
|
||||||
else
|
goto out;
|
||||||
return CURLE_FAILED_INIT;
|
|
||||||
}
|
}
|
||||||
#if defined(CURLDEBUG) && defined(HAVE_CARES_PORTS_CSV)
|
|
||||||
else {
|
|
||||||
const char *env = getenv("CURL_DNS_SERVER");
|
|
||||||
if(env) {
|
|
||||||
int rc = ares_set_servers_ports_csv(ares->channel, env);
|
|
||||||
if(rc)
|
|
||||||
infof(data, "ares_set_servers_ports_csv failed: %d", rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return CURLE_OK;
|
rc = async_ares_set_dns_servers(data, FALSE);
|
||||||
/* make sure that all other returns from this function should destroy the
|
if(rc && rc != CURLE_NOT_BUILT_IN)
|
||||||
ares channel before returning error! */
|
goto out;
|
||||||
|
|
||||||
|
rc = Curl_async_ares_set_dns_interface(data);
|
||||||
|
if(rc && rc != CURLE_NOT_BUILT_IN)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rc = Curl_async_ares_set_dns_local_ip4(data);
|
||||||
|
if(rc && rc != CURLE_NOT_BUILT_IN)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rc = Curl_async_ares_set_dns_local_ip6(data);
|
||||||
|
if(rc && rc != CURLE_NOT_BUILT_IN)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rc = CURLE_OK;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if(rc && ares->channel) {
|
||||||
|
ares_destroy(ares->channel);
|
||||||
|
ares->channel = NULL;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode async_ares_init_lazy(struct Curl_easy *data)
|
static CURLcode async_ares_init_lazy(struct Curl_easy *data)
|
||||||
|
|
@ -794,43 +809,39 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
|
||||||
return NULL; /* no struct yet */
|
return NULL; /* no struct yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_set_dns_servers(struct Curl_easy *data,
|
/* Set what DNS server are is to use. This is called in 2 situations:
|
||||||
char *servers)
|
* 1. when the application does `CURLOPT_DNS_SERVERS´ and passing NULL
|
||||||
|
* means any previous set value should be unset. Which means
|
||||||
|
* we need to destroy and create the are channel anew, if there is one.
|
||||||
|
* 2. When we lazy init the ares channel and NULL means that there
|
||||||
|
* are no preferences and we do not reset any existing channel. */
|
||||||
|
static CURLcode async_ares_set_dns_servers(struct Curl_easy *data,
|
||||||
|
bool reset_on_null)
|
||||||
{
|
{
|
||||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||||
CURLcode result = CURLE_NOT_BUILT_IN;
|
CURLcode result = CURLE_NOT_BUILT_IN;
|
||||||
int ares_result;
|
const char *servers = data->set.str[STRING_DNS_SERVERS];
|
||||||
|
int ares_result = ARES_SUCCESS;
|
||||||
|
|
||||||
|
#if defined(CURLDEBUG) && defined(HAVE_CARES_SERVERS_CSV)
|
||||||
|
if(getenv("CURL_DNS_SERVER"))
|
||||||
|
servers = getenv("CURL_DNS_SERVER");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If server is NULL, this purges all DNS servers from c-ares. Reset it to
|
|
||||||
* default.
|
|
||||||
*/
|
|
||||||
if(!servers) {
|
if(!servers) {
|
||||||
Curl_async_destroy(data);
|
if(reset_on_null) {
|
||||||
result = async_ares_init_lazy(data);
|
Curl_async_destroy(data);
|
||||||
if(!result) {
|
|
||||||
/* this now needs to restore the other options set to c-ares */
|
|
||||||
if(data->set.str[STRING_DNS_INTERFACE])
|
|
||||||
(void)Curl_set_dns_interface(data,
|
|
||||||
data->set.str[STRING_DNS_INTERFACE]);
|
|
||||||
if(data->set.str[STRING_DNS_LOCAL_IP4])
|
|
||||||
(void)Curl_set_dns_local_ip4(data,
|
|
||||||
data->set.str[STRING_DNS_LOCAL_IP4]);
|
|
||||||
if(data->set.str[STRING_DNS_LOCAL_IP6])
|
|
||||||
(void)Curl_set_dns_local_ip6(data,
|
|
||||||
data->set.str[STRING_DNS_LOCAL_IP6]);
|
|
||||||
}
|
}
|
||||||
return result;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_CARES_SERVERS_CSV
|
#ifdef HAVE_CARES_SERVERS_CSV
|
||||||
result = async_ares_init_lazy(data);
|
/* if channel is not there, this is just a parameter check */
|
||||||
if(result)
|
if(ares->channel)
|
||||||
return result;
|
|
||||||
|
|
||||||
#ifdef HAVE_CARES_PORTS_CSV
|
#ifdef HAVE_CARES_PORTS_CSV
|
||||||
ares_result = ares_set_servers_ports_csv(ares->channel, servers);
|
ares_result = ares_set_servers_ports_csv(ares->channel, servers);
|
||||||
#else
|
#else
|
||||||
ares_result = ares_set_servers_csv(ares->channel, servers);
|
ares_result = ares_set_servers_csv(ares->channel, servers);
|
||||||
#endif
|
#endif
|
||||||
switch(ares_result) {
|
switch(ares_result) {
|
||||||
case ARES_SUCCESS:
|
case ARES_SUCCESS:
|
||||||
|
|
@ -854,21 +865,23 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_set_dns_interface(struct Curl_easy *data,
|
CURLcode Curl_async_ares_set_dns_servers(struct Curl_easy *data)
|
||||||
const char *interf)
|
{
|
||||||
|
return async_ares_set_dns_servers(data, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_async_ares_set_dns_interface(struct Curl_easy *data)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_CARES_LOCAL_DEV
|
#ifdef HAVE_CARES_LOCAL_DEV
|
||||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||||
CURLcode result;
|
const char *interf = data->set.str[STRING_DNS_INTERFACE];
|
||||||
|
|
||||||
if(!interf)
|
if(!interf)
|
||||||
interf = "";
|
interf = "";
|
||||||
|
|
||||||
result = async_ares_init_lazy(data);
|
/* if channel is not there, this is just a parameter check */
|
||||||
if(result)
|
if(ares->channel)
|
||||||
return result;
|
ares_set_local_dev(ares->channel, interf);
|
||||||
|
|
||||||
ares_set_local_dev(ares->channel, interf);
|
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
#else /* c-ares version too old! */
|
#else /* c-ares version too old! */
|
||||||
|
|
@ -878,13 +891,12 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
|
CURLcode Curl_async_ares_set_dns_local_ip4(struct Curl_easy *data)
|
||||||
const char *local_ip4)
|
|
||||||
{
|
{
|
||||||
#ifdef HAVE_CARES_SET_LOCAL
|
#ifdef HAVE_CARES_SET_LOCAL
|
||||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||||
struct in_addr a4;
|
struct in_addr a4;
|
||||||
CURLcode result;
|
const char *local_ip4 = data->set.str[STRING_DNS_LOCAL_IP4];
|
||||||
|
|
||||||
if((!local_ip4) || (local_ip4[0] == 0)) {
|
if((!local_ip4) || (local_ip4[0] == 0)) {
|
||||||
a4.s_addr = 0; /* disabled: do not bind to a specific address */
|
a4.s_addr = 0; /* disabled: do not bind to a specific address */
|
||||||
|
|
@ -896,11 +908,9 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = async_ares_init_lazy(data);
|
/* if channel is not there yet, this is just a parameter check */
|
||||||
if(result)
|
if(ares->channel)
|
||||||
return result;
|
ares_set_local_ip4(ares->channel, ntohl(a4.s_addr));
|
||||||
|
|
||||||
ares_set_local_ip4(ares->channel, ntohl(a4.s_addr));
|
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
#else /* c-ares version too old! */
|
#else /* c-ares version too old! */
|
||||||
|
|
@ -910,13 +920,12 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
|
CURLcode Curl_async_ares_set_dns_local_ip6(struct Curl_easy *data)
|
||||||
const char *local_ip6)
|
|
||||||
{
|
{
|
||||||
#if defined(HAVE_CARES_SET_LOCAL) && defined(USE_IPV6)
|
#if defined(HAVE_CARES_SET_LOCAL) && defined(USE_IPV6)
|
||||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||||
unsigned char a6[INET6_ADDRSTRLEN];
|
unsigned char a6[INET6_ADDRSTRLEN];
|
||||||
CURLcode result;
|
const char *local_ip6 = data->set.str[STRING_DNS_LOCAL_IP6];
|
||||||
|
|
||||||
if((!local_ip6) || (local_ip6[0] == 0)) {
|
if((!local_ip6) || (local_ip6[0] == 0)) {
|
||||||
/* disabled: do not bind to a specific address */
|
/* disabled: do not bind to a specific address */
|
||||||
|
|
@ -929,11 +938,9 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = async_ares_init_lazy(data);
|
/* if channel is not there, this is just a parameter check */
|
||||||
if(result)
|
if(ares->channel)
|
||||||
return result;
|
ares_set_local_ip6(ares->channel, a6);
|
||||||
|
|
||||||
ares_set_local_ip6(ares->channel, a6);
|
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
#else /* c-ares version too old! */
|
#else /* c-ares version too old! */
|
||||||
|
|
|
||||||
30
lib/asyn.h
30
lib/asyn.h
|
|
@ -154,31 +154,17 @@ struct async_ares_ctx {
|
||||||
void Curl_async_ares_shutdown(struct Curl_easy *data);
|
void Curl_async_ares_shutdown(struct Curl_easy *data);
|
||||||
void Curl_async_ares_destroy(struct Curl_easy *data);
|
void Curl_async_ares_destroy(struct Curl_easy *data);
|
||||||
|
|
||||||
/*
|
/* Set the DNS server to use by ares, from `data` settings. */
|
||||||
* Function provided by the resolver backend to set DNS servers to use.
|
CURLcode Curl_async_ares_set_dns_servers(struct Curl_easy *data);
|
||||||
*/
|
|
||||||
CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers);
|
|
||||||
|
|
||||||
/*
|
/* Set the DNS interfacer to use by ares, from `data` settings. */
|
||||||
* Function provided by the resolver backend to set
|
CURLcode Curl_async_ares_set_dns_interface(struct Curl_easy *data);
|
||||||
* outgoing interface to use for DNS requests
|
|
||||||
*/
|
|
||||||
CURLcode Curl_set_dns_interface(struct Curl_easy *data,
|
|
||||||
const char *interf);
|
|
||||||
|
|
||||||
/*
|
/* Set the local ipv4 address to use by ares, from `data` settings. */
|
||||||
* Function provided by the resolver backend to set
|
CURLcode Curl_async_ares_set_dns_local_ip4(struct Curl_easy *data);
|
||||||
* local IPv4 address to use as source address for DNS requests
|
|
||||||
*/
|
|
||||||
CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
|
|
||||||
const char *local_ip4);
|
|
||||||
|
|
||||||
/*
|
/* Set the local ipv6 address to use by ares, from `data` settings. */
|
||||||
* Function provided by the resolver backend to set
|
CURLcode Curl_async_ares_set_dns_local_ip6(struct Curl_easy *data);
|
||||||
* local IPv6 address to use as source address for DNS requests
|
|
||||||
*/
|
|
||||||
CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
|
|
||||||
const char *local_ip6);
|
|
||||||
|
|
||||||
#endif /* CURLRES_ARES */
|
#endif /* CURLRES_ARES */
|
||||||
|
|
||||||
|
|
|
||||||
22
lib/easy.c
22
lib/easy.c
|
|
@ -1050,28 +1050,6 @@ CURL *curl_easy_duphandle(CURL *d)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CURLRES_ARES
|
|
||||||
{
|
|
||||||
CURLcode rc;
|
|
||||||
|
|
||||||
rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]);
|
|
||||||
if(rc && rc != CURLE_NOT_BUILT_IN)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]);
|
|
||||||
if(rc && rc != CURLE_NOT_BUILT_IN)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]);
|
|
||||||
if(rc && rc != CURLE_NOT_BUILT_IN)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]);
|
|
||||||
if(rc && rc != CURLE_NOT_BUILT_IN)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
#endif /* USE_ARES */
|
|
||||||
|
|
||||||
outcurl->magic = CURLEASY_MAGIC_NUMBER;
|
outcurl->magic = CURLEASY_MAGIC_NUMBER;
|
||||||
|
|
||||||
/* we reach this point and thus we are OK */
|
/* we reach this point and thus we are OK */
|
||||||
|
|
|
||||||
|
|
@ -2540,25 +2540,25 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
|
||||||
result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], ptr);
|
result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], ptr);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
return Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
|
return Curl_async_ares_set_dns_servers(data);
|
||||||
|
|
||||||
case CURLOPT_DNS_INTERFACE:
|
case CURLOPT_DNS_INTERFACE:
|
||||||
result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], ptr);
|
result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], ptr);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
return Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]);
|
return Curl_async_ares_set_dns_interface(data);
|
||||||
|
|
||||||
case CURLOPT_DNS_LOCAL_IP4:
|
case CURLOPT_DNS_LOCAL_IP4:
|
||||||
result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], ptr);
|
result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], ptr);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
return Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]);
|
return Curl_async_ares_set_dns_local_ip4(data);
|
||||||
|
|
||||||
case CURLOPT_DNS_LOCAL_IP6:
|
case CURLOPT_DNS_LOCAL_IP6:
|
||||||
result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], ptr);
|
result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], ptr);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
return Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]);
|
return Curl_async_ares_set_dns_local_ip6(data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_UNIX_SOCKETS
|
#ifdef USE_UNIX_SOCKETS
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue