lsquic_senhist.c revision bfc7bfd8
1/* Copyright (c) 2017 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_senhist.c -- Sent history implementation
4 */
5
6#include <assert.h>
7#include <inttypes.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include "lsquic_int_types.h"
13#include "lsquic_senhist.h"
14
15
16void
17lsquic_senhist_init (lsquic_senhist_t *hist)
18{
19    lsquic_packints_init(&hist->sh_pints);
20}
21
22
23void
24lsquic_senhist_cleanup (lsquic_senhist_t *hist)
25{
26    lsquic_packints_cleanup(&hist->sh_pints);
27}
28
29
30/* At the time of this writing, the only reason the sequence of sent
31 * packet numbers could contain a hole is elision of stream frames from
32 * scheduled, but delayed packets.  If such packet becomes empty after
33 * elision, it is dropped from the queue.
34 */
35
36
37/* The fast insert is used in the normal case, when packets are sent
38 * out in the same order in which they are scheduled: that is, their
39 * packet numbers are always increasing.
40 */
41static int
42senhist_add_fast (lsquic_senhist_t *hist, lsquic_packno_t packno)
43{
44    struct packet_interval *pi;
45
46    pi = TAILQ_FIRST(&hist->sh_pints.pk_intervals);
47    if (pi)
48    {
49        /* Check that packet numbers are always increasing */
50        assert(packno > pi->range.high);
51        if (packno == pi->range.high + 1)
52        {
53            ++pi->range.high;
54            return 0;
55        }
56    }
57
58    pi = malloc(sizeof(*pi));
59    if (!pi)
60        return -1;
61    pi->range.high = packno;
62    pi->range.low = packno;
63    TAILQ_INSERT_HEAD(&hist->sh_pints.pk_intervals, pi, next_pi);
64    return 0;
65}
66
67
68int
69lsquic_senhist_add (lsquic_senhist_t *hist, lsquic_packno_t packno)
70{
71        return senhist_add_fast(hist, packno);
72}
73
74
75int
76lsquic_senhist_sent_range (lsquic_senhist_t *hist, lsquic_packno_t low,
77                                                   lsquic_packno_t high)
78{
79    const struct lsquic_packno_range *range;
80    for (range = lsquic_packints_first(&hist->sh_pints); range;
81                            range = lsquic_packints_next(&hist->sh_pints))
82        if (range->low <= low && range->high >= high)
83            return 1;
84    return 0;
85}
86
87
88lsquic_packno_t
89lsquic_senhist_largest (lsquic_senhist_t *hist)
90{
91    const struct lsquic_packno_range *range;
92    range = lsquic_packints_first(&hist->sh_pints);
93    if (range)
94        return range->high;
95    else
96        return 0;
97}
98
99
100void
101lsquic_senhist_tostr (lsquic_senhist_t *hist, char *buf, size_t bufsz)
102{
103    const struct lsquic_packno_range *range;
104    size_t off;
105    int n;
106    for (off = 0, range = lsquic_packints_first(&hist->sh_pints);
107            range && off < bufsz;
108                off += n, range = lsquic_packints_next(&hist->sh_pints))
109    {
110        n = snprintf(buf + off, bufsz - off, "[%"PRIu64"-%"PRIu64"]",
111                                                    range->high, range->low);
112        if (n < 0 || (size_t) n >= bufsz - off)
113            break;
114    }
115    if (bufsz > 0)
116        buf[off] = '\0';
117}
118
119
120size_t
121lsquic_senhist_mem_used (const struct lsquic_senhist *hist)
122{
123    return sizeof(*hist)
124         - sizeof(hist->sh_pints)
125         + lsquic_packints_mem_used(&hist->sh_pints);
126}
127
128
129