← Commit list

3ddbd522b9

Stefan Eissing
Stefan Eissing
2026-09-11
SUCCESS Duration: 423s

Subject

dnscache/conncache tweaks

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/conncache.c+2 -3
@@ -646,11 +646,11 @@ static bool cpool_foreach(struct Curl_easy *data,
* Return TRUE if idle connection kept in pool, FALSE if closed.
*/
bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
- struct connectdata *conn)
+ struct connectdata *conn,
+ const struct curltime *pnow)
{
struct cpool *cpool = cpool_get_instance(data);
struct connectdata *oldest_idle = NULL;
- const struct curltime *pnow = NULL;
struct Curl_easy *admin;
unsigned int maxconnects;
bool kept = TRUE;
@@ -672,7 +672,6 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
}
/* remember times, connection had been used just before */
- pnow = Curl_pgrs_now(data);
conn->lastchecked_ms = conn->lastupkeep_ms = conn->lastused_ms =
curlx_ptimediff_ms(pnow, &conn->created);
if(cpool && maxconnects) {
lib/conncache.h+2 -1
@@ -137,7 +137,8 @@ bool Curl_cpool_find(struct Curl_easy *data,
* Return TRUE if idle connection kept in pool, FALSE if closed.
*/
bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
- struct connectdata *conn);
+ struct connectdata *conn,
+ const struct curltime *pnow);
/**
* Scans the connection pool for half-open/dead
lib/multi.c+3 -2
@@ -629,6 +629,7 @@ static void multi_done_locked(struct connectdata *conn,
void *userdata)
{
struct multi_done_ctx *mdctx = userdata;
+ const struct curltime *pnow = Curl_pgrs_now(data);
Curl_detach_connection(data);
@@ -642,7 +643,7 @@ static void multi_done_locked(struct connectdata *conn,
data->state.done = TRUE; /* called now! */
- Curl_dnscache_prune(data);
+ Curl_dnscache_prune(data, pnow);
if(multi_conn_should_close(conn, data, (bool)mdctx->premature)) {
CURL_TRC_M(data, "multi_done, terminating conn #%" FMT_OFF_T " to %s:%u, "
@@ -663,7 +664,7 @@ static void multi_done_locked(struct connectdata *conn,
}
else {
/* the connection is no longer in use by any transfer */
- if(Curl_cpool_conn_now_idle(data, conn)) {
+ if(Curl_cpool_conn_now_idle(data, conn, pnow)) {
/* connection kept in the cpool */
infof(data, "Connection #%" FMT_OFF_T " to host %s:%u left intact",
conn->connection_id, conn->origin->user_hostname,
lib/vdns/dnscache.c+67 -51
@@ -56,7 +56,7 @@
#include "curlx/strcopy.h"
#include "curlx/strparse.h"
-#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */
+#define MAX_HOSTCACHE_LEN (255 + 3) /* max FQDN + type + port */
#define MAX_DNS_CACHE_SIZE 29999
@@ -83,7 +83,7 @@ static void dnsc_str2id(struct dnsc_id *pid, char type,
}
struct dnsc_key {
- char data[MAX_HOSTCACHE_LEN];
+ uint8_t data[MAX_HOSTCACHE_LEN];
size_t len;
};
@@ -94,14 +94,14 @@ struct dnsc_key {
static void dnsc_id2key(struct dnsc_key *key, struct dnsc_id *id)
{
size_t namelen = curlx_strlen(&id->name);
- if(namelen > (sizeof(key->data) - 8))
- namelen = sizeof(key->data) - 8;
+ if(namelen > (sizeof(key->data) - 3))
+ namelen = sizeof(key->data) - 3;
/* store and lower case the name */
key->data[0] = id->type;
- Curl_strntolower(key->data + 1, curlx_str(&id->name), namelen);
- /* include the terminating 0 in key length */
- key->len = namelen + 2 +
- curl_msnprintf(&key->data[namelen + 1], 7, ":%u", id->port);
+ key->data[1] = (uint8_t)((id->port >> 8) & 0xff);
+ key->data[2] = (uint8_t)(id->port & 0xff);
+ Curl_strntolower((char *)key->data + 3, curlx_str(&id->name), namelen);
+ key->len = namelen + 3;
}
static void dnscache_entry_free(struct Curl_dns_entry *dns)
@@ -114,7 +114,7 @@ static void dnscache_entry_free(struct Curl_dns_entry *dns)
}
struct dnscache_prune_data {
- struct curltime now;
+ const struct curltime *pnow;
timediff_t oldest_ms; /* oldest time in cache not pruned. */
timediff_t max_age_ms;
};
@@ -131,15 +131,27 @@ static int dnscache_entry_is_stale(void *datap, void *hc)
struct dnscache_prune_data *prune = (struct dnscache_prune_data *)datap;
struct Curl_dns_entry *dns = (struct Curl_dns_entry *)hc;
- if(dns->timestamp.tv_sec || dns->timestamp.tv_usec) {
+ if(!dns->permanent) {
/* get age in milliseconds */
- timediff_t age = curlx_ptimediff_ms(&prune->now, &dns->timestamp);
- if(!dns->addr)
- age *= 2; /* negative entries age twice as fast */
- if(age >= prune->max_age_ms)
+ timediff_t age_ms = curlx_ptimediff_ms(prune->pnow, &dns->added);
+ switch(dns->type) {
+ case CURL_DNST_ADDR:
+ if(!dns->addr)
+ age_ms *= 2; /* negative entries age twice as fast */
+ break;
+#ifdef USE_HTTPSRR
+ case CURL_DNST_HTTPS:
+ if(!dns->hinfo)
+ age_ms *= 2; /* negative entries age twice as fast */
+ break;
+#endif
+ default:
+ break;
+ }
+ if(age_ms >= prune->max_age_ms)
return TRUE;
- if(age > prune->oldest_ms)
- prune->oldest_ms = age;
+ if(age_ms > prune->oldest_ms)
+ prune->oldest_ms = age_ms;
}
return FALSE;
}
@@ -150,12 +162,12 @@ static int dnscache_entry_is_stale(void *datap, void *hc)
*/
static timediff_t dnscache_prune(struct Curl_hash *hostcache,
timediff_t cache_timeout_ms,
- struct curltime now)
+ const struct curltime *pnow)
{
struct dnscache_prune_data user;
user.max_age_ms = cache_timeout_ms;
- user.now = now;
+ user.pnow = pnow;
user.oldest_ms = 0;
Curl_hash_clean_with_criterium(hostcache,
@@ -192,7 +204,7 @@ static void dnscache_unlock(struct Curl_easy *data,
* Library-wide function for pruning the DNS cache. This function takes and
* returns the appropriate locks.
*/
-void Curl_dnscache_prune(struct Curl_easy *data)
+void Curl_dnscache_prune(struct Curl_easy *data, const struct curltime *pnow)
{
struct Curl_dnscache *dnscache = dnscache_get(data);
/* the timeout may be set -1 (forever) */
@@ -207,7 +219,7 @@ void Curl_dnscache_prune(struct Curl_easy *data)
do {
/* Remove outdated and unused entries from the hostcache */
timediff_t oldest_ms =
- dnscache_prune(&dnscache->entries, timeout_ms, *Curl_pgrs_now(data));
+ dnscache_prune(&dnscache->entries, timeout_ms, pnow);
if(Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE)
/* prune the ones over half this age */
@@ -233,11 +245,11 @@ void Curl_dnscache_clear(struct Curl_easy *data)
}
/* lookup address, returns entry if found and not stale */
-static CURLcode fetch_addr(struct Curl_easy *data,
- struct Curl_dnscache *dnscache,
- uint8_t dns_queries,
- struct Curl_peer *peer,
- struct Curl_dns_entry **pdns)
+static CURLcode fetch_entry(struct Curl_easy *data,
+ struct Curl_dnscache *dnscache,
+ uint8_t dns_queries,
+ struct Curl_peer *peer,
+ struct Curl_dns_entry **pdns)
{
struct Curl_dns_entry *dns = NULL;
struct dnsc_id id;
@@ -272,7 +284,7 @@ static CURLcode fetch_addr(struct Curl_easy *data,
/* See whether the returned entry is stale. Done before we release lock */
struct dnscache_prune_data user;
- user.now = *Curl_pgrs_now(data);
+ user.pnow = Curl_pgrs_now(data);
user.max_age_ms = data->set.dns_cache_timeout_ms;
user.oldest_ms = 0;
@@ -331,7 +343,7 @@ CURLcode Curl_dnscache_get(struct Curl_easy *data,
CURLcode result = CURLE_OK;
dnscache_lock(data, dnscache);
- result = fetch_addr(data, dnscache, dns_queries, peer, &dns);
+ result = fetch_entry(data, dnscache, dns_queries, peer, &dns);
if(!result && dns)
dns->refcount++; /* we pass out a reference */
else if(result) {
@@ -438,12 +450,14 @@ static bool dnscache_ai_has_family(struct Curl_addrinfo *ai, int ai_family)
return FALSE;
}
-static struct Curl_dns_entry *dnsc_entry_create(struct Curl_easy *data,
- struct dnsc_id *pid,
+static struct Curl_dns_entry *dnsc_entry_create(struct dnsc_id *pid,
bool permanent)
{
struct Curl_dns_entry *dns = NULL;
+ if(curlx_strlen(&pid->name) > UINT16_MAX)
+ goto out;
+
/* Create a new cache entry, struct already has the hostname NUL */
dns = curlx_calloc(1, sizeof(struct Curl_dns_entry) +
curlx_strlen(&pid->name));
@@ -451,18 +465,11 @@ static struct Curl_dns_entry *dnsc_entry_create(struct Curl_easy *data,
goto out;
dns->refcount = 1; /* the cache has the first reference */
- dns->hostlen = curlx_strlen(&pid->name);
dns->port = pid->port;
+ dns->hostlen = (uint16_t)curlx_strlen(&pid->name);
if(dns->hostlen)
memcpy(dns->hostname, curlx_str(&pid->name), dns->hostlen);
-
- if(permanent) {
- dns->timestamp.tv_sec = 0; /* an entry that never goes stale */
- dns->timestamp.tv_usec = 0; /* an entry that never goes stale */
- }
- else {
- dns->timestamp = *Curl_pgrs_now(data);
- }
+ dns->permanent = permanent;
out:
return dns;
@@ -545,7 +552,7 @@ struct Curl_dns_entry *Curl_dnsc_mk_addr(struct Curl_easy *data,
struct Curl_dns_entry *dns;
dnsc_peer2id(&id, CURL_DNST_ADDR, peer);
- dns = dnsc_entry_create(data, &id, FALSE);
+ dns = dnsc_entry_create(&id, FALSE);
dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr, NULL);
return dns;
}
@@ -560,11 +567,20 @@ struct Curl_dns_entry *Curl_dnsc_mk_addr2(struct Curl_easy *data,
struct Curl_dns_entry *dns;
dnsc_peer2id(&id, CURL_DNST_ADDR, peer);
- dns = dnsc_entry_create(data, &id, FALSE);
+ dns = dnsc_entry_create(&id, FALSE);
dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr1, paddr2);
return dns;
}
+static struct Curl_dns_entry *dnsc_add_entry(struct Curl_easy *data,
+ struct Curl_dnscache *dnscache,
+ struct dnsc_key *key,
+ struct Curl_dns_entry *entry)
+{
+ entry->added = *Curl_pgrs_now(data);
+ return Curl_hash_add(&dnscache->entries, key->data, key->len, entry);
+}
+
#ifdef USE_HTTPSRR
static struct Curl_dns_entry *dnsc_entry_assign_https(
struct Curl_dns_entry *dns,
@@ -601,8 +617,9 @@ struct Curl_dns_entry *Curl_dnsc_mk_https(struct Curl_easy *data,
struct dnsc_id id;
struct Curl_dns_entry *dns;
+ (void)data;
dnsc_peer2id(&id, CURL_DNST_HTTPS, peer);
- dns = dnsc_entry_create(data, &id, FALSE);
+ dns = dnsc_entry_create(&id, FALSE);
dns = dnsc_entry_assign_https(dns, phinfo);
return dns;
}
@@ -610,20 +627,19 @@ struct Curl_dns_entry *Curl_dnsc_mk_https(struct Curl_easy *data,
static struct Curl_dns_entry *dnsc_add_https(struct Curl_easy *data,
struct Curl_dnscache *dnscache,
struct Curl_https_rrinfo **phinfo,
- struct dnsc_id *id,
- bool permanent)
+ struct dnsc_id *id)
{
struct Curl_dns_entry *dns, *dns2;
struct dnsc_key key;
- dns = dnsc_entry_create(data, id, permanent);
+ dns = dnsc_entry_create(id, FALSE);
dns = dnsc_entry_assign_https(dns, phinfo);
if(!dns)
return NULL;
/* Store the resolved data in our DNS cache. */
dnsc_id2key(&key, id);
- dns2 = Curl_hash_add(&dnscache->entries, key.data, key.len, (void *)dns);
+ dns2 = dnsc_add_entry(data, dnscache, &key, dns);
if(!dns2) {
dnscache_entry_free(dns);
return NULL;
@@ -646,13 +662,13 @@ static struct Curl_dns_entry *dnsc_add_addr(struct Curl_easy *data,
struct Curl_dns_entry *dns;
struct Curl_dns_entry *dns2;
- dns = dnsc_entry_create(data, id, permanent);
+ dns = dnsc_entry_create(id, permanent);
dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr, NULL);
if(!dns)
return NULL;
/* Store the resolved data in our DNS cache. */
- dns2 = Curl_hash_add(&dnscache->entries, key->data, key->len, (void *)dns);
+ dns2 = dnsc_add_entry(data, dnscache, key, dns);
if(!dns2) {
dnscache_entry_free(dns);
return NULL;
@@ -675,14 +691,14 @@ static struct Curl_dns_entry *dnsc_add_peer_addr(
struct Curl_dns_entry *dns2;
struct dnsc_key key;
- dns = dnsc_entry_create(data, id, permanent);
+ dns = dnsc_entry_create(id, permanent);
dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr, NULL);
if(!dns)
return NULL;
/* Store the resolved data in our DNS cache. */
dnsc_id2key(&key, id);
- dns2 = Curl_hash_add(&dnscache->entries, key.data, key.len, (void *)dns);
+ dns2 = dnsc_add_entry(data, dnscache, &key, dns);
if(!dns2) {
dnscache_entry_free(dns);
return NULL;
@@ -712,7 +728,7 @@ CURLcode Curl_dnscache_add(struct Curl_easy *data,
/* Store the resolved data in our DNS cache and up ref count */
dnscache_lock(data, dnscache);
- if(!Curl_hash_add(&dnscache->entries, key.data, key.len, (void *)entry)) {
+ if(!dnsc_add_entry(data, dnscache, &key, entry)) {
dnscache_unlock(data, dnscache);
return CURLE_OUT_OF_MEMORY;
}
@@ -749,7 +765,7 @@ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data,
#ifdef USE_HTTPSRR
else if(dns_queries == CURL_DNSQ_HTTPS) {
dnsc_peer2id(&id, CURL_DNST_HTTPS, peer);
- dns = dnsc_add_https(data, dnscache, NULL, &id, FALSE);
+ dns = dnsc_add_https(data, dnscache, NULL, &id);
if(!dns)
result = CURLE_OUT_OF_MEMORY;
}
lib/vdns/dnscache.h+6 -8
@@ -46,16 +46,14 @@ struct Curl_dns_entry {
#ifdef USE_HTTPSRR
struct Curl_https_rrinfo *hinfo;
#endif
- /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (does not time out) */
- struct curltime timestamp;
- size_t hostlen;
- /* reference counter, entry is freed on reaching 0 */
- uint32_t refcount;
- /* hostname port number that resolved to addr. */
- uint16_t port;
+ struct curltime added; /* time this entry was added to the cache */
+ uint32_t refcount; /* reference counter, entry is freed on reaching 0 */
+ uint16_t hostlen; /* length of hostname */
+ uint16_t port; /* host port */
char type; /* CURL_DNST_ADDR or CURL_DNST_HTTPS */
uint8_t dns_queries; /* CURL_DNSQ_* type of queries performed for this */
uint8_t dns_responses; /* CURL_DNSQ_* type this entry has responses for */
+ BIT(permanent); /* entry is permanent, e.g. does not time out */
/* hostname that resolved to addr. may be NULL (Unix domain sockets). */
char hostname[1];
};
@@ -101,7 +99,7 @@ void Curl_dnscache_init(struct Curl_dnscache *dns, size_t size);
void Curl_dnscache_destroy(struct Curl_dnscache *dns);
/* prune old entries from the DNS cache */
-void Curl_dnscache_prune(struct Curl_easy *data);
+void Curl_dnscache_prune(struct Curl_easy *data, const struct curltime *pnow);
/* clear the DNS cache */
void Curl_dnscache_clear(struct Curl_easy *data);
tests/unit/unit1607.c+30 -12
@@ -23,6 +23,7 @@
***************************************************************************/
#include "unitcheck.h"
#include "urldata.h"
+#include "strcase.h"
#include "curl_addrinfo.h"
static CURLcode t1607_setup(void)
@@ -32,6 +33,27 @@ static CURLcode t1607_setup(void)
return result;
}
+struct t1607_key {
+ uint8_t data[255 + 3];
+ size_t len;
+};
+
+static void t1607_create_key(struct t1607_key *key,
+ const char *hostname,
+ uint16_t port,
+ uint8_t type)
+{
+ size_t namelen = strlen(hostname);
+ if(namelen > (sizeof(key->data) - 3))
+ namelen = sizeof(key->data) - 3;
+ /* store and lower case the name */
+ key->data[0] = type;
+ key->data[1] = (uint8_t)((port >> 8) & 0xff);
+ key->data[2] = (uint8_t)(port & 0xff);
+ Curl_strntolower((char *)key->data + 3, hostname, namelen);
+ key->len = namelen + 3;
+}
+
static CURLcode test_unit1607(const char *arg)
{
/* In builds without IPv6 support CURLOPT_RESOLVE should skip over those
@@ -108,7 +130,7 @@ static CURLcode test_unit1607(const char *arg)
size_t addressnum = CURL_ARRAYSIZE(tests[i].address);
struct Curl_addrinfo *addr;
struct Curl_dns_entry *dns;
- void *entry_id;
+ struct t1607_key entry_id;
bool problem = FALSE;
easy = curl_easy_init();
if(!easy)
@@ -127,13 +149,9 @@ static CURLcode test_unit1607(const char *arg)
Curl_loadhostpairs(easy);
- entry_id = (void *)curl_maprintf("%c%s:%u", CURL_DNST_ADDR,
- tests[i].host, tests[i].port);
- if(!entry_id)
- goto error;
+ t1607_create_key(&entry_id, tests[i].host, tests[i].port, CURL_DNST_ADDR);
dns = Curl_hash_pick(&multi->dnscache.entries,
- entry_id, strlen(entry_id) + 1);
- curlx_safefree(entry_id);
+ entry_id.data, entry_id.len);
addr = dns ? dns->addr : NULL;
@@ -190,18 +208,18 @@ static CURLcode test_unit1607(const char *arg)
break;
}
- if(dns->timestamp.tv_sec && tests[i].permanent) {
+ if(!dns->permanent && tests[i].permanent) {
curl_mfprintf(stderr,
- "%s:%d tests[%zu] failed. the timestamp is not zero "
+ "%s:%d tests[%zu] failed. the permanent bit is not set "
"but tests[%zu].permanent is TRUE\n",
__FILE__, __LINE__, i, i);
problem = TRUE;
break;
}
- if(dns->timestamp.tv_sec == 0 && !tests[i].permanent) {
- curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the timestamp is zero "
- "but tests[%zu].permanent is FALSE\n",
+ if(dns->permanent && !tests[i].permanent) {
+ curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the permanent bit "
+ "is set but tests[%zu].permanent is FALSE\n",
__FILE__, __LINE__, i, i);
problem = TRUE;
break;