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