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