struct cf_hc_ctx {
cf_hc_state state;
- const struct Curl_dns_entry *remotehost;
struct curltime started; /* when connect started */
CURLcode result; /* overall result */
struct cf_hc_baller ballers[2];
struct Curl_easy *data,
int transport)
{
- struct cf_hc_ctx *ctx = cf->ctx;
struct Curl_cfilter *save = cf->next;
cf->next = NULL;
}
if(!b->result)
- b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost,
- transport, CURL_CF_SSL_ENABLE);
+ b->result = Curl_cf_setup_insert_after(cf, data, transport,
+ CURL_CF_SSL_ENABLE);
b->cf = cf->next;
cf->next = save;
}
static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
- const struct Curl_dns_entry *remotehost,
enum alpnid *alpnids, size_t alpn_count)
{
struct Curl_cfilter *cf = NULL;
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- ctx->remotehost = remotehost;
for(i = 0; i < alpn_count; ++i)
cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]);
for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
static CURLcode cf_http_connect_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
- const struct Curl_dns_entry *remotehost,
enum alpnid *alpn_ids, size_t alpn_count)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- result = cf_hc_create(&cf, data, remotehost, alpn_ids, alpn_count);
+ result = cf_hc_create(&cf, data, alpn_ids, alpn_count);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
struct connectdata *conn,
- int sockindex,
- const struct Curl_dns_entry *remotehost)
+ int sockindex)
{
enum alpnid alpn_ids[2];
size_t alpn_count = 0;
struct Curl_cfilter cf_fake, *cf = NULL;
(void)sockindex;
- (void)remotehost;
/* we want to log for the filter before we create it, fake it. */
memset(&cf_fake, 0, sizeof(cf_fake));
cf_fake.cft = &Curl_cft_http_connect;
* We are here after having selected a connection to a host+port and
* can no longer change that. Any HTTPSRR advice for other hosts and ports
* we need to ignore. */
- struct Curl_https_rrinfo *rr = remotehost ? remotehost->hinfo : NULL;
+ struct Curl_dns_entry *dns = data->state.dns[sockindex];
+ struct Curl_https_rrinfo *rr = dns ? dns->hinfo : NULL;
if(rr && !rr->no_def_alpn && /* ALPNs are defaults */
(!rr->target || /* for same host */
!rr->target[0] ||
/* If we identified ALPNs to use, install our filter. Otherwise,
* install nothing, so our call will use a default connect setup. */
if(alpn_count) {
- result = cf_http_connect_add(data, conn, sockindex, remotehost,
- alpn_ids, alpn_count);
+ result = cf_http_connect_add(data, conn, sockindex, alpn_ids, alpn_count);
}
out:
CURLcode Curl_cf_http_connect_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
- const struct Curl_dns_entry *remotehost,
bool try_h3, bool try_h21);
CURLcode
Curl_cf_http_connect_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
- const struct Curl_dns_entry *remotehost,
bool try_h3, bool try_h21);
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
struct connectdata *conn,
- int sockindex,
- const struct Curl_dns_entry *remotehost);
+ int sockindex);
#endif /* !defined(CURL_DISABLE_HTTP) */
struct cf_he_ctx {
int transport;
cf_ip_connect_create *cf_create;
- const struct Curl_dns_entry *remotehost;
cf_connect_state state;
struct eyeballer *baller[2];
struct eyeballer *winner;
* There might be more than one IP address to try out.
*/
static CURLcode start_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const struct Curl_dns_entry *remotehost)
+ struct Curl_easy *data)
{
struct cf_he_ctx *ctx = cf->ctx;
struct connectdata *conn = cf->conn;
int ai_family0 = 0, ai_family1 = 0;
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL;
+ struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
+
+ if(!dns)
+ return CURLE_FAILED_INIT;
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
ctx->started = curlx_now();
- /* remotehost->addr is the list of addresses from the resolver, each
+ /* dns->addr is the list of addresses from the resolver, each
* with an address family. The list has at least one entry, possibly
* many more.
* We try at most 2 at a time, until we either get a connection or
if(conn->ip_version == CURL_IPRESOLVE_V6) {
#ifdef USE_IPV6
ai_family0 = AF_INET6;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
+ addr0 = addr_first_match(dns->addr, ai_family0);
#endif
}
else if(conn->ip_version == CURL_IPRESOLVE_V4) {
ai_family0 = AF_INET;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
+ addr0 = addr_first_match(dns->addr, ai_family0);
}
else {
/* no user preference, we try ipv6 always first when available */
#ifdef USE_IPV6
ai_family0 = AF_INET6;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
+ addr0 = addr_first_match(dns->addr, ai_family0);
#endif
/* next candidate is ipv4 */
ai_family1 = AF_INET;
- addr1 = addr_first_match(remotehost->addr, ai_family1);
+ addr1 = addr_first_match(dns->addr, ai_family1);
/* no ip address families, probably AF_UNIX or something, use the
* address family given to us */
- if(!addr1 && !addr0 && remotehost->addr) {
- ai_family0 = remotehost->addr->ai_family;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
+ if(!addr1 && !addr0 && dns->addr) {
+ ai_family0 = dns->addr->ai_family;
+ addr0 = addr_first_match(dns->addr, ai_family0);
}
}
case SCFST_INIT:
DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data));
DEBUGASSERT(!cf->connected);
- result = start_connect(cf, data, ctx->remotehost);
+ result = start_connect(cf, data);
if(result)
return result;
ctx->state = SCFST_WAITING;
struct Curl_easy *data,
struct connectdata *conn,
cf_ip_connect_create *cf_create,
- const struct Curl_dns_entry *remotehost,
int transport)
{
struct cf_he_ctx *ctx = NULL;
}
ctx->transport = transport;
ctx->cf_create = cf_create;
- ctx->remotehost = remotehost;
result = Curl_cf_create(pcf, &Curl_cft_happy_eyeballs, ctx);
out:
if(result) {
Curl_safefree(*pcf);
- Curl_safefree(ctx);
+ free(ctx);
}
return result;
}
static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
- const struct Curl_dns_entry *remotehost,
int transport)
{
cf_ip_connect_create *cf_create;
return CURLE_UNSUPPORTED_PROTOCOL;
}
result = cf_happy_eyeballs_create(&cf, data, cf_at->conn,
- cf_create, remotehost,
- transport);
+ cf_create, transport);
if(result)
return result;
struct cf_setup_ctx {
cf_setup_state state;
- const struct Curl_dns_entry *remotehost;
int ssl_mode;
int transport;
};
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
+ struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
if(cf->connected) {
*done = TRUE;
/* connect current sub-chain */
connect_sub_chain:
+ if(!dns)
+ return CURLE_FAILED_INIT;
+
if(cf->next && !cf->next->connected) {
result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
}
if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
- result = cf_he_insert_after(cf, data, ctx->remotehost, ctx->transport);
+ result = cf_he_insert_after(cf, data, ctx->transport);
if(result)
return result;
ctx->state = CF_SETUP_CNNCT_EYEBALLS;
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
- const struct Curl_dns_entry *remotehost,
int transport,
int ssl_mode)
{
goto out;
}
ctx->state = CF_SETUP_INIT;
- ctx->remotehost = remotehost;
ctx->ssl_mode = ssl_mode;
ctx->transport = transport;
out:
*pcf = result ? NULL : cf;
- free(ctx);
+ if(ctx) {
+ free(ctx);
+ }
return result;
}
static CURLcode cf_setup_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
- const struct Curl_dns_entry *remotehost,
int transport,
int ssl_mode)
{
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
+ result = cf_setup_create(&cf, data, transport, ssl_mode);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
- const struct Curl_dns_entry *remotehost,
int transport,
int ssl_mode)
{
CURLcode result;
DEBUGASSERT(data);
- result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
+ result = cf_setup_create(&cf, data, transport, ssl_mode);
if(result)
goto out;
Curl_conn_cf_insert_after(cf_at, cf);
CURLcode Curl_conn_setup(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
- const struct Curl_dns_entry *remotehost,
+ struct Curl_dns_entry *dns,
int ssl_mode)
{
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
DEBUGASSERT(conn->handler);
+ DEBUGASSERT(dns);
+
+ Curl_resolv_unlink(data, &data->state.dns[sockindex]);
+ data->state.dns[sockindex] = dns;
#if !defined(CURL_DISABLE_HTTP)
if(!conn->cfilter[sockindex] &&
conn->handler->protocol == CURLPROTO_HTTPS) {
DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
- result = Curl_cf_https_setup(data, conn, sockindex, remotehost);
+ result = Curl_cf_https_setup(data, conn, sockindex);
if(result)
goto out;
}
/* Still no cfilter set, apply default. */
if(!conn->cfilter[sockindex]) {
- result = cf_setup_add(data, conn, sockindex, remotehost,
- conn->transport, ssl_mode);
+ result = cf_setup_add(data, conn, sockindex, conn->transport, ssl_mode);
if(result)
goto out;
}
DEBUGASSERT(conn->cfilter[sockindex]);
out:
+ if(result)
+ Curl_resolv_unlink(data, &data->state.dns[sockindex]);
return result;
}
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
- const struct Curl_dns_entry *remotehost,
int transport,
int ssl_mode);
CURLcode Curl_conn_setup(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
- const struct Curl_dns_entry *remotehost,
+ struct Curl_dns_entry *dns,
int ssl_mode);
extern struct Curl_cftype Curl_cft_happy_eyeballs;
struct connectdata *conn)
{
if(!conn->bits.shutdown_handler) {
- if(conn->dns_entry)
- Curl_resolv_unlink(data, &conn->dns_entry);
/* Cleanup NTLM connection-related data */
Curl_http_auth_cleanup_ntlm(conn);
/* clear all meta data */
Curl_meta_reset(data);
- /* clear any async resolve data */
+ /* clear any resolve data */
Curl_async_shutdown(data);
+ Curl_resolv_unlink(data, &data->state.dns[0]);
+ Curl_resolv_unlink(data, &data->state.dns[1]);
/* zero out UserDefined data: */
Curl_freeset(data);
memset(&data->set, 0, sizeof(struct UserDefined));
CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
if(result) {
- Curl_resolv_unlink(data, &dns); /* we are done using this dns entry */
if(ftpc->count1 == 0 && ftpcode == 229)
return ftp_epsv_disable(data, ftpc, conn);
/* this just dumps information about this second connection */
ftp_pasv_verbose(data, dns->addr, ftpc->newhost, connectport);
- Curl_resolv_unlink(data, &dns); /* we are done using this address */
-
free(conn->secondaryhostname);
conn->secondary_port = ftpc->newport;
conn->secondaryhostname = strdup(ftpc->newhost);
Note: this function disconnects and frees the conn data in case of
resolve failure */
-CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
+CURLcode Curl_once_resolved(struct Curl_easy *data,
+ struct Curl_dns_entry *dns,
+ bool *protocol_done)
{
CURLcode result;
struct connectdata *conn = data->conn;
#ifdef USE_CURL_ASYNC
if(data->state.async.dns) {
- conn->dns_entry = data->state.async.dns;
+ DEBUGASSERT(data->state.async.dns == dns);
data->state.async.dns = NULL;
}
#endif
- result = Curl_setup_conn(data, protocol_done);
+ result = Curl_setup_conn(data, dns, protocol_done);
if(result) {
Curl_detach_connection(data);
/* IPv4 threadsafe resolve function used for synch and asynch builds */
struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
-CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_connect);
+CURLcode Curl_once_resolved(struct Curl_easy *data,
+ struct Curl_dns_entry *dns,
+ bool *protocol_connect);
/*
* Curl_printable_address() returns a printable version of the 1st address
data->state.done = TRUE; /* called just now! */
data->state.recent_conn_id = conn->connection_id;
- if(conn->dns_entry)
- Curl_resolv_unlink(data, &conn->dns_entry); /* done with this */
+ Curl_resolv_unlink(data, &data->state.dns[0]); /* done with this */
+ Curl_resolv_unlink(data, &data->state.dns[1]);
Curl_dnscache_prune(data);
/* if data->set.reuse_forbid is TRUE, it means the libcurl client has
bool connected;
/* Perform the next step in the connection phase, and then move on to the
WAITCONNECT state */
- result = Curl_once_resolved(data, &connected);
+ result = Curl_once_resolved(data, dns, &connected);
if(result)
/* if Curl_once_resolved() returns failure, the connection struct is
#include "vtls/vtls.h"
#include "curlx/warnless.h"
#include "sendf.h"
+#include "hostip.h"
#include "http2.h"
#include "setopt.h"
#include "multiif.h"
if(data->psl == &data->share->psl)
data->psl = data->multi ? &data->multi->psl : NULL;
#endif
+ if(data->share->specifier & (1 << CURL_LOCK_DATA_DNS)) {
+ Curl_resolv_unlink(data, &data->state.dns[0]);
+ Curl_resolv_unlink(data, &data->state.dns[1]);
+ }
data->share->dirty--;
Curl_safefree(data->info.contenttype);
Curl_safefree(data->info.wouldredirect);
+ /* release any resolve information this transfer kept */
Curl_async_destroy(data);
+ Curl_resolv_unlink(data, &data->state.dns[0]); /* done with this */
+ Curl_resolv_unlink(data, &data->state.dns[1]);
data_priority_cleanup(data);
#ifdef USE_UNIX_SOCKETS
static CURLcode resolve_unix(struct Curl_easy *data,
struct connectdata *conn,
- char *unix_path)
+ char *unix_path,
+ struct Curl_dns_entry **pdns)
{
- struct Curl_dns_entry *hostaddr = NULL;
+ struct Curl_dns_entry *hostaddr;
bool longpath = FALSE;
DEBUGASSERT(unix_path);
- DEBUGASSERT(conn->dns_entry == NULL);
+ *pdns = NULL;
/* Unix domain sockets are local. The host gets ignored, just use the
* specified domain socket address. Do not cache "DNS entries". There is
}
hostaddr->refcount = 1; /* connection is the only one holding this */
- conn->dns_entry = hostaddr;
+ *pdns = hostaddr;
return CURLE_OK;
}
#endif
*************************************************************/
static CURLcode resolve_server(struct Curl_easy *data,
struct connectdata *conn,
- bool *async)
+ bool *async,
+ struct Curl_dns_entry **pdns)
{
struct hostname *ehost;
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
const char *peertype = "host";
CURLcode result;
+
+ *pdns = NULL;
+
#ifdef USE_UNIX_SOCKETS
- char *unix_path = conn->unix_domain_socket;
+ {
+ char *unix_path = conn->unix_domain_socket;
#ifndef CURL_DISABLE_PROXY
- if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
- !strncmp(UNIX_SOCKET_PREFIX"/",
- conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
- unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
+ if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
+ !strncmp(UNIX_SOCKET_PREFIX"/",
+ conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
+ unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
#endif
- if(unix_path) {
- /* This only works if previous transport is TRNSPRT_TCP. Check it? */
- conn->transport = TRNSPRT_UNIX;
- return resolve_unix(data, conn, unix_path);
+ if(unix_path) {
+ /* This only works if previous transport is TRNSPRT_TCP. Check it? */
+ conn->transport = TRNSPRT_UNIX;
+ return resolve_unix(data, conn, unix_path, pdns);
+ }
}
#endif
- DEBUGASSERT(conn->dns_entry == NULL);
-
#ifndef CURL_DISABLE_PROXY
if(CONN_IS_PROXIED(conn)) {
ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
result = Curl_resolv_timeout(data, conn->hostname_resolve,
conn->primary.remote_port, conn->ip_version,
- &conn->dns_entry, timeout_ms);
+ pdns, timeout_ms);
+ DEBUGASSERT(!result || !*pdns);
if(result == CURLE_AGAIN) {
- DEBUGASSERT(!conn->dns_entry);
*async = TRUE;
return CURLE_OK;
}
failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
return result;
}
- DEBUGASSERT(conn->dns_entry);
+ DEBUGASSERT(*pdns);
return CURLE_OK;
}
static CURLcode create_conn(struct Curl_easy *data,
struct connectdata **in_connect,
- bool *async)
+ bool *reusedp)
{
CURLcode result = CURLE_OK;
struct connectdata *conn;
bool force_reuse = FALSE;
bool waitpipe = FALSE;
- *async = FALSE;
+ *reusedp = FALSE;
*in_connect = NULL;
/*************************************************************
/* We are reusing the connection - no need to resolve anything, and
idnconvert_hostname() was called already in create_conn() for the reuse
case. */
- *async = FALSE;
- }
- else {
- /*************************************************************
- * Resolve the address of the server or proxy
- *************************************************************/
- result = resolve_server(data, conn, async);
- if(result)
- goto out;
+ *reusedp = TRUE;
}
/* persist the scheme and handler the transfer is using */
* Curl_setup_conn() also handles reused connections
*/
CURLcode Curl_setup_conn(struct Curl_easy *data,
+ struct Curl_dns_entry *dns,
bool *protocol_done)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
+ DEBUGASSERT(dns);
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
- if(conn->handler->flags & PROTOPT_NONETWORK) {
- /* nothing to setup when not using a network */
- *protocol_done = TRUE;
- return result;
- }
-
if(!conn->bits.reuse)
- result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
+ result = Curl_conn_setup(data, conn, FIRSTSOCKET, dns,
CURL_CF_SSL_DEFAULT);
if(!result)
result = Curl_headers_init(data);
{
CURLcode result;
struct connectdata *conn;
+ bool reused = FALSE;
*asyncp = FALSE; /* assume synchronous resolves by default */
+ *protocol_done = FALSE;
/* Set the request to virgin state based on transfer settings */
Curl_req_hard_reset(&data->req, data);
/* call the stuff that needs to be called */
- result = create_conn(data, &conn, asyncp);
+ result = create_conn(data, &conn, &reused);
+
+ if(result == CURLE_NO_CONNECTION_AVAILABLE) {
+ DEBUGASSERT(!conn);
+ return result;
+ }
if(!result) {
- if(CONN_ATTACHED(conn) > 1)
- /* multiplexed */
+ DEBUGASSERT(conn);
+ if(reused) {
+ if(CONN_ATTACHED(conn) > 1)
+ /* multiplexed */
+ *protocol_done = TRUE;
+ }
+ else if(conn->handler->flags & PROTOPT_NONETWORK) {
+ *asyncp = FALSE;
+ Curl_pgrsTime(data, TIMER_NAMELOOKUP);
*protocol_done = TRUE;
- else if(!*asyncp) {
- /* DNS resolution is done: that is either because this is a reused
- connection, in which case DNS was unnecessary, or because DNS
- really did finish already (synch resolver/fast async resolve) */
- result = Curl_setup_conn(data, protocol_done);
+ }
+ else {
+ /*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+ struct Curl_dns_entry *dns;
+ result = resolve_server(data, conn, asyncp, &dns);
+ if(!result) {
+ *asyncp = !dns;
+ if(dns)
+ /* DNS resolution is done: that is either because this is a reused
+ connection, in which case DNS was unnecessary, or because DNS
+ really did finish already (synch resolver/fast async resolve) */
+ result = Curl_setup_conn(data, dns, protocol_done);
+ }
}
}
- if(result == CURLE_NO_CONNECTION_AVAILABLE) {
- return result;
- }
- else if(result && conn) {
+ if(result && conn) {
/* We are not allowed to return failure with memory left allocated in the
connectdata struct, free those here */
Curl_detach_connection(data);
CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
CURLcode Curl_setup_conn(struct Curl_easy *data,
+ struct Curl_dns_entry *dns,
bool *protocol_done);
void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn);
CURLcode Curl_parse_login_details(const char *login, const size_t len,
* the connection is cleaned up (see Curl_hash_add2()).*/
struct Curl_hash meta_hash;
- /* 'dns_entry' is the particular host we use. This points to an entry in the
- DNS cache and it will not get pruned while locked. It gets unlocked in
- multi_done(). This entry will be NULL if the connection is reused as then
- there is no name resolve done. */
- struct Curl_dns_entry *dns_entry;
-
/* 'remote_addr' is the particular IP we connected to. it is owned, set
* and NULLed by the connected socket filter (if there is one). */
const struct Curl_sockaddr_ex *remote_addr;
#endif
struct auth authhost; /* auth details for host */
struct auth authproxy; /* auth details for proxy */
+
+ struct Curl_dns_entry *dns[2]; /* DNS to connect FIRST/SECONDARY */
#ifdef USE_CURL_ASYNC
struct Curl_async async; /* asynchronous name resolver data */
#endif