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