mirror of
https://github.com/curl/curl.git
synced 2026-04-14 22:41:40 +03:00
dnscache: own source file, improvements
- Rename `Curl_resolv_unlink()` to `Curl_dns_entry_unlink()`. - Change `Curl_dnscache_get()` to return CURLcode result. Returns now `CURLE_COULDNT_RESOLVE_HOST` for "negative" cache entries. - Add `Curl_dnscache_add_negative()` to put a "negative" entry into the cache. Closes #20864
This commit is contained in:
parent
b0f6e9a3d7
commit
96d5b5c688
35 changed files with 1648 additions and 1413 deletions
176
lib/asyn-thrdd.c
176
lib/asyn-thrdd.c
|
|
@ -101,12 +101,12 @@ void Curl_async_global_cleanup(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void async_thrdd_destroy(struct Curl_easy *data);
|
||||
static void async_thrdd_shutdown(struct Curl_easy *data);
|
||||
|
||||
CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl)
|
||||
CURLcode Curl_async_get_impl(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async,
|
||||
void **impl)
|
||||
{
|
||||
(void)data;
|
||||
(void)async;
|
||||
*impl = NULL;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
|
@ -144,7 +144,7 @@ static void addr_ctx_unlink(struct async_thrdd_addr_ctx **paddr_ctx,
|
|||
/* Initialize context for threaded resolver */
|
||||
static struct async_thrdd_addr_ctx *
|
||||
addr_ctx_create(struct Curl_easy *data,
|
||||
const char *hostname, int port,
|
||||
struct Curl_resolv_async *async,
|
||||
const struct addrinfo *hints)
|
||||
{
|
||||
struct async_thrdd_addr_ctx *addr_ctx = curlx_calloc(1, sizeof(*addr_ctx));
|
||||
|
|
@ -152,7 +152,7 @@ addr_ctx_create(struct Curl_easy *data,
|
|||
return NULL;
|
||||
|
||||
addr_ctx->thread_hnd = curl_thread_t_null;
|
||||
addr_ctx->port = port;
|
||||
addr_ctx->port = async->port;
|
||||
addr_ctx->ref_count = 1;
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
|
|
@ -177,7 +177,7 @@ addr_ctx_create(struct Curl_easy *data,
|
|||
/* Copying hostname string because original can be destroyed by parent
|
||||
* thread during gethostbyname execution.
|
||||
*/
|
||||
addr_ctx->hostname = curlx_strdup(hostname);
|
||||
addr_ctx->hostname = curlx_strdup(async->hostname);
|
||||
if(!addr_ctx->hostname)
|
||||
goto err_exit;
|
||||
|
||||
|
|
@ -287,9 +287,10 @@ static CURL_THREAD_RETURN_T CURL_STDCALL gethostbyname_thread(void *arg)
|
|||
/*
|
||||
* async_thrdd_destroy() cleans up async resolver data and thread handle.
|
||||
*/
|
||||
static void async_thrdd_destroy(struct Curl_easy *data)
|
||||
static void async_thrdd_destroy(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
struct async_thrdd_ctx *thrdd = &async->thrdd;
|
||||
struct async_thrdd_addr_ctx *addr = thrdd->addr;
|
||||
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
|
|
@ -333,7 +334,7 @@ static void async_thrdd_rr_done(void *user_data, ares_status_t status,
|
|||
const ares_dns_record_t *dnsrec)
|
||||
{
|
||||
struct Curl_easy *data = user_data;
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async->thrdd;
|
||||
|
||||
(void)timeouts;
|
||||
thrdd->rr.done = TRUE;
|
||||
|
|
@ -344,7 +345,7 @@ static void async_thrdd_rr_done(void *user_data, ares_status_t status,
|
|||
|
||||
static CURLcode async_rr_start(struct Curl_easy *data, int port)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async->thrdd;
|
||||
int status;
|
||||
char *rrname = NULL;
|
||||
|
||||
|
|
@ -390,38 +391,21 @@ static CURLcode async_rr_start(struct Curl_easy *data, int port)
|
|||
* Returns FALSE in case of failure, otherwise TRUE.
|
||||
*/
|
||||
static bool async_thrdd_init(struct Curl_easy *data,
|
||||
const char *hostname, int port, int ip_version,
|
||||
struct Curl_resolv_async *async,
|
||||
const struct addrinfo *hints)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
struct async_thrdd_ctx *thrdd = &async->thrdd;
|
||||
struct async_thrdd_addr_ctx *addr_ctx;
|
||||
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
int err = ENOMEM;
|
||||
|
||||
if(thrdd->addr
|
||||
DEBUGASSERT(!thrdd->addr);
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
|| thrdd->rr.channel
|
||||
DEBUGASSERT(!thrdd->rr.channel);
|
||||
#endif
|
||||
) {
|
||||
CURL_TRC_DNS(data, "starting new resolve, with previous not cleaned up");
|
||||
async_thrdd_destroy(data);
|
||||
DEBUGASSERT(!thrdd->addr);
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
DEBUGASSERT(!thrdd->rr.channel);
|
||||
#endif
|
||||
}
|
||||
|
||||
data->state.async.dns = NULL;
|
||||
data->state.async.done = FALSE;
|
||||
data->state.async.port = port;
|
||||
data->state.async.ip_version = ip_version;
|
||||
curlx_free(data->state.async.hostname);
|
||||
data->state.async.hostname = curlx_strdup(hostname);
|
||||
if(!data->state.async.hostname)
|
||||
goto err_exit;
|
||||
|
||||
addr_ctx = addr_ctx_create(data, hostname, port, hints);
|
||||
addr_ctx = addr_ctx_create(data, async, hints);
|
||||
if(!addr_ctx)
|
||||
goto err_exit;
|
||||
thrdd->addr = addr_ctx;
|
||||
|
|
@ -445,22 +429,24 @@ static bool async_thrdd_init(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
if(async_rr_start(data, port))
|
||||
if(async_rr_start(data, async->port))
|
||||
infof(data, "Failed HTTPS RR operation");
|
||||
#endif
|
||||
CURL_TRC_DNS(data, "resolve thread started for of %s:%d", hostname, port);
|
||||
CURL_TRC_DNS(data, "resolve thread started for of %s:%d",
|
||||
async->hostname, async->port);
|
||||
return TRUE;
|
||||
|
||||
err_exit:
|
||||
CURL_TRC_DNS(data, "resolve thread failed init: %d", err);
|
||||
async_thrdd_destroy(data);
|
||||
async_thrdd_destroy(data, async);
|
||||
errno = err;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void async_thrdd_shutdown(struct Curl_easy *data)
|
||||
static void async_thrdd_shutdown(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
struct async_thrdd_ctx *thrdd = &async->thrdd;
|
||||
struct async_thrdd_addr_ctx *addr_ctx = thrdd->addr;
|
||||
curl_bit done;
|
||||
|
||||
|
|
@ -491,15 +477,16 @@ static void async_thrdd_shutdown(struct Curl_easy *data)
|
|||
* 'entry' may be NULL and then no data is returned
|
||||
*/
|
||||
static CURLcode asyn_thrdd_await(struct Curl_easy *data,
|
||||
struct async_thrdd_addr_ctx *addr_ctx,
|
||||
struct Curl_resolv_async *async,
|
||||
struct Curl_dns_entry **entry)
|
||||
{
|
||||
struct async_thrdd_addr_ctx *addr_ctx = async->thrdd.addr;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(addr_ctx->thread_hnd != curl_thread_t_null) {
|
||||
if(addr_ctx && (addr_ctx->thread_hnd != curl_thread_t_null)) {
|
||||
/* not interested in result? cancel, if still running... */
|
||||
if(!entry)
|
||||
async_thrdd_shutdown(data);
|
||||
async_thrdd_shutdown(data, async);
|
||||
|
||||
if(addr_ctx->thread_hnd != curl_thread_t_null) {
|
||||
CURL_TRC_DNS(data, "resolve, wait for thread to finish");
|
||||
|
|
@ -508,14 +495,13 @@ static CURLcode asyn_thrdd_await(struct Curl_easy *data,
|
|||
}
|
||||
}
|
||||
|
||||
if(entry)
|
||||
result = Curl_async_is_resolved(data, entry);
|
||||
if(entry) {
|
||||
result = Curl_async_take_result(data, async, entry);
|
||||
if(result == CURLE_AGAIN)
|
||||
result = CURLE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
data->state.async.done = TRUE;
|
||||
if(entry)
|
||||
*entry = data->state.async.dns;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -523,19 +509,19 @@ static CURLcode asyn_thrdd_await(struct Curl_easy *data,
|
|||
* Until we gain a way to signal the resolver threads to stop early, we must
|
||||
* wait for them and ignore their results.
|
||||
*/
|
||||
void Curl_async_thrdd_shutdown(struct Curl_easy *data)
|
||||
void Curl_async_thrdd_shutdown(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
{
|
||||
async_thrdd_shutdown(data);
|
||||
async_thrdd_shutdown(data, async);
|
||||
}
|
||||
|
||||
void Curl_async_thrdd_destroy(struct Curl_easy *data)
|
||||
void Curl_async_thrdd_destroy(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
|
||||
if(thrdd->addr && !data->set.quick_exit) {
|
||||
(void)asyn_thrdd_await(data, thrdd->addr, NULL);
|
||||
if(!data->set.quick_exit) {
|
||||
(void)asyn_thrdd_await(data, async, NULL);
|
||||
}
|
||||
async_thrdd_destroy(data);
|
||||
async_thrdd_destroy(data, async);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -552,34 +538,26 @@ void Curl_async_thrdd_destroy(struct Curl_easy *data)
|
|||
* This is the version for resolves-in-a-thread.
|
||||
*/
|
||||
CURLcode Curl_async_await(struct Curl_easy *data,
|
||||
struct Curl_dns_entry **dns)
|
||||
struct Curl_resolv_async *async,
|
||||
struct Curl_dns_entry **entry)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
if(thrdd->addr)
|
||||
return asyn_thrdd_await(data, thrdd->addr, dns);
|
||||
return CURLE_FAILED_INIT;
|
||||
return asyn_thrdd_await(data, async, entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_async_is_resolved() is called repeatedly to check if a previous
|
||||
* Curl_async_take_result() is called repeatedly to check if a previous
|
||||
* name resolve request has completed. It should also make sure to time-out if
|
||||
* the operation seems to take too long.
|
||||
*/
|
||||
CURLcode Curl_async_is_resolved(struct Curl_easy *data,
|
||||
struct Curl_dns_entry **dns)
|
||||
CURLcode Curl_async_take_result(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async,
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
struct async_thrdd_ctx *thrdd = &async->thrdd;
|
||||
curl_bit done = FALSE;
|
||||
|
||||
DEBUGASSERT(dns);
|
||||
*dns = NULL;
|
||||
|
||||
if(data->state.async.done) {
|
||||
*dns = data->state.async.dns;
|
||||
CURL_TRC_DNS(data, "threaded: is_resolved(), already done, dns=%sfound",
|
||||
*dns ? "" : "not ");
|
||||
return CURLE_OK;
|
||||
}
|
||||
DEBUGASSERT(pdns);
|
||||
*pdns = NULL;
|
||||
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
/* best effort, ignore errors */
|
||||
|
|
@ -598,16 +576,14 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data,
|
|||
if(done) {
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
data->state.async.done = TRUE;
|
||||
Curl_resolv_unlink(data, &data->state.async.dns);
|
||||
Curl_expire_done(data, EXPIRE_ASYNC_NAME);
|
||||
|
||||
if(thrdd->addr->res) {
|
||||
data->state.async.dns =
|
||||
struct Curl_dns_entry *dns =
|
||||
Curl_dnscache_mk_entry(data, &thrdd->addr->res,
|
||||
data->state.async.hostname, 0,
|
||||
data->state.async.port, FALSE);
|
||||
if(!data->state.async.dns)
|
||||
async->hostname, async->port,
|
||||
async->ip_version);
|
||||
if(!dns)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
|
|
@ -619,22 +595,21 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data,
|
|||
if(!lhrr)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
else
|
||||
data->state.async.dns->hinfo = lhrr;
|
||||
dns->hinfo = lhrr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(!result && data->state.async.dns)
|
||||
result = Curl_dnscache_add(data, data->state.async.dns);
|
||||
if(!result && dns) {
|
||||
result = Curl_dnscache_add(data, dns);
|
||||
*pdns = dns;
|
||||
}
|
||||
}
|
||||
|
||||
if(!result && !data->state.async.dns)
|
||||
if(!result && !*pdns)
|
||||
result = Curl_resolver_error(data, NULL);
|
||||
if(result)
|
||||
Curl_resolv_unlink(data, &data->state.async.dns);
|
||||
*dns = data->state.async.dns;
|
||||
CURL_TRC_DNS(data, "is_resolved() result=%d, dns=%sfound",
|
||||
result, *dns ? "" : "not ");
|
||||
async_thrdd_shutdown(data);
|
||||
result, *pdns ? "" : "not ");
|
||||
async_thrdd_shutdown(data, async);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
|
|
@ -657,13 +632,13 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data,
|
|||
|
||||
thrdd->addr->interval_end = elapsed + thrdd->addr->poll_interval;
|
||||
Curl_expire(data, thrdd->addr->poll_interval, EXPIRE_ASYNC_NAME);
|
||||
return CURLE_OK;
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async->thrdd;
|
||||
CURLcode result = CURLE_OK;
|
||||
curl_bit thrd_done;
|
||||
|
||||
|
|
@ -711,13 +686,13 @@ CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
|
|||
/*
|
||||
* Curl_async_getaddrinfo() - for platforms without getaddrinfo
|
||||
*/
|
||||
CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, const char *hostname,
|
||||
int port, int ip_version)
|
||||
CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
{
|
||||
(void)ip_version;
|
||||
|
||||
/* fire up a new resolver thread! */
|
||||
if(async_thrdd_init(data, hostname, port, ip_version, NULL)) {
|
||||
if(async_thrdd_init(data, async, NULL)) {
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
|
@ -730,23 +705,22 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, const char *hostname,
|
|||
/*
|
||||
* Curl_async_getaddrinfo() - for getaddrinfo
|
||||
*/
|
||||
CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, const char *hostname,
|
||||
int port, int ip_version)
|
||||
CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
int pf = PF_INET;
|
||||
|
||||
CURL_TRC_DNS(data, "init threaded resolve of %s:%d", hostname, port);
|
||||
CURL_TRC_DNS(data, "init threaded resolve of %s:%d",
|
||||
async->hostname, async->port);
|
||||
#ifdef CURLRES_IPV6
|
||||
if((ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
|
||||
if((async->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
|
||||
/* The stack seems to be IPv6-enabled */
|
||||
if(ip_version == CURL_IPRESOLVE_V6)
|
||||
if(async->ip_version == CURL_IPRESOLVE_V6)
|
||||
pf = PF_INET6;
|
||||
else
|
||||
pf = PF_UNSPEC;
|
||||
}
|
||||
#else
|
||||
(void)ip_version;
|
||||
#endif /* CURLRES_IPV6 */
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
|
|
@ -756,7 +730,7 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, const char *hostname,
|
|||
SOCK_STREAM : SOCK_DGRAM;
|
||||
|
||||
/* fire up a new resolver thread! */
|
||||
if(async_thrdd_init(data, hostname, port, ip_version, &hints))
|
||||
if(async_thrdd_init(data, async, &hints))
|
||||
return CURLE_OK;
|
||||
|
||||
failf(data, "getaddrinfo() thread failed to start");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue