forked from quic-go/quic-go
ack NACK handling
This commit is contained in:
@@ -12,6 +12,7 @@ type outgoingPacketAckHandler struct {
|
||||
lastSentPacketNumber protocol.PacketNumber
|
||||
highestInOrderAckedPacketNumber protocol.PacketNumber
|
||||
highestInOrderAckedEntropy EntropyAccumulator
|
||||
LargestObserved protocol.PacketNumber
|
||||
packetHistory map[protocol.PacketNumber]*Packet
|
||||
packetHistoryMutex sync.Mutex
|
||||
}
|
||||
@@ -56,7 +57,12 @@ func (h *outgoingPacketAckHandler) ReceivedAck(ackFrame *frames.AckFrame) error
|
||||
return errors.New("OutgoingPacketAckHandler: Received ACK for an unsent package")
|
||||
}
|
||||
|
||||
if ackFrame.LargestObserved <= h.LargestObserved { // duplicate or out-of-order AckFrame
|
||||
return nil
|
||||
}
|
||||
|
||||
entropyError := errors.New("OutgoingPacketAckHandler: Wrong entropy")
|
||||
mapAccessError := errors.New("OutgoingPacketAckHandler: Packet does not exist in PacketHistory")
|
||||
|
||||
h.packetHistoryMutex.Lock()
|
||||
defer h.packetHistoryMutex.Unlock()
|
||||
@@ -64,21 +70,78 @@ func (h *outgoingPacketAckHandler) ReceivedAck(ackFrame *frames.AckFrame) error
|
||||
highestInOrderAckedEntropy := h.highestInOrderAckedEntropy
|
||||
highestInOrderAckedPacketNumber := ackFrame.GetHighestInOrderPacketNumber()
|
||||
for i := h.highestInOrderAckedPacketNumber + 1; i <= highestInOrderAckedPacketNumber; i++ {
|
||||
highestInOrderAckedEntropy.Add(h.packetHistory[i].PacketNumber, h.packetHistory[i].EntropyBit)
|
||||
packet, ok := h.packetHistory[i]
|
||||
if !ok {
|
||||
return mapAccessError
|
||||
}
|
||||
highestInOrderAckedEntropy.Add(packet.PacketNumber, packet.EntropyBit)
|
||||
}
|
||||
|
||||
var expectedEntropy EntropyAccumulator
|
||||
|
||||
if !ackFrame.HasNACK() {
|
||||
if ackFrame.Entropy != byte(h.packetHistory[ackFrame.LargestObserved].Entropy) {
|
||||
return entropyError
|
||||
packet, ok := h.packetHistory[ackFrame.LargestObserved]
|
||||
if !ok {
|
||||
return mapAccessError
|
||||
}
|
||||
expectedEntropy = packet.Entropy
|
||||
} else {
|
||||
if highestInOrderAckedPacketNumber == h.highestInOrderAckedPacketNumber {
|
||||
expectedEntropy = h.highestInOrderAckedEntropy
|
||||
} else {
|
||||
packet, ok := h.packetHistory[highestInOrderAckedPacketNumber]
|
||||
if !ok {
|
||||
return mapAccessError
|
||||
}
|
||||
expectedEntropy = packet.Entropy
|
||||
}
|
||||
|
||||
nackRangeIndex := len(ackFrame.NackRanges) - 1
|
||||
nackRange := ackFrame.NackRanges[nackRangeIndex]
|
||||
for i := highestInOrderAckedPacketNumber + 1; i <= ackFrame.LargestObserved; i++ {
|
||||
if i > nackRange.LastPacketNumber {
|
||||
nackRangeIndex--
|
||||
if nackRangeIndex >= 0 {
|
||||
nackRange = ackFrame.NackRanges[nackRangeIndex]
|
||||
}
|
||||
}
|
||||
if i >= nackRange.FirstPacketNumber && i <= nackRange.LastPacketNumber {
|
||||
continue
|
||||
}
|
||||
packet, ok := h.packetHistory[i]
|
||||
if !ok {
|
||||
return mapAccessError
|
||||
}
|
||||
expectedEntropy.Add(i, packet.EntropyBit)
|
||||
}
|
||||
}
|
||||
// ToDo: check entropy for ACKs with NACKs
|
||||
|
||||
if ackFrame.Entropy != byte(expectedEntropy) {
|
||||
return entropyError
|
||||
}
|
||||
|
||||
// Entropy ok. Now actually process the ACK packet
|
||||
for i := h.highestInOrderAckedPacketNumber; i <= highestInOrderAckedPacketNumber; i++ {
|
||||
delete(h.packetHistory, i)
|
||||
}
|
||||
|
||||
if ackFrame.HasNACK() {
|
||||
nackRangeIndex := len(ackFrame.NackRanges) - 1
|
||||
nackRange := ackFrame.NackRanges[nackRangeIndex]
|
||||
for i := highestInOrderAckedPacketNumber + 1; i <= ackFrame.LargestObserved; i++ {
|
||||
if i > nackRange.LastPacketNumber {
|
||||
nackRangeIndex--
|
||||
if nackRangeIndex >= 0 {
|
||||
nackRange = ackFrame.NackRanges[nackRangeIndex]
|
||||
}
|
||||
}
|
||||
if i >= nackRange.FirstPacketNumber && i <= nackRange.LastPacketNumber {
|
||||
continue
|
||||
}
|
||||
delete(h.packetHistory, i)
|
||||
}
|
||||
}
|
||||
|
||||
h.highestInOrderAckedPacketNumber = highestInOrderAckedPacketNumber
|
||||
h.highestInOrderAckedEntropy = highestInOrderAckedEntropy
|
||||
return nil
|
||||
|
||||
@@ -14,7 +14,7 @@ var _ = Describe("AckHandler", func() {
|
||||
})
|
||||
|
||||
Context("SentPacket", func() {
|
||||
It("accepts three consecutive packets", func() {
|
||||
It("accepts two consecutive packets", func() {
|
||||
entropy := EntropyAccumulator(0)
|
||||
packet1 := Packet{PacketNumber: 1, Plaintext: []byte{0x13, 0x37}, EntropyBit: true}
|
||||
packet2 := Packet{PacketNumber: 2, Plaintext: []byte{0xBE, 0xEF}, EntropyBit: true}
|
||||
@@ -85,10 +85,10 @@ var _ = Describe("AckHandler", func() {
|
||||
BeforeEach(func() {
|
||||
packets = []*Packet{
|
||||
&Packet{PacketNumber: 1, Plaintext: []byte{0x13, 0x37}, EntropyBit: true},
|
||||
&Packet{PacketNumber: 2, Plaintext: []byte{0xBE, 0xEF}, EntropyBit: false},
|
||||
&Packet{PacketNumber: 2, Plaintext: []byte{0xBE, 0xEF}, EntropyBit: true},
|
||||
&Packet{PacketNumber: 3, Plaintext: []byte{0xCA, 0xFE}, EntropyBit: true},
|
||||
&Packet{PacketNumber: 4, Plaintext: []byte{0x54, 0x32}, EntropyBit: true},
|
||||
&Packet{PacketNumber: 5, Plaintext: []byte{0x54, 0x32}, EntropyBit: false},
|
||||
&Packet{PacketNumber: 5, Plaintext: []byte{0x54, 0x32}, EntropyBit: true},
|
||||
&Packet{PacketNumber: 6, Plaintext: []byte{0x54, 0x32}, EntropyBit: true},
|
||||
}
|
||||
for _, packet := range packets {
|
||||
@@ -140,6 +140,121 @@ var _ = Describe("AckHandler", func() {
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(3)))
|
||||
})
|
||||
|
||||
It("checks the entropy after an previous ACK was already received", func() {
|
||||
expectedEntropy := EntropyAccumulator(0)
|
||||
expectedEntropy.Add(1, packets[0].EntropyBit)
|
||||
ack := frames.AckFrame{
|
||||
LargestObserved: 1,
|
||||
Entropy: byte(expectedEntropy),
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectedEntropy.Add(2, packets[1].EntropyBit)
|
||||
ack = frames.AckFrame{
|
||||
LargestObserved: 2,
|
||||
Entropy: byte(expectedEntropy),
|
||||
}
|
||||
err = handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("ACKs with NACK ranges", func() {
|
||||
It("handles an ACK with one NACK range and one missing packet", func() {
|
||||
nackRange := frames.NackRange{FirstPacketNumber: 2, LastPacketNumber: 2}
|
||||
entropy := EntropyAccumulator(0)
|
||||
entropy.Add(packets[0].PacketNumber, packets[0].EntropyBit) // Packet 1
|
||||
entropy.Add(packets[2].PacketNumber, packets[2].EntropyBit) // Packet 3
|
||||
ack := frames.AckFrame{
|
||||
LargestObserved: 3,
|
||||
Entropy: byte(entropy),
|
||||
NackRanges: []frames.NackRange{nackRange},
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(3)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(4)))
|
||||
})
|
||||
|
||||
It("handles an ACK with one NACK range and two missing packets", func() {
|
||||
nackRange := frames.NackRange{FirstPacketNumber: 2, LastPacketNumber: 3}
|
||||
entropy := EntropyAccumulator(0)
|
||||
entropy.Add(packets[0].PacketNumber, packets[0].EntropyBit) // Packet 1
|
||||
entropy.Add(packets[3].PacketNumber, packets[3].EntropyBit) // Packet 4
|
||||
ack := frames.AckFrame{
|
||||
LargestObserved: 4,
|
||||
Entropy: byte(entropy),
|
||||
NackRanges: []frames.NackRange{nackRange},
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(3)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(4)))
|
||||
})
|
||||
|
||||
It("handles an ACK with multiple NACK ranges", func() {
|
||||
nackRanges := []frames.NackRange{
|
||||
frames.NackRange{FirstPacketNumber: 4, LastPacketNumber: 4},
|
||||
frames.NackRange{FirstPacketNumber: 2, LastPacketNumber: 2},
|
||||
}
|
||||
entropy := EntropyAccumulator(0)
|
||||
entropy.Add(packets[0].PacketNumber, packets[0].EntropyBit) // Packet 1
|
||||
entropy.Add(packets[2].PacketNumber, packets[2].EntropyBit) // Packet 3
|
||||
entropy.Add(packets[4].PacketNumber, packets[4].EntropyBit) // Packet 5
|
||||
ack := frames.AckFrame{
|
||||
LargestObserved: 5,
|
||||
Entropy: byte(entropy),
|
||||
NackRanges: nackRanges,
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(3)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(4)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(5)))
|
||||
})
|
||||
|
||||
It("rejects an ACK with a NACK that has incorrect entropy", func() {
|
||||
nackRange := frames.NackRange{FirstPacketNumber: 2, LastPacketNumber: 3}
|
||||
entropy := EntropyAccumulator(0)
|
||||
entropy.Add(packets[0].PacketNumber, packets[0].EntropyBit) // Packet 1
|
||||
entropy.Add(packets[3].PacketNumber, packets[3].EntropyBit) // Packet 4
|
||||
ack := frames.AckFrame{
|
||||
LargestObserved: 4,
|
||||
Entropy: byte(entropy + 1),
|
||||
NackRanges: []frames.NackRange{nackRange},
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(2)))
|
||||
})
|
||||
|
||||
It("checks the entropy of an ACK with a NACK after an previous ACK was already received", func() {
|
||||
expectedEntropy := EntropyAccumulator(0)
|
||||
expectedEntropy.Add(1, packets[0].EntropyBit)
|
||||
ack := frames.AckFrame{
|
||||
LargestObserved: 1,
|
||||
Entropy: byte(expectedEntropy),
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectedEntropy.Add(4, packets[3].EntropyBit)
|
||||
nackRange := frames.NackRange{FirstPacketNumber: 2, LastPacketNumber: 3}
|
||||
ack = frames.AckFrame{
|
||||
LargestObserved: 4,
|
||||
Entropy: byte(expectedEntropy),
|
||||
NackRanges: []frames.NackRange{nackRange},
|
||||
}
|
||||
err = handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user