package ackhandler import ( "fmt" "time" "github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/utils" ) type sentPacketHistory struct { rttStats *utils.RTTStats packetList *PacketList packetMap map[protocol.PacketNumber]*PacketElement highestSent protocol.PacketNumber } func newSentPacketHistory(rttStats *utils.RTTStats) *sentPacketHistory { return &sentPacketHistory{ rttStats: rttStats, packetList: NewPacketList(), packetMap: make(map[protocol.PacketNumber]*PacketElement), highestSent: protocol.InvalidPacketNumber, } } func (h *sentPacketHistory) SentPacket(p *Packet, isAckEliciting bool) { if p.PacketNumber <= h.highestSent { panic("non-sequential packet number use") } // Skipped packet numbers. for pn := h.highestSent + 1; pn < p.PacketNumber; pn++ { el := h.packetList.PushBack(Packet{ PacketNumber: pn, EncryptionLevel: p.EncryptionLevel, SendTime: p.SendTime, skippedPacket: true, }) h.packetMap[pn] = el } h.highestSent = p.PacketNumber if isAckEliciting { el := h.packetList.PushBack(*p) h.packetMap[p.PacketNumber] = el } } // Iterate iterates through all packets. func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) error { cont := true var next *PacketElement for el := h.packetList.Front(); cont && el != nil; el = next { var err error next = el.Next() cont, err = cb(&el.Value) if err != nil { return err } } return nil } // FirstOutStanding returns the first outstanding packet. func (h *sentPacketHistory) FirstOutstanding() *Packet { for el := h.packetList.Front(); el != nil; el = el.Next() { if !el.Value.declaredLost && !el.Value.skippedPacket { return &el.Value } } return nil } func (h *sentPacketHistory) Len() int { return len(h.packetMap) } func (h *sentPacketHistory) Remove(p protocol.PacketNumber) error { el, ok := h.packetMap[p] if !ok { return fmt.Errorf("packet %d not found in sent packet history", p) } h.packetList.Remove(el) delete(h.packetMap, p) return nil } func (h *sentPacketHistory) HasOutstandingPackets() bool { return h.FirstOutstanding() != nil } func (h *sentPacketHistory) DeleteOldPackets(now time.Time) { maxAge := 3 * h.rttStats.PTO(false) var nextEl *PacketElement for el := h.packetList.Front(); el != nil; el = nextEl { nextEl = el.Next() p := el.Value if p.SendTime.After(now.Add(-maxAge)) { break } if !p.skippedPacket && !p.declaredLost { // should only happen in the case of drastic RTT changes continue } delete(h.packetMap, p.PacketNumber) h.packetList.Remove(el) } }