lsquic_rechist.c revision 229fce07
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_rechist.c -- History of received packets.
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <inttypes.h>
9#include <stdlib.h>
10#include <string.h>
11#ifdef MSVC
12#include <vc_compat.h>
13#endif
14
15#include "lsquic_int_types.h"
16#include "lsquic_types.h"
17#include "lsquic_rechist.h"
18
19#define LSQUIC_LOGGER_MODULE LSQLM_RECHIST
20#define LSQUIC_LOG_CONN_ID rechist->rh_cid
21#include "lsquic_logger.h"
22
23
24void
25lsquic_rechist_init (struct lsquic_rechist *rechist, lsquic_cid_t cid)
26{
27    memset(rechist, 0, sizeof(*rechist));
28    rechist->rh_cid = cid;
29    rechist->rh_cutoff = 1;
30    lsquic_packints_init(&rechist->rh_pints);
31    LSQ_DEBUG("instantiated received packet history");
32}
33
34
35void
36lsquic_rechist_cleanup (lsquic_rechist_t *rechist)
37{
38    lsquic_packints_cleanup(&rechist->rh_pints);
39    memset(rechist, 0, sizeof(*rechist));
40}
41
42
43enum received_st
44lsquic_rechist_received (lsquic_rechist_t *rechist, lsquic_packno_t packno,
45                         lsquic_time_t now)
46{
47    const struct lsquic_packno_range *first_range;
48
49    LSQ_DEBUG("received %"PRIu64, packno);
50    if (packno < rechist->rh_cutoff)
51    {
52        if (packno)
53            return REC_ST_DUP;
54        else
55            return REC_ST_ERR;
56    }
57
58    first_range = lsquic_packints_first(&rechist->rh_pints);
59    if (!first_range || packno > first_range->high)
60        rechist->rh_largest_acked_received = now;
61
62    switch (lsquic_packints_add(&rechist->rh_pints, packno))
63    {
64    case PACKINTS_OK:
65        ++rechist->rh_n_packets;
66        return REC_ST_OK;
67    case PACKINTS_DUP:
68        return REC_ST_DUP;
69    default:
70        assert(0);
71    case PACKINTS_ERR:
72        return REC_ST_ERR;
73    }
74}
75
76
77void
78lsquic_rechist_stop_wait (lsquic_rechist_t *rechist, lsquic_packno_t cutoff)
79{
80    LSQ_INFO("stop wait: %"PRIu64, cutoff);
81
82    if (rechist->rh_flags & RH_CUTOFF_SET)
83    {
84        assert(cutoff >= rechist->rh_cutoff);  /* Check performed in full_conn */
85        if (cutoff == rechist->rh_cutoff)
86            return;
87    }
88
89    rechist->rh_cutoff = cutoff;
90    rechist->rh_flags |= RH_CUTOFF_SET;
91    struct packet_interval *pi, *next;
92    for (pi = TAILQ_FIRST(&rechist->rh_pints.pk_intervals); pi; pi = next)
93    {
94        next = TAILQ_NEXT(pi, next_pi);
95        if (pi->range.low < cutoff)
96        {
97            if (pi->range.high < cutoff)
98            {
99                rechist->rh_n_packets -= (unsigned)(pi->range.high - pi->range.low + 1);
100                TAILQ_REMOVE(&rechist->rh_pints.pk_intervals, pi, next_pi);
101                free(pi);
102            }
103            else
104            {
105                rechist->rh_n_packets -= (unsigned)(cutoff - pi->range.low);
106                pi->range.low = cutoff;
107            }
108        }
109    }
110    lsquic_packints_sanity_check(&rechist->rh_pints);
111}
112
113
114lsquic_packno_t
115lsquic_rechist_largest_packno (const lsquic_rechist_t *rechist)
116{
117    const struct packet_interval *pi =
118                                TAILQ_FIRST(&rechist->rh_pints.pk_intervals);
119    if (pi)
120        return pi->range.high;
121    else
122        return 0;   /* Don't call this function if history is empty */
123}
124
125
126lsquic_packno_t
127lsquic_rechist_cutoff (const lsquic_rechist_t *rechist)
128{
129    if (rechist->rh_flags & RH_CUTOFF_SET)
130        return rechist->rh_cutoff;
131    else
132        return 0;
133}
134
135
136lsquic_time_t
137lsquic_rechist_largest_recv (const lsquic_rechist_t *rechist)
138{
139    return rechist->rh_largest_acked_received;
140}
141
142
143const struct lsquic_packno_range *
144lsquic_rechist_first (lsquic_rechist_t *rechist)
145{
146    return lsquic_packints_first(&rechist->rh_pints);
147}
148
149
150const struct lsquic_packno_range *
151lsquic_rechist_next (lsquic_rechist_t *rechist)
152{
153    return lsquic_packints_next(&rechist->rh_pints);
154}
155
156
157size_t
158lsquic_rechist_mem_used (const struct lsquic_rechist *rechist)
159{
160    return sizeof(*rechist)
161         - sizeof(rechist->rh_pints)
162         + lsquic_packints_mem_used(&rechist->rh_pints);
163}
164