Packages
hackney
3.0.3
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_stock_shi.c
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_stock_shi.c
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include <time.h>
#include "lsquic.h"
#include "lsquic_stock_shi.h"
#include "lsquic_malo.h"
#include "lsquic_hash.h"
struct stock_shared_hash
{
TAILQ_HEAD(, hash_elem) lru_elems;
struct lsquic_hash *lhash;
struct malo *malo;
};
struct key
{
void *buf;
unsigned sz;
};
struct hash_elem
{
TAILQ_ENTRY(hash_elem) next_lru_he;
struct lsquic_hash_elem lhash_elem;
void *data;
time_t expiry; /* If not 0, the element is on LRU list */
struct key key;
unsigned data_sz;
};
static void
free_key_data (struct hash_elem *he)
{
free(he->key.buf);
}
static void
delete_expired_elements (struct stock_shared_hash *hash)
{
struct hash_elem *he;
time_t now = time(NULL);
while ((he = TAILQ_FIRST(&hash->lru_elems)))
{
if (he->expiry < now)
{
lsquic_hash_erase(hash->lhash, &he->lhash_elem);
if (he->expiry)
TAILQ_REMOVE(&hash->lru_elems, he, next_lru_he);
free_key_data(he);
lsquic_malo_put(he);
}
else
break;
}
}
static int
stock_shi_insert (void *hash_ctx, void *key, unsigned key_sz,
void *data, unsigned data_sz, time_t expiry)
{
struct stock_shared_hash *const hash = hash_ctx;
struct hash_elem *he;
/* Potential optimization: do not exire on every insert. Use case:
* if many insert occur in a row, it is not efficient to perform
* this check every time. Can add a counter in hash.
*/
if (!TAILQ_EMPTY(&hash->lru_elems))
delete_expired_elements(hash);
he = lsquic_malo_get(hash->malo);
if (!he)
return -1;
he->key.buf = malloc(key_sz + data_sz + 1);
if (!he->key.buf)
{
lsquic_malo_put(he);
return -1;
}
memmove(he->key.buf, key, key_sz);
((char *)(he->key.buf))[key_sz] = 0;
he->key.sz = key_sz;
he->data = (char *)he->key.buf + he->key.sz + 1;
memmove(he->data, data, data_sz);
he->data_sz = data_sz;
he->expiry = expiry;
memset(&he->lhash_elem, 0, sizeof(he->lhash_elem));
if (lsquic_hash_insert(hash->lhash, he->key.buf,
he->key.sz, he, &he->lhash_elem))
{
if (expiry)
TAILQ_INSERT_TAIL(&hash->lru_elems, he, next_lru_he);
return 0;
}
else
{
lsquic_malo_put(he);
return -1;
}
}
static int
stock_shi_lookup (void *hash_ctx, const void *key, unsigned key_sz,
void **data, unsigned *data_sz)
{
struct stock_shared_hash *const hash = hash_ctx;
struct hash_elem *he;
struct lsquic_hash_elem *el;
if (!TAILQ_EMPTY(&hash->lru_elems))
delete_expired_elements(hash);
el = lsquic_hash_find(hash->lhash, key, key_sz);
if (!el)
return 0; /* 0: not found */
he = lsquic_hashelem_getdata(el);
*data = he->data;
*data_sz = he->data_sz;
return 1; /* 1: found */
}
static int
stock_shi_delete (void *hash_ctx, const void *key, unsigned key_sz)
{
struct stock_shared_hash *const hash = hash_ctx;
struct lsquic_hash_elem *el;
struct hash_elem *he;
if (!TAILQ_EMPTY(&hash->lru_elems))
delete_expired_elements(hash);
el = lsquic_hash_find(hash->lhash, key, key_sz);
if (!el)
return -1;
he = lsquic_hashelem_getdata(el);
lsquic_hash_erase(hash->lhash, el);
if (he->expiry)
TAILQ_REMOVE(&hash->lru_elems, he, next_lru_he);
free_key_data(he);
lsquic_malo_put(he);
return 0;
}
struct stock_shared_hash *
lsquic_stock_shared_hash_new (void)
{
struct malo *malo;
struct stock_shared_hash *hash;
malo = lsquic_malo_create(sizeof(struct hash_elem));
if (!malo)
return NULL;
hash = lsquic_malo_get(malo);
if (!hash)
{ /* This would be really odd, but let's check this for completeness. */
lsquic_malo_destroy(malo);
return NULL;
}
hash->malo = malo;
hash->lhash = lsquic_hash_create();
TAILQ_INIT(&hash->lru_elems);
return hash;
}
void
lsquic_stock_shared_hash_destroy (struct stock_shared_hash *hash)
{
struct hash_elem *he;
struct lsquic_hash_elem *el;
for (el = lsquic_hash_first(hash->lhash); el;
el = lsquic_hash_next(hash->lhash))
{
he = lsquic_hashelem_getdata(el);
free_key_data(he);
/* No need to lsquic_malo_put(he) here */
}
lsquic_hash_destroy(hash->lhash);
lsquic_malo_destroy(hash->malo);
}
const struct lsquic_shared_hash_if stock_shi =
{
.shi_insert = stock_shi_insert,
.shi_delete = stock_shi_delete,
.shi_lookup = stock_shi_lookup,
};
/* Need this to save one malloc using malo: */
typedef char hash_not_larger_than_hash_elem [
(sizeof(struct stock_shared_hash) <= sizeof(struct hash_elem)) ? 1 : -1];