lsquic_rechist.c revision b1a7c3f9
1/* Copyright (c) 2017 - 2020 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 12#include "lsquic_int_types.h" 13#include "lsquic_types.h" 14#include "lsquic_rechist.h" 15 16#define LSQUIC_LOGGER_MODULE LSQLM_RECHIST 17#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(rechist->rh_conn) 18#include "lsquic_logger.h" 19 20 21void 22lsquic_rechist_init (struct lsquic_rechist *rechist, 23 const struct lsquic_conn *conn, int ietf) 24{ 25 memset(rechist, 0, sizeof(*rechist)); 26 rechist->rh_conn = conn; 27 rechist->rh_cutoff = ietf ? 0 : 1; 28 lsquic_packints_init(&rechist->rh_pints); 29 LSQ_DEBUG("instantiated received packet history"); 30#if LSQUIC_ACK_ATTACK 31 const char *s = getenv("LSQUIC_ACK_ATTACK"); 32 if (s && atoi(s)) 33 { 34 LSQ_NOTICE("ACK attack mode ON!"); 35 rechist->rh_flags |= RH_ACK_ATTACK; 36 } 37#endif 38} 39 40 41void 42lsquic_rechist_cleanup (lsquic_rechist_t *rechist) 43{ 44 lsquic_packints_cleanup(&rechist->rh_pints); 45 memset(rechist, 0, sizeof(*rechist)); 46} 47 48 49enum received_st 50lsquic_rechist_received (lsquic_rechist_t *rechist, lsquic_packno_t packno, 51 lsquic_time_t now) 52{ 53 const struct lsquic_packno_range *first_range; 54 55 LSQ_DEBUG("received %"PRIu64, packno); 56 if (packno < rechist->rh_cutoff) 57 { 58 if (packno) 59 return REC_ST_DUP; 60 else 61 return REC_ST_ERR; 62 } 63 64 first_range = lsquic_packints_first(&rechist->rh_pints); 65 if (!first_range || packno > first_range->high) 66 rechist->rh_largest_acked_received = now; 67 68 switch (lsquic_packints_add(&rechist->rh_pints, packno)) 69 { 70 case PACKINTS_OK: 71 ++rechist->rh_n_packets; 72 return REC_ST_OK; 73 case PACKINTS_DUP: 74 return REC_ST_DUP; 75 default: 76 assert(0); 77 case PACKINTS_ERR: 78 return REC_ST_ERR; 79 } 80} 81 82 83void 84lsquic_rechist_stop_wait (lsquic_rechist_t *rechist, lsquic_packno_t cutoff) 85{ 86 LSQ_INFO("stop wait: %"PRIu64, cutoff); 87 88 if (rechist->rh_flags & RH_CUTOFF_SET) 89 { 90 assert(cutoff >= rechist->rh_cutoff); /* Check performed in full_conn */ 91 if (cutoff == rechist->rh_cutoff) 92 return; 93 } 94 95 rechist->rh_cutoff = cutoff; 96 rechist->rh_flags |= RH_CUTOFF_SET; 97 struct packet_interval *pi, *next; 98 for (pi = TAILQ_FIRST(&rechist->rh_pints.pk_intervals); pi; pi = next) 99 { 100 next = TAILQ_NEXT(pi, next_pi); 101 if (pi->range.low < cutoff) 102 { 103 if (pi->range.high < cutoff) 104 { 105 rechist->rh_n_packets -= (unsigned)(pi->range.high - pi->range.low + 1); 106 TAILQ_REMOVE(&rechist->rh_pints.pk_intervals, pi, next_pi); 107 free(pi); 108 } 109 else 110 { 111 rechist->rh_n_packets -= (unsigned)(cutoff - pi->range.low); 112 pi->range.low = cutoff; 113 } 114 } 115 } 116 lsquic_packints_sanity_check(&rechist->rh_pints); 117} 118 119 120lsquic_packno_t 121lsquic_rechist_largest_packno (const lsquic_rechist_t *rechist) 122{ 123 const struct packet_interval *pi = 124 TAILQ_FIRST(&rechist->rh_pints.pk_intervals); 125 if (pi) 126 return pi->range.high; 127 else 128 return 0; /* Don't call this function if history is empty */ 129} 130 131 132lsquic_packno_t 133lsquic_rechist_cutoff (const lsquic_rechist_t *rechist) 134{ 135 if (rechist->rh_flags & RH_CUTOFF_SET) 136 return rechist->rh_cutoff; 137 else 138 return 0; 139} 140 141 142lsquic_time_t 143lsquic_rechist_largest_recv (const lsquic_rechist_t *rechist) 144{ 145 return rechist->rh_largest_acked_received; 146} 147 148 149const struct lsquic_packno_range * 150lsquic_rechist_first (lsquic_rechist_t *rechist) 151{ 152#if LSQUIC_ACK_ATTACK 153 if (rechist->rh_flags & RH_ACK_ATTACK) 154 { 155 /* This only performs the lazy variant of the attack. An aggressive 156 * attack would increase the value of high number. 157 */ 158 const struct lsquic_packno_range *range; 159 160 range = lsquic_packints_first(&rechist->rh_pints); 161 if (!range) 162 return NULL; 163 rechist->rh_first = *range; 164 range = &TAILQ_LAST(&rechist->rh_pints.pk_intervals, pinhead)->range; 165 rechist->rh_first.low = range->low; 166 return &rechist->rh_first; 167 } 168#endif 169 return lsquic_packints_first(&rechist->rh_pints); 170} 171 172 173const struct lsquic_packno_range * 174lsquic_rechist_next (lsquic_rechist_t *rechist) 175{ 176#if LSQUIC_ACK_ATTACK 177 if (rechist->rh_flags & RH_ACK_ATTACK) 178 return NULL; 179#endif 180 return lsquic_packints_next(&rechist->rh_pints); 181} 182 183 184size_t 185lsquic_rechist_mem_used (const struct lsquic_rechist *rechist) 186{ 187 return sizeof(*rechist) 188 - sizeof(rechist->rh_pints) 189 + lsquic_packints_mem_used(&rechist->rh_pints); 190} 191 192 193const struct lsquic_packno_range * 194lsquic_rechist_peek (const struct lsquic_rechist *rechist) 195{ 196 const struct packet_interval *pint; 197 198 pint = TAILQ_FIRST(&rechist->rh_pints.pk_intervals); 199 if (pint) 200 return &pint->range; 201 else 202 return NULL; 203} 204