Packages
hackney
3.0.1
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/lsquic/src/liblsquic/lsquic_hash.c
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_hash.c
*/
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#ifdef WIN32
#include <vc_compat.h>
#endif
#include "lsquic_hash.h"
#include "lsquic_xxhash.h"
TAILQ_HEAD(hels_head, lsquic_hash_elem);
#define N_BUCKETS(n_bits) (1U << (n_bits))
#define BUCKNO(n_bits, hash) ((hash) & (N_BUCKETS(n_bits) - 1))
struct lsquic_hash
{
struct hels_head *qh_buckets,
qh_all;
struct lsquic_hash_elem *qh_iter_next;
int (*qh_cmp)(const void *, const void *, size_t);
unsigned (*qh_hash)(const void *, size_t, unsigned seed);
unsigned qh_count;
unsigned qh_nbits;
};
struct lsquic_hash *
lsquic_hash_create_ext (int (*cmp)(const void *, const void *, size_t),
unsigned (*hashf)(const void *, size_t, unsigned seed))
{
struct hels_head *buckets;
struct lsquic_hash *hash;
unsigned nbits = 2;
unsigned i;
buckets = malloc(sizeof(buckets[0]) * N_BUCKETS(nbits));
if (!buckets)
return NULL;
hash = malloc(sizeof(*hash));
if (!hash)
{
free(buckets);
return NULL;
}
for (i = 0; i < N_BUCKETS(nbits); ++i)
TAILQ_INIT(&buckets[i]);
TAILQ_INIT(&hash->qh_all);
hash->qh_cmp = cmp;
hash->qh_hash = hashf;
hash->qh_buckets = buckets;
hash->qh_nbits = nbits;
hash->qh_iter_next = NULL;
hash->qh_count = 0;
return hash;
}
struct lsquic_hash *
lsquic_hash_create (void)
{
return lsquic_hash_create_ext(memcmp, XXH32);
}
void
lsquic_hash_destroy (struct lsquic_hash *hash)
{
free(hash->qh_buckets);
free(hash);
}
static int
lsquic_hash_grow (struct lsquic_hash *hash)
{
struct hels_head *new_buckets, *new[2];
struct lsquic_hash_elem *el;
unsigned n, old_nbits;
int idx;
old_nbits = hash->qh_nbits;
new_buckets = malloc(sizeof(hash->qh_buckets[0])
* N_BUCKETS(old_nbits + 1));
if (!new_buckets)
return -1;
for (n = 0; n < N_BUCKETS(old_nbits); ++n)
{
new[0] = &new_buckets[n];
new[1] = &new_buckets[n + N_BUCKETS(old_nbits)];
TAILQ_INIT(new[0]);
TAILQ_INIT(new[1]);
while ((el = TAILQ_FIRST(&hash->qh_buckets[n])))
{
TAILQ_REMOVE(&hash->qh_buckets[n], el, qhe_next_bucket);
idx = (BUCKNO(old_nbits + 1, el->qhe_hash_val) >> old_nbits) & 1;
TAILQ_INSERT_TAIL(new[idx], el, qhe_next_bucket);
}
}
free(hash->qh_buckets);
hash->qh_nbits = old_nbits + 1;
hash->qh_buckets = new_buckets;
return 0;
}
struct lsquic_hash_elem *
lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
unsigned key_sz, void *value, struct lsquic_hash_elem *el)
{
unsigned buckno, hash_val;
if (el->qhe_flags & QHE_HASHED)
return NULL;
if (hash->qh_count >= N_BUCKETS(hash->qh_nbits) / 2 &&
0 != lsquic_hash_grow(hash))
return NULL;
hash_val = hash->qh_hash(key, key_sz, (uintptr_t) hash);
buckno = BUCKNO(hash->qh_nbits, hash_val);
TAILQ_INSERT_TAIL(&hash->qh_all, el, qhe_next_all);
TAILQ_INSERT_TAIL(&hash->qh_buckets[buckno], el, qhe_next_bucket);
el->qhe_key_data = key;
el->qhe_key_len = key_sz;
el->qhe_value = value;
el->qhe_hash_val = hash_val;
el->qhe_flags |= QHE_HASHED;
++hash->qh_count;
return el;
}
struct lsquic_hash_elem *
lsquic_hash_find (struct lsquic_hash *hash, const void *key, unsigned key_sz)
{
unsigned buckno, hash_val;
struct lsquic_hash_elem *el;
hash_val = hash->qh_hash(key, key_sz, (uintptr_t) hash);
buckno = BUCKNO(hash->qh_nbits, hash_val);
TAILQ_FOREACH(el, &hash->qh_buckets[buckno], qhe_next_bucket)
if (hash_val == el->qhe_hash_val &&
key_sz == el->qhe_key_len &&
0 == hash->qh_cmp(key, el->qhe_key_data, key_sz))
{
return el;
}
return NULL;
}
void
lsquic_hash_erase (struct lsquic_hash *hash, struct lsquic_hash_elem *el)
{
unsigned buckno;
assert(el->qhe_flags & QHE_HASHED);
buckno = BUCKNO(hash->qh_nbits, el->qhe_hash_val);
if (hash->qh_iter_next == el)
hash->qh_iter_next = TAILQ_NEXT(el, qhe_next_all);
TAILQ_REMOVE(&hash->qh_buckets[buckno], el, qhe_next_bucket);
TAILQ_REMOVE(&hash->qh_all, el, qhe_next_all);
el->qhe_flags &= ~QHE_HASHED;
--hash->qh_count;
}
void
lsquic_hash_reset_iter (struct lsquic_hash *hash)
{
hash->qh_iter_next = TAILQ_FIRST(&hash->qh_all);
}
struct lsquic_hash_elem *
lsquic_hash_first (struct lsquic_hash *hash)
{
lsquic_hash_reset_iter(hash);
return lsquic_hash_next(hash);
}
struct lsquic_hash_elem *
lsquic_hash_next (struct lsquic_hash *hash)
{
struct lsquic_hash_elem *el;
el = hash->qh_iter_next;
if (el)
hash->qh_iter_next = TAILQ_NEXT(el, qhe_next_all);
return el;
}
unsigned
lsquic_hash_count (struct lsquic_hash *hash)
{
return hash->qh_count;
}
size_t
lsquic_hash_mem_used (const struct lsquic_hash *hash)
{
return sizeof(*hash)
+ N_BUCKETS(hash->qh_nbits) * sizeof(hash->qh_buckets[0]);
}