lsquic_senhist.c revision c51ce338
150aadb33SDmitri Tikhonov/* Copyright (c) 2017 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov/*
350aadb33SDmitri Tikhonov * lsquic_senhist.c -- Sent history implementation
450aadb33SDmitri Tikhonov */
550aadb33SDmitri Tikhonov
650aadb33SDmitri Tikhonov#include <assert.h>
750aadb33SDmitri Tikhonov#include <inttypes.h>
850aadb33SDmitri Tikhonov#include <stdio.h>
950aadb33SDmitri Tikhonov#include <stdlib.h>
1050aadb33SDmitri Tikhonov#include <string.h>
1150aadb33SDmitri Tikhonov
1250aadb33SDmitri Tikhonov#include "lsquic_int_types.h"
1350aadb33SDmitri Tikhonov#include "lsquic_senhist.h"
1450aadb33SDmitri Tikhonov
1550aadb33SDmitri Tikhonov
1650aadb33SDmitri Tikhonovvoid
1750aadb33SDmitri Tikhonovlsquic_senhist_init (lsquic_senhist_t *hist)
1850aadb33SDmitri Tikhonov{
1950aadb33SDmitri Tikhonov    lsquic_packints_init(&hist->sh_pints);
2050aadb33SDmitri Tikhonov#ifndef NDEBUG
2150aadb33SDmitri Tikhonov    {
2250aadb33SDmitri Tikhonov        const char *env;
2350aadb33SDmitri Tikhonov        env = getenv("LSQUIC_REORDER_SENT");
2450aadb33SDmitri Tikhonov        if (env && atoi(env))
2550aadb33SDmitri Tikhonov            hist->sh_flags = SH_REORDER;
2650aadb33SDmitri Tikhonov        else
2750aadb33SDmitri Tikhonov            hist->sh_flags = 0;
2850aadb33SDmitri Tikhonov    }
2950aadb33SDmitri Tikhonov#endif
3050aadb33SDmitri Tikhonov}
3150aadb33SDmitri Tikhonov
3250aadb33SDmitri Tikhonov
3350aadb33SDmitri Tikhonovvoid
3450aadb33SDmitri Tikhonovlsquic_senhist_cleanup (lsquic_senhist_t *hist)
3550aadb33SDmitri Tikhonov{
3650aadb33SDmitri Tikhonov    lsquic_packints_cleanup(&hist->sh_pints);
3750aadb33SDmitri Tikhonov}
3850aadb33SDmitri Tikhonov
3950aadb33SDmitri Tikhonov
4050aadb33SDmitri Tikhonov/* At the time of this writing, the only reason the sequence of sent
4150aadb33SDmitri Tikhonov * packet numbers could contain a hole is elision of stream frames from
4250aadb33SDmitri Tikhonov * scheduled, but delayed packets.  If such packet becomes empty after
4350aadb33SDmitri Tikhonov * elision, it is dropped from the queue.
4450aadb33SDmitri Tikhonov */
4550aadb33SDmitri Tikhonov
4650aadb33SDmitri Tikhonov
4750aadb33SDmitri Tikhonov/* The fast insert is used in the normal case, when packets are sent
4850aadb33SDmitri Tikhonov * out in the same order in which they are scheduled: that is, their
4950aadb33SDmitri Tikhonov * packet numbers are always increasing.
5050aadb33SDmitri Tikhonov */
5150aadb33SDmitri Tikhonovstatic int
5250aadb33SDmitri Tikhonovsenhist_add_fast (lsquic_senhist_t *hist, lsquic_packno_t packno)
5350aadb33SDmitri Tikhonov{
5450aadb33SDmitri Tikhonov    struct packet_interval *pi;
5550aadb33SDmitri Tikhonov
5650aadb33SDmitri Tikhonov    pi = TAILQ_FIRST(&hist->sh_pints.pk_intervals);
5750aadb33SDmitri Tikhonov    if (pi)
5850aadb33SDmitri Tikhonov    {
5950aadb33SDmitri Tikhonov        /* Check that packet numbers are always increasing */
6050aadb33SDmitri Tikhonov        assert(packno > pi->range.high);
6150aadb33SDmitri Tikhonov        if (packno == pi->range.high + 1)
6250aadb33SDmitri Tikhonov        {
6350aadb33SDmitri Tikhonov            ++pi->range.high;
6450aadb33SDmitri Tikhonov            return 0;
6550aadb33SDmitri Tikhonov        }
6650aadb33SDmitri Tikhonov    }
6750aadb33SDmitri Tikhonov
6850aadb33SDmitri Tikhonov    pi = malloc(sizeof(*pi));
6950aadb33SDmitri Tikhonov    if (!pi)
7050aadb33SDmitri Tikhonov        return -1;
7150aadb33SDmitri Tikhonov    pi->range.high = packno;
7250aadb33SDmitri Tikhonov    pi->range.low = packno;
7350aadb33SDmitri Tikhonov    TAILQ_INSERT_HEAD(&hist->sh_pints.pk_intervals, pi, next_pi);
7450aadb33SDmitri Tikhonov    return 0;
7550aadb33SDmitri Tikhonov}
7650aadb33SDmitri Tikhonov
7750aadb33SDmitri Tikhonov
7850aadb33SDmitri Tikhonov#ifndef NDEBUG
7950aadb33SDmitri Tikhonovstatic int
8050aadb33SDmitri Tikhonovsenhist_add_slow (lsquic_senhist_t *hist, lsquic_packno_t packno)
8150aadb33SDmitri Tikhonov{
8250aadb33SDmitri Tikhonov    switch (lsquic_packints_add(&hist->sh_pints, packno))
8350aadb33SDmitri Tikhonov    {
8450aadb33SDmitri Tikhonov    case PACKINTS_OK:
8550aadb33SDmitri Tikhonov        return 0;
8650aadb33SDmitri Tikhonov    case PACKINTS_DUP:  /* We should not generate duplicate packet numbers! */
8750aadb33SDmitri Tikhonov    default:
8850aadb33SDmitri Tikhonov        assert(0);
8950aadb33SDmitri Tikhonov    case PACKINTS_ERR:
9050aadb33SDmitri Tikhonov        return -1;
9150aadb33SDmitri Tikhonov    }
9250aadb33SDmitri Tikhonov}
9350aadb33SDmitri Tikhonov#endif
9450aadb33SDmitri Tikhonov
9550aadb33SDmitri Tikhonov
9650aadb33SDmitri Tikhonovint
9750aadb33SDmitri Tikhonovlsquic_senhist_add (lsquic_senhist_t *hist, lsquic_packno_t packno)
9850aadb33SDmitri Tikhonov{
9950aadb33SDmitri Tikhonov#ifndef NDEBUG
10050aadb33SDmitri Tikhonov    if (hist->sh_flags & SH_REORDER)
10150aadb33SDmitri Tikhonov        return senhist_add_slow(hist, packno);
10250aadb33SDmitri Tikhonov    else
10350aadb33SDmitri Tikhonov#endif
10450aadb33SDmitri Tikhonov        return senhist_add_fast(hist, packno);
10550aadb33SDmitri Tikhonov}
10650aadb33SDmitri Tikhonov
10750aadb33SDmitri Tikhonov
10850aadb33SDmitri Tikhonovint
10950aadb33SDmitri Tikhonovlsquic_senhist_sent_range (lsquic_senhist_t *hist, lsquic_packno_t low,
11050aadb33SDmitri Tikhonov                                                   lsquic_packno_t high)
11150aadb33SDmitri Tikhonov{
11250aadb33SDmitri Tikhonov    const struct lsquic_packno_range *range;
11350aadb33SDmitri Tikhonov    for (range = lsquic_packints_first(&hist->sh_pints); range;
11450aadb33SDmitri Tikhonov                            range = lsquic_packints_next(&hist->sh_pints))
11550aadb33SDmitri Tikhonov        if (range->low <= low && range->high >= high)
11650aadb33SDmitri Tikhonov            return 1;
11750aadb33SDmitri Tikhonov    return 0;
11850aadb33SDmitri Tikhonov}
11950aadb33SDmitri Tikhonov
12050aadb33SDmitri Tikhonov
12150aadb33SDmitri Tikhonovlsquic_packno_t
12250aadb33SDmitri Tikhonovlsquic_senhist_largest (lsquic_senhist_t *hist)
12350aadb33SDmitri Tikhonov{
12450aadb33SDmitri Tikhonov    const struct lsquic_packno_range *range;
12550aadb33SDmitri Tikhonov    range = lsquic_packints_first(&hist->sh_pints);
12650aadb33SDmitri Tikhonov    if (range)
12750aadb33SDmitri Tikhonov        return range->high;
12850aadb33SDmitri Tikhonov    else
12950aadb33SDmitri Tikhonov        return 0;
13050aadb33SDmitri Tikhonov}
13150aadb33SDmitri Tikhonov
13250aadb33SDmitri Tikhonov
13350aadb33SDmitri Tikhonovvoid
13450aadb33SDmitri Tikhonovlsquic_senhist_tostr (lsquic_senhist_t *hist, char *buf, size_t bufsz)
13550aadb33SDmitri Tikhonov{
13650aadb33SDmitri Tikhonov    const struct lsquic_packno_range *range;
13750aadb33SDmitri Tikhonov    size_t off;
13850aadb33SDmitri Tikhonov    int n;
13950aadb33SDmitri Tikhonov    for (off = 0, range = lsquic_packints_first(&hist->sh_pints);
14050aadb33SDmitri Tikhonov            range && off < bufsz;
14150aadb33SDmitri Tikhonov                off += n, range = lsquic_packints_next(&hist->sh_pints))
14250aadb33SDmitri Tikhonov    {
14350aadb33SDmitri Tikhonov        n = snprintf(buf + off, bufsz - off, "[%"PRIu64"-%"PRIu64"]",
14450aadb33SDmitri Tikhonov                                                    range->high, range->low);
14550aadb33SDmitri Tikhonov        if (n < 0 || (size_t) n >= bufsz - off)
14650aadb33SDmitri Tikhonov            break;
14750aadb33SDmitri Tikhonov    }
14850aadb33SDmitri Tikhonov    if (bufsz > 0)
14950aadb33SDmitri Tikhonov        buf[off] = '\0';
15050aadb33SDmitri Tikhonov}
151c51ce338SDmitri Tikhonov
152c51ce338SDmitri Tikhonov
153c51ce338SDmitri Tikhonovsize_t
154c51ce338SDmitri Tikhonovlsquic_senhist_mem_used (const struct lsquic_senhist *hist)
155c51ce338SDmitri Tikhonov{
156c51ce338SDmitri Tikhonov    return sizeof(*hist)
157c51ce338SDmitri Tikhonov         - sizeof(hist->sh_pints)
158c51ce338SDmitri Tikhonov         + lsquic_packints_mem_used(&hist->sh_pints);
159c51ce338SDmitri Tikhonov}
160