Packages
hackney
2.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_trechist.c
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include "lsquic_int_types.h"
#include "lsquic_trechist.h"
static unsigned
find_free_slot (uint32_t slots)
{
#if __GNUC__
return __builtin_ctz(~slots);
#else
unsigned n;
slots =~ slots;
n = 0;
if (0 == (slots & ((1ULL << 16) - 1))) { n += 16; slots >>= 16; }
if (0 == (slots & ((1ULL << 8) - 1))) { n += 8; slots >>= 8; }
if (0 == (slots & ((1ULL << 4) - 1))) { n += 4; slots >>= 4; }
if (0 == (slots & ((1ULL << 2) - 1))) { n += 2; slots >>= 2; }
if (0 == (slots & ((1ULL << 1) - 1))) { n += 1; slots >>= 1; }
return n;
#endif
}
/* When capacity is reached, smallest element is removed. When the number
* of elements in a single range cannot be represented by te_count, an
* error is returned. This is the only error this function returns.
*/
int
lsquic_trechist_insert (trechist_mask_t *mask, struct trechist_elem *elems,
uint32_t packno)
{
struct trechist_elem *el, *prev, *cur, *next;
unsigned idx;
if (*mask == 0)
{
elems[0].te_low = packno;
elems[0].te_count = 1;
elems[0].te_next = 0;
*mask |= 1;
return 0;
}
el = elems;
prev = NULL;
while (1)
{
if (packno > TE_HIGH(el) + 1)
goto insert_before;
if (packno == el->te_low - 1)
{
if (el->te_next && el->te_low == TE_HIGH(&elems[el->te_next]) + 2)
{
if (el->te_count + elems[el->te_next].te_count - 1 > UCHAR_MAX)
return -1;
*mask &= ~(1u << el->te_next);
el->te_count += elems[el->te_next].te_count + 1;
el->te_low = elems[el->te_next].te_low;
el->te_next = elems[el->te_next].te_next;
}
else
{
if (el->te_count == UCHAR_MAX)
return -1;
--el->te_low;
++el->te_count;
}
return 0;
}
if (packno == TE_HIGH(el) + 1)
{
if (el->te_count == UCHAR_MAX)
return -1;
++el->te_count;
return 0;
}
if (packno >= el->te_low && packno <= TE_HIGH(el))
return 0; /* Dup */
if (!el->te_next)
break; /* insert tail */
prev = el;
el = &elems[el->te_next];
}
if (*mask == TRECHIST_MAX_RANGES_MASK)
/* No need to insert element smaller than the smallest element
* already in our list. The new element "overflows".
*/
return 0;
idx = find_free_slot(*mask);
elems[idx].te_low = packno;
elems[idx].te_count = 1;
elems[idx].te_next = 0;
*mask |= 1u << idx;;
el->te_next = idx;
return 0;
insert_before:
if (*mask != TRECHIST_MAX_RANGES_MASK)
idx = find_free_slot(*mask);
else
{ /* Drop last element and reuse its slot */
for (next = &elems[el->te_next], cur = el; next->te_next;
cur = next, next = &elems[cur->te_next])
;
idx = cur->te_next;
cur->te_next = 0;
}
*mask |= 1u << idx;;
if (el == elems)
{
elems[idx] = *el;
elems[0].te_low = packno;
elems[0].te_count = 1;
elems[0].te_next = idx;
}
else
{
assert(prev);
elems[idx].te_low = packno;
elems[idx].te_count = 1;
elems[idx].te_next = prev->te_next;
prev->te_next = idx;
}
return 0;
}
void
lsquic_trechist_iter (struct trechist_iter *iter, trechist_mask_t mask,
const struct trechist_elem *elems)
{
iter->mask = mask;
iter->elems = elems;
}
const struct lsquic_packno_range *
lsquic_trechist_first (void *iter_p)
{
struct trechist_iter *const iter = iter_p;
if (iter->mask == 0)
return NULL;
iter->next = iter->elems[0].te_next;
iter->range.low = iter->elems[0].te_low;
iter->range.high = TE_HIGH(&iter->elems[0]);
return &iter->range;
}
const struct lsquic_packno_range *
lsquic_trechist_next (void *iter_p)
{
struct trechist_iter *const iter = iter_p;
if (iter->next == 0)
return NULL;
iter->range.low = iter->elems[iter->next].te_low;
iter->range.high = TE_HIGH(&iter->elems[iter->next]);
iter->next = iter->elems[iter->next].te_next;
return &iter->range;
}
/* First TRECHIST_MAX_RANGES ranges are copied */
void
lsquic_trechist_copy_ranges (trechist_mask_t *mask,
struct trechist_elem *elems, void *src_rechist,
const struct lsquic_packno_range * (*first) (void *),
const struct lsquic_packno_range * (*next) (void *))
{
const struct lsquic_packno_range *range;
struct trechist_elem *el;
unsigned i;
for (el = NULL, i = 0, range = first(src_rechist);
i < TRECHIST_MAX_RANGES && range;
range = next(src_rechist), ++i)
{
/* This should never happen: */
assert(range->high - range->low + 1 <= UINT_MAX);
el = &elems[i];
el->te_low = range->low;
el->te_count = range->high - range->low + 1;
el->te_next = i + 1;
}
if (el)
el->te_next = 0;
if (i < 32)
*mask = (1u << i) - 1;
else
*mask = UINT32_MAX;
}
int
lsquic_trechist_contains (trechist_mask_t mask,
const struct trechist_elem *elems, uint32_t packno)
{
const struct trechist_elem *el;
if (mask == 0)
return 0;
el = &elems[0];
while (1)
{
if (packno > TE_HIGH(el))
return 0;
if (packno >= el->te_low)
return 1;
if (el->te_next)
el = &elems[el->te_next];
else
break;
}
return 0;
}
uint32_t
lsquic_trechist_max (trechist_mask_t mask, const struct trechist_elem *elems)
{
if (mask)
{
assert(mask & 1);
return TE_HIGH(&elems[0]);
}
else
return 0;
}