github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/internal/ackhandler/sent_packet_history.go (about) 1 package ackhandler 2 3 import ( 4 "fmt" 5 6 "github.com/danielpfeifer02/quic-go-prio-packs/internal/protocol" 7 "github.com/danielpfeifer02/quic-go-prio-packs/packet_setting" 8 ) 9 10 type sentPacketHistory struct { 11 packets []*packet 12 13 numOutstanding int 14 15 highestPacketNumber protocol.PacketNumber 16 } 17 18 func newSentPacketHistory() *sentPacketHistory { 19 return &sentPacketHistory{ 20 packets: make([]*packet, 0, 32), 21 highestPacketNumber: protocol.InvalidPacketNumber, 22 } 23 } 24 25 func (h *sentPacketHistory) checkSequentialPacketNumberUse(pn protocol.PacketNumber) { 26 27 // PACKET_NUMBER_TAG 28 if packet_setting.ALLOW_SETTING_PN { 29 return 30 } 31 32 if h.highestPacketNumber != protocol.InvalidPacketNumber { 33 if pn != h.highestPacketNumber+1 { 34 panic("non-sequential packet number use") 35 } 36 } 37 } 38 39 func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) { 40 h.checkSequentialPacketNumberUse(pn) 41 h.highestPacketNumber = pn 42 h.packets = append(h.packets, &packet{ 43 PacketNumber: pn, 44 skippedPacket: true, 45 }) 46 } 47 48 func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber) { 49 h.checkSequentialPacketNumberUse(pn) 50 h.highestPacketNumber = pn 51 if len(h.packets) > 0 { 52 h.packets = append(h.packets, nil) 53 } 54 } 55 56 func (h *sentPacketHistory) SentAckElicitingPacket(p *packet) { 57 h.checkSequentialPacketNumberUse(p.PacketNumber) 58 h.highestPacketNumber = p.PacketNumber 59 h.packets = append(h.packets, p) 60 if p.outstanding() { 61 h.numOutstanding++ 62 } 63 } 64 65 // Iterate iterates through all packets. 66 func (h *sentPacketHistory) Iterate(cb func(*packet) (cont bool, err error)) error { 67 for _, p := range h.packets { 68 if p == nil { 69 continue 70 } 71 cont, err := cb(p) 72 if err != nil { 73 return err 74 } 75 if !cont { 76 return nil 77 } 78 } 79 return nil 80 } 81 82 // FirstOutstanding returns the first outstanding packet. 83 func (h *sentPacketHistory) FirstOutstanding() *packet { 84 if !h.HasOutstandingPackets() { 85 return nil 86 } 87 for _, p := range h.packets { 88 if p != nil && p.outstanding() { 89 return p 90 } 91 } 92 return nil 93 } 94 95 func (h *sentPacketHistory) Len() int { 96 return len(h.packets) 97 } 98 99 func (h *sentPacketHistory) Remove(pn protocol.PacketNumber) error { 100 idx, ok := h.getIndex(pn) 101 if !ok { 102 return fmt.Errorf("packet %d not found in sent packet history", pn) 103 } 104 p := h.packets[idx] 105 if p.outstanding() { 106 h.numOutstanding-- 107 if h.numOutstanding < 0 { 108 panic("negative number of outstanding packets") 109 } 110 } 111 h.packets[idx] = nil 112 // clean up all skipped packets directly before this packet number 113 for idx > 0 { 114 idx-- 115 p := h.packets[idx] 116 if p == nil || !p.skippedPacket { 117 break 118 } 119 h.packets[idx] = nil 120 } 121 if idx == 0 { 122 h.cleanupStart() 123 } 124 if len(h.packets) > 0 && h.packets[0] == nil { 125 panic("remove failed") 126 } 127 return nil 128 } 129 130 // getIndex gets the index of packet p in the packets slice. 131 func (h *sentPacketHistory) getIndex(p protocol.PacketNumber) (int, bool) { 132 if len(h.packets) == 0 { 133 return 0, false 134 } 135 first := h.packets[0].PacketNumber 136 if p < first { 137 return 0, false 138 } 139 index := int(p - first) 140 if index > len(h.packets)-1 { 141 return 0, false 142 } 143 return index, true 144 } 145 146 func (h *sentPacketHistory) HasOutstandingPackets() bool { 147 return h.numOutstanding > 0 148 } 149 150 // delete all nil entries at the beginning of the packets slice 151 func (h *sentPacketHistory) cleanupStart() { 152 for i, p := range h.packets { 153 if p != nil { 154 h.packets = h.packets[i:] 155 return 156 } 157 } 158 h.packets = h.packets[:0] 159 } 160 161 func (h *sentPacketHistory) LowestPacketNumber() protocol.PacketNumber { 162 if len(h.packets) == 0 { 163 return protocol.InvalidPacketNumber 164 } 165 return h.packets[0].PacketNumber 166 } 167 168 func (h *sentPacketHistory) DeclareLost(pn protocol.PacketNumber) { 169 idx, ok := h.getIndex(pn) 170 if !ok { 171 return 172 } 173 p := h.packets[idx] 174 if p.outstanding() { 175 h.numOutstanding-- 176 if h.numOutstanding < 0 { 177 panic("negative number of outstanding packets") 178 } 179 } 180 h.packets[idx] = nil 181 if idx == 0 { 182 h.cleanupStart() 183 } 184 }