lsquic_rechist.c revision ab5c8df2
1/* Copyright (c) 2017 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 -= 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