From 657aae79c04c9440b656c86daf11b38dc553d718 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 18 Apr 2025 11:03:29 +0200 Subject: [PATCH] lib: add meta_hash to connection, eliminate hash_offt With a meta_hash at each connection (similar to easy handle, let multi_ev.c store its pollsets as meta data, no longer needing its own hashes. This eliminates the last use of Curl_hash_offt. Remove it. Closes #17095 --- docs/internals/HASH.md | 37 ------ docs/internals/UINT_SETS.md | 3 - lib/Makefile.inc | 4 +- lib/doh.c | 2 +- lib/easy.c | 2 +- lib/http2.c | 2 +- lib/multi_ev.c | 85 ++++++------- lib/multi_ev.h | 6 +- lib/{hash_offt.c => uint-hash.c} | 207 ++----------------------------- lib/{hash_offt.h => uint-hash.h} | 33 +---- lib/url.c | 33 +++++ lib/url.h | 10 +- lib/urldata.h | 7 +- lib/vquic/curl_msh3.c | 2 +- lib/vquic/curl_ngtcp2.c | 2 +- lib/vquic/curl_quiche.c | 2 +- tests/data/test1616 | 4 +- tests/unit/unit1616.c | 28 ++--- 18 files changed, 126 insertions(+), 343 deletions(-) rename lib/{hash_offt.c => uint-hash.c} (55%) rename lib/{hash_offt.h => uint-hash.h} (70%) diff --git a/docs/internals/HASH.md b/docs/internals/HASH.md index 5a5bdc9838..9534eb7d1a 100644 --- a/docs/internals/HASH.md +++ b/docs/internals/HASH.md @@ -149,40 +149,3 @@ Called repeatedly, it iterates over all the entries in the hash table. Note: it only guarantees functionality if the hash table remains untouched during its iteration. - -# `curl_off_t` dedicated hash functions - -## `Curl_hash_offt_init` - -~~~c -void Curl_hash_offt_init(struct Curl_hash *h, - size_t slots, - Curl_hash_dtor dtor); -~~~ - -Initializes a hash table for `curl_off_t` values. Pass in desired number of -`slots` and `dtor` function. - -## `Curl_hash_offt_set` - -~~~c -void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem); -~~~ - -Associate a custom `elem` pointer with the given `id`. - -## `Curl_hash_offt_remove` - -~~~c -int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id); -~~~ - -Remove the `id` from the hash. - -## `Curl_hash_offt_get` - -~~~c -void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id); -~~~ - -Get the pointer associated with the specified `id`. diff --git a/docs/internals/UINT_SETS.md b/docs/internals/UINT_SETS.md index 38509e308d..de00b9b47a 100644 --- a/docs/internals/UINT_SETS.md +++ b/docs/internals/UINT_SETS.md @@ -126,6 +126,3 @@ Iterating a sparse bitset works the same as for bitset and table. At last, there are places in libcurl such as the HTTP/2 and HTTP/3 protocol implementations that need to store their own data related to a transfer. `uint_hash` allows then to associate an unsigned int, e.g. the transfer's `mid`, to their own data. - -This is just a variation of `hash_offt` that can associate data with a `connection_id`. Which -is a specialization of the generic `Curl_hash`. diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 0b034df92e..414c955945 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -164,7 +164,6 @@ LIB_CFILES = \ getinfo.c \ gopher.c \ hash.c \ - hash_offt.c \ headers.c \ hmac.c \ hostip.c \ @@ -237,6 +236,7 @@ LIB_CFILES = \ timeval.c \ transfer.c \ uint-bset.c \ + uint-hash.c \ uint-spbset.c \ uint-table.c \ url.c \ @@ -314,7 +314,6 @@ LIB_HFILES = \ getinfo.h \ gopher.h \ hash.h \ - hash_offt.h \ headers.h \ hostip.h \ hsts.h \ @@ -380,6 +379,7 @@ LIB_HFILES = \ timeval.h \ transfer.h \ uint-bset.h \ + uint-hash.h \ uint-spbset.h \ uint-table.h \ url.h \ diff --git a/lib/doh.c b/lib/doh.c index 25d4fc43d2..027b138e25 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -249,7 +249,7 @@ static void doh_probe_done(struct Curl_easy *data, Curl_dyn_len(&doh_req->resp_body)); Curl_dyn_free(&doh_req->resp_body); } - Curl_meta_clear(doh, CURL_EZM_DOH_PROBE); + Curl_meta_remove(doh, CURL_EZM_DOH_PROBE); } if(result) diff --git a/lib/easy.c b/lib/easy.c index f63c73c8af..8e95fe7311 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -1419,7 +1419,7 @@ CURLcode Curl_meta_set(struct Curl_easy *data, const char *key, return CURLE_OK; } -void Curl_meta_clear(struct Curl_easy *data, const char *key) +void Curl_meta_remove(struct Curl_easy *data, const char *key) { Curl_hash_delete(&data->meta_hash, CURL_UNCONST(key), strlen(key) + 1); } diff --git a/lib/http2.c b/lib/http2.c index 9423a5d2a1..84be0797a9 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -29,7 +29,7 @@ #include #include "urldata.h" #include "bufq.h" -#include "hash_offt.h" +#include "uint-hash.h" #include "http1.h" #include "http2.h" #include "http.h" diff --git a/lib/multi_ev.c b/lib/multi_ev.c index 96595387c6..9e2b039edf 100644 --- a/lib/multi_ev.c +++ b/lib/multi_ev.c @@ -27,6 +27,7 @@ #include #include "urldata.h" +#include "url.h" #include "cfilters.h" #include "curl_trc.h" #include "multiif.h" @@ -57,7 +58,7 @@ static void mev_in_callback(struct Curl_multi *multi, bool value) */ struct mev_sh_entry { struct uint_spbset xfers; /* bitset of transfers `mid`s on this socket */ - struct Curl_hash_offt conns; /* hash of connections using this socket */ + struct connectdata *conn; /* connection using this socket or NULL */ void *user_data; /* libcurl app data via curl_multi_assign() */ unsigned int action; /* CURL_POLL_IN/CURL_POLL_OUT we last told the * libcurl application to watch out for */ @@ -84,7 +85,6 @@ static void mev_sh_entry_dtor(void *freethis) { struct mev_sh_entry *entry = (struct mev_sh_entry *)freethis; Curl_uint_spbset_destroy(&entry->xfers); - Curl_hash_offt_destroy(&entry->conns); free(entry); } @@ -117,7 +117,6 @@ mev_sh_entry_add(struct Curl_hash *sh, curl_socket_t s) return NULL; /* major failure */ Curl_uint_spbset_init(&check->xfers); - Curl_hash_offt_init(&check->conns, CURL_MEV_CONN_HASH_SIZE, NULL); /* make/add new hash entry */ if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { @@ -136,7 +135,7 @@ static void mev_sh_entry_kill(struct Curl_multi *multi, curl_socket_t s) static size_t mev_sh_entry_user_count(struct mev_sh_entry *e) { - return Curl_uint_spbset_count(&e->xfers) + Curl_hash_offt_count(&e->conns); + return Curl_uint_spbset_count(&e->xfers) + (e->conn ? 1 : 0); } static bool mev_sh_entry_xfer_known(struct mev_sh_entry *e, @@ -148,7 +147,7 @@ static bool mev_sh_entry_xfer_known(struct mev_sh_entry *e, static bool mev_sh_entry_conn_known(struct mev_sh_entry *e, struct connectdata *conn) { - return !!Curl_hash_offt_get(&e->conns, conn->connection_id); + return (e->conn == conn); } static bool mev_sh_entry_xfer_add(struct mev_sh_entry *e, @@ -164,7 +163,11 @@ static bool mev_sh_entry_conn_add(struct mev_sh_entry *e, { /* detect weird values */ DEBUGASSERT(mev_sh_entry_user_count(e) < 100000); - return !!Curl_hash_offt_set(&e->conns, conn->connection_id, conn); + DEBUGASSERT(!e->conn); + if(e->conn) + return FALSE; + e->conn = conn; + return TRUE; } @@ -180,7 +183,12 @@ static bool mev_sh_entry_xfer_remove(struct mev_sh_entry *e, static bool mev_sh_entry_conn_remove(struct mev_sh_entry *e, struct connectdata *conn) { - return Curl_hash_offt_remove(&e->conns, conn->connection_id); + DEBUGASSERT(e->conn == conn); + if(e->conn == conn) { + e->conn = NULL; + return TRUE; + } + return FALSE; } /* Purge any information about socket `s`. @@ -344,11 +352,11 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, return CURLM_OUT_OF_MEMORY; } CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", added %s #%" FMT_OFF_T - ", total=%u/%zu (xfer/conn)", s, + ", total=%u/%d (xfer/conn)", s, conn ? "connection" : "transfer", conn ? conn->connection_id : data->mid, Curl_uint_spbset_count(&entry->xfers), - Curl_hash_offt_count(&entry->conns)); + entry->conn ? 1 : 0); } else { for(j = 0; j < prev_ps->num; j++) { @@ -414,9 +422,9 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, if(mresult) return mresult; CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", removed transfer, " - "total=%u/%zu (xfer/conn)", s, + "total=%u/%d (xfer/conn)", s, Curl_uint_spbset_count(&entry->xfers), - Curl_hash_offt_count(&entry->conns)); + entry->conn ? 1 : 0); } else { mresult = mev_forget_socket(multi, data, s, "last user gone"); @@ -430,15 +438,22 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, return CURLM_OK; } +static void mev_pollset_dtor(void *key, size_t klen, void *entry) +{ + (void)key; + (void)klen; + free(entry); +} + static struct easy_pollset* -mev_add_new_conn_pollset(struct Curl_hash_offt *h, curl_off_t id) +mev_add_new_conn_pollset(struct connectdata *conn) { struct easy_pollset *ps; ps = calloc(1, sizeof(*ps)); if(!ps) return NULL; - if(!Curl_hash_offt_set(h, id, ps)) { + if(Curl_conn_meta_set(conn, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor)) { free(ps); return NULL; } @@ -446,14 +461,14 @@ mev_add_new_conn_pollset(struct Curl_hash_offt *h, curl_off_t id) } static struct easy_pollset* -mev_add_new_xfer_pollset(struct uint_hash *h, unsigned int id) +mev_add_new_xfer_pollset(struct Curl_easy *data) { struct easy_pollset *ps; ps = calloc(1, sizeof(*ps)); if(!ps) return NULL; - if(!Curl_uint_hash_set(h, id, ps)) { + if(Curl_meta_set(data, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor)) { free(ps); return NULL; } @@ -461,16 +476,14 @@ mev_add_new_xfer_pollset(struct uint_hash *h, unsigned int id) } static struct easy_pollset * -mev_get_last_pollset(struct Curl_multi *multi, - struct Curl_easy *data, +mev_get_last_pollset(struct Curl_easy *data, struct connectdata *conn) { if(data) { if(conn) - return Curl_hash_offt_get(&multi->ev.conn_pollsets, - conn->connection_id); + return Curl_conn_meta_get(conn, CURL_META_MEV_POLLSET); else if(data) - return Curl_uint_hash_get(&multi->ev.xfer_pollsets, data->mid); + return Curl_meta_get(data, CURL_META_MEV_POLLSET); } return NULL; } @@ -494,15 +507,13 @@ static CURLMcode mev_assess(struct Curl_multi *multi, struct easy_pollset ps, *last_ps; mev_init_cur_pollset(&ps, data, conn); - last_ps = mev_get_last_pollset(multi, data, conn); + last_ps = mev_get_last_pollset(data, conn); if(!last_ps && ps.num) { if(conn) - last_ps = mev_add_new_conn_pollset(&multi->ev.conn_pollsets, - conn->connection_id); + last_ps = mev_add_new_conn_pollset(conn); else - last_ps = mev_add_new_xfer_pollset(&multi->ev.xfer_pollsets, - data->mid); + last_ps = mev_add_new_xfer_pollset(data); if(!last_ps) return CURLM_OUT_OF_MEMORY; } @@ -588,7 +599,7 @@ void Curl_multi_ev_expire_xfers(struct Curl_multi *multi, while(Curl_uint_spbset_next(&entry->xfers, mid, &mid)); } - if(Curl_hash_offt_count(&entry->conns)) + if(entry->conn) *run_cpool = TRUE; } } @@ -605,7 +616,7 @@ void Curl_multi_ev_xfer_done(struct Curl_multi *multi, DEBUGASSERT(!data->conn); /* transfer should have been detached */ if(data != multi->admin) { (void)mev_assess(multi, data, NULL); - Curl_uint_hash_remove(&multi->ev.xfer_pollsets, data->mid); + Curl_meta_remove(data, CURL_META_MEV_POLLSET); } } @@ -614,36 +625,18 @@ void Curl_multi_ev_conn_done(struct Curl_multi *multi, struct connectdata *conn) { (void)mev_assess(multi, data, conn); - Curl_hash_offt_remove(&multi->ev.conn_pollsets, conn->connection_id); + Curl_conn_meta_remove(conn, CURL_META_MEV_POLLSET); } #define CURL_MEV_PS_HASH_SLOTS (991) /* nice prime */ -static void mev_hash_conn_pollset_free(curl_off_t id, void *entry) -{ - (void)id; - free(entry); -} - -static void mev_hash_xfer_pollset_free(unsigned int id, void *entry) -{ - (void)id; - free(entry); -} - void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize) { Curl_hash_init(&multi->ev.sh_entries, hashsize, mev_sh_entry_hash, mev_sh_entry_compare, mev_sh_entry_dtor); - Curl_uint_hash_init(&multi->ev.xfer_pollsets, - CURL_MEV_PS_HASH_SLOTS, mev_hash_xfer_pollset_free); - Curl_hash_offt_init(&multi->ev.conn_pollsets, - CURL_MEV_PS_HASH_SLOTS, mev_hash_conn_pollset_free); } void Curl_multi_ev_cleanup(struct Curl_multi *multi) { Curl_hash_destroy(&multi->ev.sh_entries); - Curl_uint_hash_destroy(&multi->ev.xfer_pollsets); - Curl_hash_offt_destroy(&multi->ev.conn_pollsets); } diff --git a/lib/multi_ev.h b/lib/multi_ev.h index 3aa6cca24c..06be842fb9 100644 --- a/lib/multi_ev.h +++ b/lib/multi_ev.h @@ -25,17 +25,17 @@ ***************************************************************************/ #include "hash.h" -#include "hash_offt.h" struct Curl_easy; struct Curl_multi; struct easy_pollset; struct uint_bset; +/* meta key for event pollset at easy handle or connection */ +#define CURL_META_MEV_POLLSET "meta:mev:ps" + struct curl_multi_ev { struct Curl_hash sh_entries; - struct uint_hash xfer_pollsets; - struct Curl_hash_offt conn_pollsets; }; /* Setup/teardown of multi event book-keeping. */ diff --git a/lib/hash_offt.c b/lib/uint-hash.c similarity index 55% rename from lib/hash_offt.c rename to lib/uint-hash.c index cef29742a2..afeb684d0c 100644 --- a/lib/hash_offt.c +++ b/lib/uint-hash.c @@ -26,207 +26,12 @@ #include -#include "hash_offt.h" +#include "uint-hash.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" -/* random patterns for API verification */ -#ifdef DEBUGBUILD -#define CURL_HASHOFFTINIT 0x7117e781 -#endif - -static size_t hash_offt_hash(curl_off_t id, size_t slots) -{ - return (size_t)((id >= 0) ? (id % slots) : (-id % slots)); -} - -struct Curl_hash_offt_entry { - curl_off_t id; - struct Curl_hash_offt_entry *next; - void *value; -}; - -void Curl_hash_offt_init(struct Curl_hash_offt *h, - size_t slots, - Curl_hash_offt_dtor *dtor) -{ - DEBUGASSERT(h); - DEBUGASSERT(slots); - - h->table = NULL; - h->dtor = dtor; - h->size = 0; - h->slots = slots; -#ifdef DEBUGBUILD - h->init = CURL_HASHOFFTINIT; -#endif -} - -static struct Curl_hash_offt_entry * -hash_offt_mk_entry(curl_off_t id, void *value) -{ - struct Curl_hash_offt_entry *e; - - /* allocate the struct for the hash entry */ - e = malloc(sizeof(*e)); - if(e) { - e->id = id; - e->next = NULL; - e->value = value; - } - return e; -} - -static void hash_offt_entry_clear(struct Curl_hash_offt *h, - struct Curl_hash_offt_entry *e) -{ - DEBUGASSERT(h); - DEBUGASSERT(e); - if(e->value) { - if(h->dtor) - h->dtor(e->id, e->value); - e->value = NULL; - } -} - -static void hash_offt_entry_destroy(struct Curl_hash_offt *h, - struct Curl_hash_offt_entry *e) -{ - hash_offt_entry_clear(h, e); - free(e); -} - -static void hash_offt_entry_unlink(struct Curl_hash_offt *h, - struct Curl_hash_offt_entry **he_anchor, - struct Curl_hash_offt_entry *he) -{ - *he_anchor = he->next; - --h->size; -} - -static void hash_offtr_elem_link(struct Curl_hash_offt *h, - struct Curl_hash_offt_entry **he_anchor, - struct Curl_hash_offt_entry *he) -{ - he->next = *he_anchor; - *he_anchor = he; - ++h->size; -} - -#define CURL_HASH_OFFT_SLOT(h,id) h->table[hash_offt_hash(id, h->slots)] -#define CURL_HASH_OFFT_SLOT_ADDR(h,id) &CURL_HASH_OFFT_SLOT(h,id) - -bool Curl_hash_offt_set(struct Curl_hash_offt *h, curl_off_t id, void *value) -{ - struct Curl_hash_offt_entry *he, **slot; - - DEBUGASSERT(h); - DEBUGASSERT(h->slots); - DEBUGASSERT(h->init == CURL_HASHOFFTINIT); - if(!h->table) { - h->table = calloc(h->slots, sizeof(*he)); - if(!h->table) - return FALSE; /* OOM */ - } - - slot = CURL_HASH_OFFT_SLOT_ADDR(h, id); - for(he = *slot; he; he = he->next) { - if(he->id == id) { - /* existing key entry, overwrite by clearing old pointer */ - hash_offt_entry_clear(h, he); - he->value = value; - return TRUE; - } - } - - he = hash_offt_mk_entry(id, value); - if(!he) - return FALSE; /* OOM */ - - hash_offtr_elem_link(h, slot, he); - return TRUE; -} - -bool Curl_hash_offt_remove(struct Curl_hash_offt *h, curl_off_t id) -{ - DEBUGASSERT(h); - DEBUGASSERT(h->slots); - DEBUGASSERT(h->init == CURL_HASHOFFTINIT); - if(h->table) { - struct Curl_hash_offt_entry *he, **he_anchor; - - he_anchor = CURL_HASH_OFFT_SLOT_ADDR(h, id); - while(*he_anchor) { - he = *he_anchor; - if(id == he->id) { - hash_offt_entry_unlink(h, he_anchor, he); - hash_offt_entry_destroy(h, he); - return TRUE; - } - he_anchor = &he->next; - } - } - return FALSE; -} - -void *Curl_hash_offt_get(struct Curl_hash_offt *h, curl_off_t id) -{ - DEBUGASSERT(h); - DEBUGASSERT(h->init == CURL_HASHOFFTINIT); - if(h->table) { - struct Curl_hash_offt_entry *he; - DEBUGASSERT(h->slots); - he = CURL_HASH_OFFT_SLOT(h, id); - while(he) { - if(id == he->id) { - return he->value; - } - he = he->next; - } - } - return NULL; -} - -void Curl_hash_offt_clear(struct Curl_hash_offt *h) -{ - if(h && h->table) { - struct Curl_hash_offt_entry *he, **he_anchor; - size_t i; - DEBUGASSERT(h->init == CURL_HASHOFFTINIT); - for(i = 0; i < h->slots; ++i) { - he_anchor = &h->table[i]; - while(*he_anchor) { - he = *he_anchor; - hash_offt_entry_unlink(h, he_anchor, he); - hash_offt_entry_destroy(h, he); - } - } - } -} - -void -Curl_hash_offt_destroy(struct Curl_hash_offt *h) -{ - DEBUGASSERT(h->init == CURL_HASHOFFTINIT); - if(h->table) { - Curl_hash_offt_clear(h); - Curl_safefree(h->table); - } - DEBUGASSERT(h->size == 0); - h->slots = 0; -} - -size_t Curl_hash_offt_count(struct Curl_hash_offt *h) -{ - DEBUGASSERT(h->init == CURL_HASHOFFTINIT); - return h->size; -} - -/* FOR NOW: basically a duplicate of Curl_hash_offt, BUT we hope to - * eliminate the offt variant in the near future. */ - /* random patterns for API verification */ #ifdef DEBUGBUILD #define CURL_UINTHASHINIT 0x7117e779 @@ -311,7 +116,7 @@ static void uint_hash_elem_link(struct uint_hash *h, } #define CURL_UINT_HASH_SLOT(h,id) h->table[uint_hash_hash(id, h->slots)] -#define CURL_UINT_HASH_SLOT_ADDR(h,id) &CURL_HASH_OFFT_SLOT(h,id) +#define CURL_UINT_HASH_SLOT_ADDR(h,id) &CURL_UINT_HASH_SLOT(h,id) bool Curl_uint_hash_set(struct uint_hash *h, unsigned int id, void *value) { @@ -401,8 +206,12 @@ static void uint_hash_clear(struct uint_hash *h) } } -void -Curl_uint_hash_destroy(struct uint_hash *h) +void Curl_uint_hash_clear(struct uint_hash *h) +{ + uint_hash_clear(h); +} + +void Curl_uint_hash_destroy(struct uint_hash *h) { DEBUGASSERT(h->init == CURL_UINTHASHINIT); if(h->table) { diff --git a/lib/hash_offt.h b/lib/uint-hash.h similarity index 70% rename from lib/hash_offt.h rename to lib/uint-hash.h index 80bab95c2a..1b52dba4c4 100644 --- a/lib/hash_offt.h +++ b/lib/uint-hash.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_HASH_OFFT_H -#define HEADER_CURL_HASH_OFFT_H +#ifndef HEADER_CURL_UINT_HASH_H +#define HEADER_CURL_UINT_HASH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -30,32 +30,6 @@ #include "llist.h" -struct Curl_hash_offt_entry; -typedef void Curl_hash_offt_dtor(curl_off_t id, void *value); - -/* Hash for `curl_off_t` as key */ -struct Curl_hash_offt { - struct Curl_hash_offt_entry **table; - Curl_hash_offt_dtor *dtor; - size_t slots; - size_t size; -#ifdef DEBUGBUILD - int init; -#endif -}; - -void Curl_hash_offt_init(struct Curl_hash_offt *h, - size_t slots, - Curl_hash_offt_dtor *dtor); -void Curl_hash_offt_destroy(struct Curl_hash_offt *h); - -bool Curl_hash_offt_set(struct Curl_hash_offt *h, curl_off_t id, void *value); -bool Curl_hash_offt_remove(struct Curl_hash_offt *h, curl_off_t id); -void *Curl_hash_offt_get(struct Curl_hash_offt *h, curl_off_t id); -void Curl_hash_offt_clear(struct Curl_hash_offt *h); -size_t Curl_hash_offt_count(struct Curl_hash_offt *h); - - /* A version with unsigned int as key */ typedef void Curl_uint_hash_dtor(unsigned int id, void *value); struct uint_hash_entry; @@ -76,6 +50,7 @@ void Curl_uint_hash_init(struct uint_hash *h, unsigned int slots, Curl_uint_hash_dtor *dtor); void Curl_uint_hash_destroy(struct uint_hash *h); +void Curl_uint_hash_clear(struct uint_hash *h); bool Curl_uint_hash_set(struct uint_hash *h, unsigned int id, void *value); bool Curl_uint_hash_remove(struct uint_hash *h, unsigned int id); @@ -90,4 +65,4 @@ void Curl_uint_hash_visit(struct uint_hash *h, Curl_uint_hash_visit_cb *cb, void *user_data); -#endif /* HEADER_CURL_HASH_OFFT_H */ +#endif /* HEADER_CURL_UINT_HASH_H */ diff --git a/lib/url.c b/lib/url.c index 473582ca40..9d17ce9779 100644 --- a/lib/url.c +++ b/lib/url.c @@ -601,6 +601,7 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn) #endif Curl_safefree(conn->destination); Curl_uint_spbset_destroy(&conn->xfers_attached); + Curl_hash_destroy(&conn->meta_hash); free(conn); /* free all the connection oriented data */ } @@ -3322,6 +3323,15 @@ static void reuse_conn(struct Curl_easy *data, Curl_conn_free(data, temp); } +static void conn_meta_freeentry(void *p) +{ + (void)p; + /* Will always be FALSE. Cannot use a 0 assert here since compilers + * are not in agreement if they then want a NORETURN attribute or + * not. *sigh* */ + DEBUGASSERT(p == NULL); +} + /** * create_conn() sets up a new connectdata struct, or reuses an already * existing one, and resolves hostname. @@ -3377,6 +3387,9 @@ static CURLcode create_conn(struct Curl_easy *data, *in_connect = conn; /* Do the unfailable inits first, before checks that may early return */ + Curl_hash_init(&conn->meta_hash, 23, + Curl_hash_str, Curl_str_key_compare, conn_meta_freeentry); + /* GSSAPI related inits */ Curl_sec_conn_init(conn); @@ -3944,3 +3957,23 @@ void Curl_data_priority_clear_state(struct Curl_easy *data) } #endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */ + + +CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key, + void *meta_data, Curl_meta_dtor *meta_dtor) +{ + if(!Curl_hash_add2(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1, + meta_data, meta_dtor)) { + meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data); + } + return CURLE_OK; +} +void Curl_conn_meta_remove(struct connectdata *conn, const char *key) +{ + Curl_hash_delete(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1); +} + +void *Curl_conn_meta_get(struct connectdata *conn, const char *key) +{ + return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1); +} diff --git a/lib/url.h b/lib/url.h index aa687228ab..76a935ecee 100644 --- a/lib/url.h +++ b/lib/url.h @@ -54,10 +54,18 @@ typedef void Curl_meta_dtor(void *key, size_t key_len, void *meta_data); * Takes ownership of `meta_data` and destroys it when the call fails. */ CURLcode Curl_meta_set(struct Curl_easy *data, const char *key, void *meta_data, Curl_meta_dtor *meta_dtor); -void Curl_meta_clear(struct Curl_easy *data, const char *key); +void Curl_meta_remove(struct Curl_easy *data, const char *key); void *Curl_meta_get(struct Curl_easy *data, const char *key); void Curl_meta_reset(struct Curl_easy *data); +/* Set connection meta data for the key. Any existing entry for that + * key will be destroyed. + * Takes ownership of `meta_data` and destroys it when the call fails. */ +CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key, + void *meta_data, Curl_meta_dtor *meta_dtor); +void Curl_conn_meta_remove(struct connectdata *conn, const char *key); +void *Curl_conn_meta_get(struct connectdata *conn, const char *key); + /* Get protocol handler for a URI scheme * @param scheme URI scheme, case-insensitive * @return NULL of handler not found diff --git a/lib/urldata.h b/lib/urldata.h index e76d4a1043..eddcb0a2b7 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -152,7 +152,6 @@ typedef unsigned int curl_prot_t; #include "http_chunks.h" /* for the structs and enum stuff */ #include "hostip.h" #include "hash.h" -#include "hash_offt.h" #include "splay.h" #include "dynbuf.h" #include "dynhds.h" @@ -750,6 +749,12 @@ struct connectdata { track the connections in the log output */ char *destination; /* string carrying normalized hostname+port+scope */ + /* `meta_hash` is a general key-value store for implementations + * with the lifetime of the connection. + * Elements need to be added with their own destructor to be invoked when + * 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 diff --git a/lib/vquic/curl_msh3.c b/lib/vquic/curl_msh3.c index 7dca1dc115..cd85fd5fb9 100644 --- a/lib/vquic/curl_msh3.c +++ b/lib/vquic/curl_msh3.c @@ -28,7 +28,7 @@ #include "../urldata.h" #include "../hash.h" -#include "../hash_offt.h" +#include "../uint-hash.h" #include "../timeval.h" #include "../multiif.h" #include "../sendf.h" diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index fc22f18f99..9827a89517 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -47,7 +47,7 @@ #endif #include "../urldata.h" -#include "../hash_offt.h" +#include "../uint-hash.h" #include "../sendf.h" #include "../strdup.h" #include "../rand.h" diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index caae5f3082..869a2bc1b0 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -29,7 +29,7 @@ #include #include #include "../bufq.h" -#include "../hash_offt.h" +#include "../uint-hash.h" #include "../urldata.h" #include "../cfilters.h" #include "../cf-socket.h" diff --git a/tests/data/test1616 b/tests/data/test1616 index cce79c122a..a203c95b01 100644 --- a/tests/data/test1616 +++ b/tests/data/test1616 @@ -2,7 +2,7 @@ unittest -hash +uint_hash @@ -16,7 +16,7 @@ none unittest -Internal hash_offt create/add/destroy testing, exercising clean functions +Internal uint_hash create/add/destroy testing, exercising clean functions diff --git a/tests/unit/unit1616.c b/tests/unit/unit1616.c index e6608a7938..3fe0c0c20d 100644 --- a/tests/unit/unit1616.c +++ b/tests/unit/unit1616.c @@ -25,13 +25,13 @@ #include "curlx.h" -#include "hash_offt.h" +#include "uint-hash.h" #include "memdebug.h" /* LAST include file */ -static struct Curl_hash_offt hash_static; +static struct uint_hash hash_static; -static void mydtor(curl_off_t id, void *elem) +static void mydtor(unsigned int id, void *elem) { int *ptr = (int *)elem; (void)id; @@ -40,13 +40,13 @@ static void mydtor(curl_off_t id, void *elem) static CURLcode unit_setup(void) { - Curl_hash_offt_init(&hash_static, 15, mydtor); + Curl_uint_hash_init(&hash_static, 15, mydtor); return CURLE_OK; } static void unit_stop(void) { - Curl_hash_offt_destroy(&hash_static); + Curl_uint_hash_destroy(&hash_static); } UNITTEST_START @@ -54,34 +54,34 @@ UNITTEST_START int *value2; bool ok; - curl_off_t key = 20; - curl_off_t key2 = 25; + unsigned int key = 20; + unsigned int key2 = 25; value = malloc(sizeof(int)); abort_unless(value != NULL, "Out of memory"); *value = 199; - ok = Curl_hash_offt_set(&hash_static, key, value); + ok = Curl_uint_hash_set(&hash_static, key, value); if(!ok) free(value); abort_unless(ok, "insertion into hash failed"); - v = Curl_hash_offt_get(&hash_static, key); + v = Curl_uint_hash_get(&hash_static, key); abort_unless(v == value, "lookup present entry failed"); - v = Curl_hash_offt_get(&hash_static, key2); + v = Curl_uint_hash_get(&hash_static, key2); abort_unless(!v, "lookup missing entry failed"); - Curl_hash_offt_clear(&hash_static); + Curl_uint_hash_clear(&hash_static); /* Attempt to add another key/value pair */ value2 = malloc(sizeof(int)); abort_unless(value2 != NULL, "Out of memory"); *value2 = 204; - ok = Curl_hash_offt_set(&hash_static, key2, value2); + ok = Curl_uint_hash_set(&hash_static, key2, value2); if(!ok) free(value2); abort_unless(ok, "insertion into hash failed"); - v = Curl_hash_offt_get(&hash_static, key2); + v = Curl_uint_hash_get(&hash_static, key2); abort_unless(v == value2, "lookup present entry failed"); - v = Curl_hash_offt_get(&hash_static, key); + v = Curl_uint_hash_get(&hash_static, key); abort_unless(!v, "lookup missing entry failed"); UNITTEST_STOP -- 2.47.3