forked from quic-go/quic-go
drop duplicate packets
Duplicate detection uses the same data structure that is used to track received packets to generate ACK frames. That means that after an old ACK range has been pruned, a severly delayed packet might be incorrectly detected as a duplicate. As we wouldn't have acknowledged receipt of this packet, this situation would have resulted in a retransmission by the peer anyway, so dropping the packet won't cause a big regression.
This commit is contained in:
@@ -60,6 +60,7 @@ type sentPacketTracker interface {
|
||||
|
||||
// ReceivedPacketHandler handles ACKs needed to send for incoming packets
|
||||
type ReceivedPacketHandler interface {
|
||||
IsPotentiallyDuplicate(protocol.PacketNumber, protocol.EncryptionLevel) bool
|
||||
ReceivedPacket(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel, rcvTime time.Time, shouldInstigateAck bool) error
|
||||
DropPackets(protocol.EncryptionLevel)
|
||||
|
||||
|
||||
@@ -136,3 +136,21 @@ func (h *receivedPacketHandler) GetAckFrame(encLevel protocol.EncryptionLevel) *
|
||||
}
|
||||
return ack
|
||||
}
|
||||
|
||||
func (h *receivedPacketHandler) IsPotentiallyDuplicate(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel) bool {
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
if h.initialPackets != nil {
|
||||
return h.initialPackets.IsPotentiallyDuplicate(pn)
|
||||
}
|
||||
case protocol.EncryptionHandshake:
|
||||
if h.handshakePackets != nil {
|
||||
return h.handshakePackets.IsPotentiallyDuplicate(pn)
|
||||
}
|
||||
case protocol.Encryption0RTT, protocol.Encryption1RTT:
|
||||
if h.appDataPackets != nil {
|
||||
return h.appDataPackets.IsPotentiallyDuplicate(pn)
|
||||
}
|
||||
}
|
||||
panic("unexpected encryption level")
|
||||
}
|
||||
|
||||
@@ -122,4 +122,26 @@ var _ = Describe("Received Packet Handler", func() {
|
||||
Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(4)))
|
||||
})
|
||||
|
||||
It("says if packets are duplicates", func() {
|
||||
sendTime := time.Now()
|
||||
sentPackets.EXPECT().GetLowestPacketNotConfirmedAcked().AnyTimes()
|
||||
// Initial
|
||||
Expect(handler.IsPotentiallyDuplicate(3, protocol.EncryptionInitial)).To(BeFalse())
|
||||
Expect(handler.ReceivedPacket(3, protocol.EncryptionInitial, sendTime, true)).To(Succeed())
|
||||
Expect(handler.IsPotentiallyDuplicate(3, protocol.EncryptionInitial)).To(BeTrue())
|
||||
// Handshake
|
||||
Expect(handler.IsPotentiallyDuplicate(3, protocol.EncryptionHandshake)).To(BeFalse())
|
||||
Expect(handler.ReceivedPacket(3, protocol.EncryptionHandshake, sendTime, true)).To(Succeed())
|
||||
Expect(handler.IsPotentiallyDuplicate(3, protocol.EncryptionHandshake)).To(BeTrue())
|
||||
// 0-RTT
|
||||
Expect(handler.IsPotentiallyDuplicate(3, protocol.Encryption0RTT)).To(BeFalse())
|
||||
Expect(handler.ReceivedPacket(3, protocol.Encryption0RTT, sendTime, true)).To(Succeed())
|
||||
Expect(handler.IsPotentiallyDuplicate(3, protocol.Encryption0RTT)).To(BeTrue())
|
||||
// 1-RTT
|
||||
Expect(handler.IsPotentiallyDuplicate(3, protocol.Encryption1RTT)).To(BeTrue())
|
||||
Expect(handler.IsPotentiallyDuplicate(4, protocol.Encryption1RTT)).To(BeFalse())
|
||||
Expect(handler.ReceivedPacket(4, protocol.Encryption1RTT, sendTime, true)).To(Succeed())
|
||||
Expect(handler.IsPotentiallyDuplicate(4, protocol.Encryption1RTT)).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -128,3 +128,18 @@ func (h *receivedPacketHistory) GetHighestAckRange() wire.AckRange {
|
||||
}
|
||||
return ackRange
|
||||
}
|
||||
|
||||
func (h *receivedPacketHistory) IsPotentiallyDuplicate(p protocol.PacketNumber) bool {
|
||||
if p < h.deletedBelow {
|
||||
return true
|
||||
}
|
||||
for el := h.ranges.Back(); el != nil; el = el.Prev() {
|
||||
if p > el.Value.End {
|
||||
return false
|
||||
}
|
||||
if p <= el.Value.End && p >= el.Value.Start {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -246,4 +246,55 @@ var _ = Describe("receivedPacketHistory", func() {
|
||||
Expect(hist.GetHighestAckRange()).To(Equal(wire.AckRange{Smallest: 6, Largest: 7}))
|
||||
})
|
||||
})
|
||||
|
||||
Context("duplicate detection", func() {
|
||||
It("doesn't declare the first packet a duplicate", func() {
|
||||
Expect(hist.IsPotentiallyDuplicate(5)).To(BeFalse())
|
||||
})
|
||||
|
||||
It("detects a duplicate in a range", func() {
|
||||
hist.ReceivedPacket(4)
|
||||
hist.ReceivedPacket(5)
|
||||
hist.ReceivedPacket(6)
|
||||
Expect(hist.IsPotentiallyDuplicate(3)).To(BeFalse())
|
||||
Expect(hist.IsPotentiallyDuplicate(4)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(5)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(6)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(7)).To(BeFalse())
|
||||
})
|
||||
|
||||
It("detects a duplicate in multiple ranges", func() {
|
||||
hist.ReceivedPacket(4)
|
||||
hist.ReceivedPacket(5)
|
||||
hist.ReceivedPacket(8)
|
||||
hist.ReceivedPacket(9)
|
||||
Expect(hist.IsPotentiallyDuplicate(3)).To(BeFalse())
|
||||
Expect(hist.IsPotentiallyDuplicate(4)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(5)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(6)).To(BeFalse())
|
||||
Expect(hist.IsPotentiallyDuplicate(7)).To(BeFalse())
|
||||
Expect(hist.IsPotentiallyDuplicate(8)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(9)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(10)).To(BeFalse())
|
||||
})
|
||||
|
||||
It("says a packet is a potentially duplicate if the ranges were already deleted", func() {
|
||||
hist.ReceivedPacket(4)
|
||||
hist.ReceivedPacket(5)
|
||||
hist.ReceivedPacket(8)
|
||||
hist.ReceivedPacket(9)
|
||||
hist.ReceivedPacket(11)
|
||||
hist.DeleteBelow(8)
|
||||
Expect(hist.IsPotentiallyDuplicate(3)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(4)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(5)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(6)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(7)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(8)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(9)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(10)).To(BeFalse())
|
||||
Expect(hist.IsPotentiallyDuplicate(11)).To(BeTrue())
|
||||
Expect(hist.IsPotentiallyDuplicate(12)).To(BeFalse())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -188,3 +188,7 @@ func (h *receivedPacketTracker) GetAckFrame() *wire.AckFrame {
|
||||
}
|
||||
|
||||
func (h *receivedPacketTracker) GetAlarmTimeout() time.Time { return h.ackAlarm }
|
||||
|
||||
func (h *receivedPacketTracker) IsPotentiallyDuplicate(pn protocol.PacketNumber) bool {
|
||||
return h.packetHistory.IsPotentiallyDuplicate(pn)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user