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:
Marten Seemann
2020-05-27 09:20:51 +07:00
parent fd5ecee85d
commit 440ff107a3
10 changed files with 170 additions and 4 deletions

View File

@@ -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)

View File

@@ -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")
}

View File

@@ -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())
})
})

View File

@@ -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
}

View File

@@ -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())
})
})
})

View File

@@ -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)
}