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