void Curl_resolver_cancel(struct Curl_easy *data)
{
DEBUGASSERT(data);
- if(data->conn->resolve_async.resolver)
- ares_cancel((ares_channel)data->conn->resolve_async.resolver);
- destroy_async_data(&data->conn->resolve_async);
+ if(data->state.async.resolver)
+ ares_cancel((ares_channel)data->state.async.resolver);
+ destroy_async_data(&data->state.async);
}
/*
struct timeval timebuf;
struct timeval *timeout;
long milli;
- int max = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
+ int max = ares_getsock((ares_channel)data->state.async.resolver,
(ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
maxtime.tv_usec = 0;
- timeout = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
- &maxtime, &timebuf);
+ timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
+ &timebuf);
milli = (long)curlx_tvtoms(timeout);
if(milli == 0)
milli += 10;
int i;
int num = 0;
- bitmask = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
- socks, ARES_GETSOCK_MAXNUM);
+ bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
+ ARES_GETSOCK_MAXNUM);
for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
pfd[i].events = 0;
if(!nfds)
/* Call ares_process() unconditionally here, even if we simply timed out
above, as otherwise the ares name resolve won't timeout! */
- ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
- ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
+ ARES_SOCKET_BAD);
else {
/* move through the descriptors and ask for processing on them */
for(i = 0; i < num; i++)
- ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
+ ares_process_fd((ares_channel)data->state.async.resolver,
(pfd[i].revents & (POLLRDNORM|POLLIN))?
pfd[i].fd:ARES_SOCKET_BAD,
(pfd[i].revents & (POLLWRNORM|POLLOUT))?
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns)
{
- struct thread_data *res = data->conn->resolve_async.tdata;
+ struct thread_data *res = data->state.async.tdata;
CURLcode result = CURLE_OK;
DEBUGASSERT(dns);
ARES_ECANCELLED synchronously for all pending responses. This will
leave us with res->num_pending == 0, which is perfect for the next
block. */
- ares_cancel((ares_channel)data->conn->resolve_async.resolver);
+ ares_cancel((ares_channel)data->state.async.resolver);
DEBUGASSERT(res->num_pending == 0);
}
#endif
them */
res->temp_ai = NULL;
- if(!data->conn->resolve_async.dns)
+ if(!data->state.async.dns)
result = Curl_resolver_error(data);
else
- *dns = data->conn->resolve_async.dns;
+ *dns = data->state.async.dns;
- destroy_async_data(&data->conn->resolve_async);
+ destroy_async_data(&data->state.async);
}
return result;
store.tv_sec = itimeout/1000;
store.tv_usec = (itimeout%1000)*1000;
- tvp = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
- &store, &tv);
+ tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
/* use the timeout period ares returned to us above if less than one
second is left, otherwise just use 1000ms to make sure the progress
return CURLE_UNRECOVERABLE_POLL;
result = Curl_resolver_is_resolved(data, entry);
- if(result || data->conn->resolve_async.done)
+ if(result || data->state.async.done)
break;
if(Curl_pgrsUpdate(data))
}
if(result)
/* failure, so we cancel the ares operation */
- ares_cancel((ares_channel)data->conn->resolve_async.resolver);
+ ares_cancel((ares_channel)data->state.async.resolver);
/* Operation complete, if the lookup was successful we now have the entry
in the cache. */
if(entry)
- *entry = data->conn->resolve_async.dns;
+ *entry = data->state.async.dns;
if(result)
/* close the connection, since we can't return failure here without
be valid so only defer it when we know the 'status' says its fine! */
return;
- res = data->conn->resolve_async.tdata;
+ res = data->state.async.tdata;
if(res) {
res->num_pending--;
if(CURL_ASYNC_SUCCESS == status) {
- struct Curl_addrinfo *ai = Curl_he2ai(hostent,
- data->conn->resolve_async.port);
+ struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
if(ai) {
compound_results(res, ai);
}
struct ares_addrinfo *result)
{
struct Curl_easy *data = (struct Curl_easy *)arg;
- if(data->conn) {
- struct thread_data *res = data->conn->resolve_async.tdata;
- (void)timeouts;
- if(ARES_SUCCESS == status) {
- res->temp_ai = ares2addr(result->nodes);
- res->last_status = CURL_ASYNC_SUCCESS;
- ares_freeaddrinfo(result);
- }
- res->num_pending--;
+ struct thread_data *res = data->state.async.tdata;
+ (void)timeouts;
+ if(ARES_SUCCESS == status) {
+ res->temp_ai = ares2addr(result->nodes);
+ res->last_status = CURL_ASYNC_SUCCESS;
+ ares_freeaddrinfo(result);
}
+ res->num_pending--;
}
#endif
res = calloc(1, sizeof(struct thread_data) + namelen);
if(res) {
strcpy(res->hostname, hostname);
- data->conn->resolve_async.hostname = res->hostname;
- data->conn->resolve_async.port = port;
- data->conn->resolve_async.done = FALSE; /* not done */
- data->conn->resolve_async.status = 0; /* clear */
- data->conn->resolve_async.dns = NULL; /* clear */
- data->conn->resolve_async.tdata = res;
+ data->state.async.hostname = res->hostname;
+ data->state.async.port = port;
+ data->state.async.done = FALSE; /* not done */
+ data->state.async.status = 0; /* clear */
+ data->state.async.dns = NULL; /* clear */
+ data->state.async.tdata = res;
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
hints.ai_flags = ARES_AI_NUMERICSERV;
msnprintf(service, sizeof(service), "%d", port);
res->num_pending = 1;
- ares_getaddrinfo((ares_channel)data->conn->resolve_async.resolver,
- hostname, service, &hints, addrinfo_cb, data);
+ ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
+ service, &hints, addrinfo_cb, data);
}
#else
res->num_pending = 2;
/* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
- hostname, PF_INET, query_completed_cb, data);
- ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
- hostname, PF_INET6, query_completed_cb, data);
+ ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+ PF_INET, query_completed_cb, data);
+ ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+ PF_INET6, query_completed_cb, data);
}
else
#endif
res->num_pending = 1;
/* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
+ ares_gethostbyname((ares_channel)data->state.async.resolver,
hostname, PF_INET,
query_completed_cb, data);
}
char *servers)
{
CURLcode result = CURLE_NOT_BUILT_IN;
- ares_channel channel, lchannel = NULL;
int ares_result;
/* If server is NULL or empty, this would purge all DNS servers
return CURLE_OK;
#ifdef HAVE_CARES_SERVERS_CSV
- if(data->conn)
- channel = data->conn->resolve_async.resolver;
- else {
- /* we are called by setopt on a data without a connection (yet). In that
- * case we set the value on a local instance for checking.
- * The configured data options are set when the connection for this
- * transfer is created. */
- result = Curl_resolver_init(data, (void **)&lchannel);
- if(result)
- goto out;
- channel = lchannel;
- }
-
#ifdef HAVE_CARES_PORTS_CSV
- ares_result = ares_set_servers_ports_csv(channel, servers);
+ ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
+ servers);
#else
- ares_result = ares_set_servers_csv(channel, servers);
+ ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
#endif
switch(ares_result) {
case ARES_SUCCESS:
result = CURLE_BAD_FUNCTION_ARGUMENT;
break;
}
-out:
- if(lchannel)
- Curl_resolver_cleanup(lchannel);
#else /* too old c-ares version! */
(void)data;
(void)(ares_result);
const char *interf)
{
#ifdef HAVE_CARES_LOCAL_DEV
- if(data->conn) {
- /* not a setopt test run, set the value */
- if(!interf)
- interf = "";
+ if(!interf)
+ interf = "";
+
+ ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
- ares_set_local_dev((ares_channel)data->conn->resolve_async.resolver,
- interf);
- }
return CURLE_OK;
#else /* c-ares version too old! */
(void)data;
}
}
- if(data->conn) {
- /* not a setopt test run, set the value */
- ares_set_local_ip4((ares_channel)data->conn->resolve_async.resolver,
- ntohl(a4.s_addr));
- }
+ ares_set_local_ip4((ares_channel)data->state.async.resolver,
+ ntohl(a4.s_addr));
return CURLE_OK;
#else /* c-ares version too old! */
}
}
- if(data->conn) {
- /* not a setopt test run, set the value */
- ares_set_local_ip6((ares_channel)data->conn->resolve_async.resolver, a6);
- }
+ ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
return CURLE_OK;
#else /* c-ares version too old! */
*/
void Curl_resolver_cancel(struct Curl_easy *data)
{
- destroy_async_data(&data->conn->resolve_async);
+ destroy_async_data(&data->state.async);
}
/* This function is used to init a threaded resolve */
static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{
- return &(data->conn->resolve_async.tdata->tsd);
+ return &(data->state.async.tdata->tsd);
}
/* Destroy resolver thread synchronization data */
{
struct thread_data *td = calloc(1, sizeof(struct thread_data));
int err = ENOMEM;
- struct Curl_async *asp = &data->conn->resolve_async;
+ struct Curl_async *asp = &data->state.async;
- data->conn->resolve_async.tdata = td;
+ data->state.async.tdata = td;
if(!td)
goto errno_exit;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- td = data->conn->resolve_async.tdata;
+ td = data->state.async.tdata;
DEBUGASSERT(td);
DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
else
DEBUGASSERT(0);
- data->conn->resolve_async.done = TRUE;
+ data->state.async.done = TRUE;
if(entry)
- *entry = data->conn->resolve_async.dns;
+ *entry = data->state.async.dns;
- if(!data->conn->resolve_async.dns && report)
+ if(!data->state.async.dns && report)
/* a name was not resolved, report error */
result = Curl_resolver_error(data);
- destroy_async_data(&data->conn->resolve_async);
+ destroy_async_data(&data->state.async);
- if(!data->conn->resolve_async.dns && report)
+ if(!data->state.async.dns && report)
connclose(data->conn, "asynch resolve failed");
return result;
*/
void Curl_resolver_kill(struct Curl_easy *data)
{
- struct thread_data *td = data->conn->resolve_async.tdata;
+ struct thread_data *td = data->state.async.tdata;
/* If we're still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry)
{
- struct thread_data *td = data->conn->resolve_async.tdata;
+ struct thread_data *td = data->state.async.tdata;
int done = 0;
DEBUGASSERT(entry);
if(done) {
getaddrinfo_complete(data);
- if(!data->conn->resolve_async.dns) {
+ if(!data->state.async.dns) {
CURLcode result = Curl_resolver_error(data);
- destroy_async_data(&data->conn->resolve_async);
+ destroy_async_data(&data->state.async);
return result;
}
- destroy_async_data(&data->conn->resolve_async);
- *entry = data->conn->resolve_async.dns;
+ destroy_async_data(&data->state.async);
+ *entry = data->state.async.dns;
}
else {
/* poll for name lookup done with exponential backoff up to 250ms */
int ret_val = 0;
timediff_t milli;
timediff_t ms;
- struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
+ struct resdata *reslv = (struct resdata *)data->state.async.resolver;
#ifndef CURL_DISABLE_SOCKETPAIR
- struct thread_data *td = data->conn->resolve_async.tdata;
+ struct thread_data *td = data->state.async.tdata;
#else
(void)socks;
#endif
int port,
int *waitp)
{
- struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
+ struct resdata *reslv = (struct resdata *)data->state.async.resolver;
*waitp = 0; /* default to synchronous response */
{
struct addrinfo hints;
int pf = PF_INET;
- struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
+ struct resdata *reslv = (struct resdata *)data->state.async.resolver;
*waitp = 0; /* default to synchronous response */
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dnsp)
{
- struct connectdata *conn = data->conn;
CURLcode result;
struct dohdata *dohp = data->req.doh;
*dnsp = NULL; /* defaults to no response */
if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
!dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
- failf(data, "Could not DoH-resolve: %s", conn->resolve_async.hostname);
+ failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
Curl_freeaddrinfo(ai);
}
else {
- conn->resolve_async.dns = dns;
+ data->state.async.dns = dns;
*dnsp = dns;
result = CURLE_OK; /* address resolution OK */
}
}
#endif
+#ifdef CURLRES_ASYNCH
+ /* Clone the resolver handle, if present, for the new handle */
+ if(Curl_resolver_duphandle(outcurl,
+ &outcurl->state.async.resolver,
+ data->state.async.resolver))
+ goto fail;
+#endif
+
+#ifdef USE_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 */
+
Curl_initinfo(outcurl);
outcurl->magic = CURLEASY_MAGIC_NUMBER;
int status,
struct Curl_addrinfo *ai)
{
- struct connectdata *conn = data->conn;
struct Curl_dns_entry *dns = NULL;
CURLcode result = CURLE_OK;
- conn->resolve_async.status = status;
+ data->state.async.status = status;
if(CURL_ASYNC_SUCCESS == status) {
if(ai) {
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns = Curl_cache_addr(data, ai,
- conn->resolve_async.hostname, 0,
- conn->resolve_async.port);
+ data->state.async.hostname, 0,
+ data->state.async.port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
}
- conn->resolve_async.dns = dns;
+ data->state.async.dns = dns;
/* Set async.done TRUE last in this function since it may be used multi-
threaded and once this is TRUE the other thread may read fields from the
async struct */
- conn->resolve_async.done = TRUE;
+ data->state.async.done = TRUE;
/* IPv4: The input hostent struct will be freed by ares when we return from
this function */
Curl_set_in_callback(data, true);
st = data->set.resolver_start(
#ifdef USE_CURL_ASYNC
- conn->resolve_async.resolver,
+ data->state.async.resolver,
#else
NULL,
#endif
struct connectdata *conn = data->conn;
#ifdef USE_CURL_ASYNC
- if(conn->resolve_async.dns) {
- conn->dns_entry = conn->resolve_async.dns;
- conn->resolve_async.dns = NULL;
+ if(data->state.async.dns) {
+ conn->dns_entry = data->state.async.dns;
+ data->state.async.dns = NULL;
}
#endif
#ifdef USE_CURL_ASYNC
CURLcode Curl_resolver_error(struct Curl_easy *data)
{
- struct connectdata *conn = data->conn;
const char *host_or_proxy;
CURLcode result;
#ifndef CURL_DISABLE_PROXY
+ struct connectdata *conn = data->conn;
if(conn->bits.httpproxy) {
host_or_proxy = "proxy";
result = CURLE_COULDNT_RESOLVE_PROXY;
}
failf(data, "Could not resolve %s: %s", host_or_proxy,
- conn->resolve_async.hostname);
+ data->state.async.hostname);
return result;
}
if(dns) {
#ifdef CURLRES_ASYNCH
- conn->resolve_async.dns = dns;
- conn->resolve_async.done = TRUE;
+ data->state.async.dns = dns;
+ data->state.async.done = TRUE;
#endif
result = CURLE_OK;
infof(data, "Hostname '%s' was found in DNS cache", hostname);
if(dns) {
#ifdef CURLRES_ASYNCH
- conn->resolve_async.dns = dns;
- conn->resolve_async.done = TRUE;
+ data->state.async.dns = dns;
+ data->state.async.done = TRUE;
#endif
infof(data, "Hostname '%s' was found", sx->hostname);
sxstate(sx, data, CONNECT_RESOLVED);
if(dns) {
#ifdef CURLRES_ASYNCH
- conn->resolve_async.dns = dns;
- conn->resolve_async.done = TRUE;
+ data->state.async.dns = dns;
+ data->state.async.done = TRUE;
#endif
infof(data, "SOCKS5: hostname '%s' found", sx->hostname);
}
Curl_safefree(data->info.contenttype);
Curl_safefree(data->info.wouldredirect);
+ /* this destroys the channel and we cannot use it anymore after this */
+ Curl_resolver_cancel(data);
+ Curl_resolver_cleanup(data->state.async.resolver);
+
data_priority_cleanup(data);
/* No longer a dirty share, if it exists */
data->magic = CURLEASY_MAGIC_NUMBER;
+ result = Curl_resolver_init(data, &data->state.async.resolver);
+ if(result) {
+ DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
+ free(data);
+ return result;
+ }
+
result = Curl_init_userdefined(data);
if(!result) {
Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
}
if(result) {
+ Curl_resolver_cleanup(data->state.async.resolver);
Curl_dyn_free(&data->state.headerb);
Curl_freeset(data);
free(data);
Curl_conn_cf_discard_all(data, conn, (int)i);
}
- Curl_resolver_cleanup(conn->resolve_async.resolver);
Curl_free_idnconverted_hostname(&conn->host);
Curl_free_idnconverted_hostname(&conn->conn_to_host);
#ifndef CURL_DISABLE_PROXY
conn->handler->disconnect(data, conn, dead_connection);
conn_shutdown(data);
- Curl_resolver_cancel(data);
/* detach it again */
Curl_detach_connection(data);
goto out;
}
- result = Curl_resolver_init(data, &conn->resolve_async.resolver);
- if(result) {
- DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
- goto out;
- }
-
Curl_attach_connection(data, conn);
-
-#ifdef USE_ARES
- result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
- if(result && result != CURLE_NOT_BUILT_IN)
- goto out;
-
- result = Curl_set_dns_interface(data,
- data->set.str[STRING_DNS_INTERFACE]);
- if(result && result != CURLE_NOT_BUILT_IN)
- goto out;
-
- result = Curl_set_dns_local_ip4(data,
- data->set.str[STRING_DNS_LOCAL_IP4]);
- if(result && result != CURLE_NOT_BUILT_IN)
- goto out;
-
- result = Curl_set_dns_local_ip6(data,
- data->set.str[STRING_DNS_LOCAL_IP6]);
- if(result && result != CURLE_NOT_BUILT_IN)
- goto out;
-#endif /* USE_ARES */
-
result = Curl_conncache_add_conn(data);
if(result)
goto out;
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;
-#ifdef USE_CURL_ASYNC
- struct Curl_async resolve_async; /* asynchronous name resolver data */
-#endif
/* 'remote_addr' is the particular IP we connected to. it is owned, set
* and NULLed by the connected socket filter (if there is one). */
#endif
struct auth authhost; /* auth details for host */
struct auth authproxy; /* auth details for proxy */
+#ifdef USE_CURL_ASYNC
+ struct Curl_async async; /* asynchronous name resolver data */
+#endif
#if defined(USE_OPENSSL)
/* void instead of ENGINE to avoid bleeding OpenSSL into this header */
bool imported_native_ca = false;
bool imported_ca_info_blob = false;
+ CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
+ ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
if(!store)
return CURLE_OUT_OF_MEMORY;