github.com/quic-go/quic-go@v0.44.0/internal/ackhandler/received_packet_history.go (about)

     1  package ackhandler
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/quic-go/quic-go/internal/protocol"
     7  	list "github.com/quic-go/quic-go/internal/utils/linkedlist"
     8  	"github.com/quic-go/quic-go/internal/wire"
     9  )
    10  
    11  // interval is an interval from one PacketNumber to the other
    12  type interval struct {
    13  	Start protocol.PacketNumber
    14  	End   protocol.PacketNumber
    15  }
    16  
    17  var intervalElementPool sync.Pool
    18  
    19  func init() {
    20  	intervalElementPool = *list.NewPool[interval]()
    21  }
    22  
    23  // The receivedPacketHistory stores if a packet number has already been received.
    24  // It generates ACK ranges which can be used to assemble an ACK frame.
    25  // It does not store packet contents.
    26  type receivedPacketHistory struct {
    27  	ranges *list.List[interval]
    28  
    29  	deletedBelow protocol.PacketNumber
    30  }
    31  
    32  func newReceivedPacketHistory() *receivedPacketHistory {
    33  	return &receivedPacketHistory{
    34  		ranges: list.NewWithPool[interval](&intervalElementPool),
    35  	}
    36  }
    37  
    38  // ReceivedPacket registers a packet with PacketNumber p and updates the ranges
    39  func (h *receivedPacketHistory) ReceivedPacket(p protocol.PacketNumber) bool /* is a new packet (and not a duplicate / delayed packet) */ {
    40  	// ignore delayed packets, if we already deleted the range
    41  	if p < h.deletedBelow {
    42  		return false
    43  	}
    44  	isNew := h.addToRanges(p)
    45  	h.maybeDeleteOldRanges()
    46  	return isNew
    47  }
    48  
    49  func (h *receivedPacketHistory) addToRanges(p protocol.PacketNumber) bool /* is a new packet (and not a duplicate / delayed packet) */ {
    50  	if h.ranges.Len() == 0 {
    51  		h.ranges.PushBack(interval{Start: p, End: p})
    52  		return true
    53  	}
    54  
    55  	for el := h.ranges.Back(); el != nil; el = el.Prev() {
    56  		// p already included in an existing range. Nothing to do here
    57  		if p >= el.Value.Start && p <= el.Value.End {
    58  			return false
    59  		}
    60  
    61  		if el.Value.End == p-1 { // extend a range at the end
    62  			el.Value.End = p
    63  			return true
    64  		}
    65  		if el.Value.Start == p+1 { // extend a range at the beginning
    66  			el.Value.Start = p
    67  
    68  			prev := el.Prev()
    69  			if prev != nil && prev.Value.End+1 == el.Value.Start { // merge two ranges
    70  				prev.Value.End = el.Value.End
    71  				h.ranges.Remove(el)
    72  			}
    73  			return true
    74  		}
    75  
    76  		// create a new range at the end
    77  		if p > el.Value.End {
    78  			h.ranges.InsertAfter(interval{Start: p, End: p}, el)
    79  			return true
    80  		}
    81  	}
    82  
    83  	// create a new range at the beginning
    84  	h.ranges.InsertBefore(interval{Start: p, End: p}, h.ranges.Front())
    85  	return true
    86  }
    87  
    88  // Delete old ranges, if we're tracking more than 500 of them.
    89  // This is a DoS defense against a peer that sends us too many gaps.
    90  func (h *receivedPacketHistory) maybeDeleteOldRanges() {
    91  	for h.ranges.Len() > protocol.MaxNumAckRanges {
    92  		h.ranges.Remove(h.ranges.Front())
    93  	}
    94  }
    95  
    96  // DeleteBelow deletes all entries below (but not including) p
    97  func (h *receivedPacketHistory) DeleteBelow(p protocol.PacketNumber) {
    98  	if p < h.deletedBelow {
    99  		return
   100  	}
   101  	h.deletedBelow = p
   102  
   103  	nextEl := h.ranges.Front()
   104  	for el := h.ranges.Front(); nextEl != nil; el = nextEl {
   105  		nextEl = el.Next()
   106  
   107  		if el.Value.End < p { // delete a whole range
   108  			h.ranges.Remove(el)
   109  		} else if p > el.Value.Start && p <= el.Value.End {
   110  			el.Value.Start = p
   111  			return
   112  		} else { // no ranges affected. Nothing to do
   113  			return
   114  		}
   115  	}
   116  }
   117  
   118  // AppendAckRanges appends to a slice of all AckRanges that can be used in an AckFrame
   119  func (h *receivedPacketHistory) AppendAckRanges(ackRanges []wire.AckRange) []wire.AckRange {
   120  	if h.ranges.Len() > 0 {
   121  		for el := h.ranges.Back(); el != nil; el = el.Prev() {
   122  			ackRanges = append(ackRanges, wire.AckRange{Smallest: el.Value.Start, Largest: el.Value.End})
   123  		}
   124  	}
   125  	return ackRanges
   126  }
   127  
   128  func (h *receivedPacketHistory) GetHighestAckRange() wire.AckRange {
   129  	ackRange := wire.AckRange{}
   130  	if h.ranges.Len() > 0 {
   131  		r := h.ranges.Back().Value
   132  		ackRange.Smallest = r.Start
   133  		ackRange.Largest = r.End
   134  	}
   135  	return ackRange
   136  }
   137  
   138  func (h *receivedPacketHistory) IsPotentiallyDuplicate(p protocol.PacketNumber) bool {
   139  	if p < h.deletedBelow {
   140  		return true
   141  	}
   142  	for el := h.ranges.Back(); el != nil; el = el.Prev() {
   143  		if p > el.Value.End {
   144  			return false
   145  		}
   146  		if p <= el.Value.End && p >= el.Value.Start {
   147  			return true
   148  		}
   149  	}
   150  	return false
   151  }