litespeed-quic/src/liblsquic/lsquic_packints.c

139 lines
2.9 KiB
C

/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_packints.c -- Packet intervals implementation.
*/
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/queue.h>
#include "lsquic_int_types.h"
#include "lsquic_packints.h"
void
lsquic_packints_init (struct packints *pints)
{
TAILQ_INIT(&pints->pk_intervals);
pints->pk_cur = NULL;
}
void
lsquic_packints_cleanup (struct packints *pints)
{
struct packet_interval *pi, *next;
for (pi = TAILQ_FIRST(&pints->pk_intervals); pi; pi = next)
{
next = TAILQ_NEXT(pi, next_pi);
free(pi);
}
}
static int
grow_pi (struct packet_interval *pi, lsquic_packno_t packno)
{
if (pi->range.low - 1 == packno) {
--pi->range.low;
return 1;
}
if (pi->range.high + 1 == packno) {
++pi->range.high;
return 1;
}
return 0;
}
#if LSQUIC_PACKINTS_SANITY_CHECK
void
lsquic_packints_sanity_check (const struct packints *packints)
{
struct packet_interval *pi;
uint64_t prev_high;
prev_high = 0;
TAILQ_FOREACH(pi, &packints->pk_intervals, next_pi)
{
if (prev_high)
{
assert(pi->range.high + 1 < prev_high);
assert(pi->range.high >= pi->range.low);
}
else
prev_high = pi->range.high;
}
}
#endif
enum packints_status
lsquic_packints_add (struct packints *pints, lsquic_packno_t packno)
{
struct packet_interval *pi, *prev;
prev = NULL;
TAILQ_FOREACH(pi, &pints->pk_intervals, next_pi)
{
if (packno <= pi->range.high)
{
if (packno >= pi->range.low)
return PACKINTS_DUP;
} else {
if (packno > pi->range.high)
break;
}
prev = pi;
}
if ((prev && grow_pi(prev, packno)) || (pi && grow_pi(pi, packno)))
{
if (prev && pi && (prev->range.low - 1 == pi->range.high)) {
prev->range.low = pi->range.low;
TAILQ_REMOVE(&pints->pk_intervals, pi, next_pi);
free(pi);
}
}
else
{
struct packet_interval *newpi = malloc(sizeof(*newpi));
if (!newpi)
return PACKINTS_ERR;
newpi->range.low = newpi->range.high = packno;
if (pi)
TAILQ_INSERT_BEFORE(pi, newpi, next_pi);
else
TAILQ_INSERT_TAIL(&pints->pk_intervals, newpi, next_pi);
}
lsquic_packints_sanity_check(pints);
return PACKINTS_OK;
}
const struct lsquic_packno_range *
lsquic_packints_first (struct packints *pints)
{
pints->pk_cur = TAILQ_FIRST(&pints->pk_intervals);
return lsquic_packints_next(pints);
}
const struct lsquic_packno_range *
lsquic_packints_next (struct packints *pints)
{
const struct lsquic_packno_range *range;
if (pints->pk_cur)
{
range = &pints->pk_cur->range;
pints->pk_cur = TAILQ_NEXT(pints->pk_cur, next_pi);
return range;
}
else
return NULL;
}