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