github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/internal/ackhandler/sent_packet_history.go (about)

     1  package ackhandler
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/metacubex/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  }