diff --git a/ackhandler/incoming_packet_ack_handler.go b/ackhandler/incoming_packet_ack_handler.go index dd4afd8ea..e66c73bc7 100644 --- a/ackhandler/incoming_packet_ack_handler.go +++ b/ackhandler/incoming_packet_ack_handler.go @@ -45,6 +45,18 @@ func (h *incomingPacketAckHandler) ReceivedPacket(packetNumber protocol.PacketNu return nil } +func (h *incomingPacketAckHandler) ReceivedStopWaiting(f *frames.StopWaitingFrame) error { + // Ignore if STOP_WAITING is unneeded + if h.highestInOrderObserved >= f.LeastUnacked { + return nil + } + + h.highestInOrderObserved = f.LeastUnacked + h.highestInOrderObservedEntropy = EntropyAccumulator(f.Entropy) + + return nil +} + // getNackRanges gets all the NACK ranges func (h *incomingPacketAckHandler) getNackRanges() ([]frames.NackRange, EntropyAccumulator) { // ToDo: use a better data structure here diff --git a/ackhandler/incoming_packet_ack_handler_test.go b/ackhandler/incoming_packet_ack_handler_test.go index ce852613e..7020472bf 100644 --- a/ackhandler/incoming_packet_ack_handler_test.go +++ b/ackhandler/incoming_packet_ack_handler_test.go @@ -1,6 +1,7 @@ package ackhandler import ( + "github.com/lucas-clemente/quic-go/frames" "github.com/lucas-clemente/quic-go/protocol" . "github.com/onsi/ginkgo" @@ -189,4 +190,43 @@ var _ = Describe("incomingPacketAckHandler", func() { Expect(entropy).To(Equal(expectedEntropy)) }) }) + + Context("handling STOP_WAITING frames", func() { + It("resets the entropy", func() { + // We simulate 20 packets, numbers 10, 11 and 12 lost + expectedAfterStopWaiting := EntropyAccumulator(0) + for i := 1; i < 20; i++ { + entropyBit := false + if i%3 == 0 || i%5 == 0 { + entropyBit = true + } + + if i == 10 || i == 11 || i == 12 { + continue + } + if i > 12 { + expectedAfterStopWaiting.Add(protocol.PacketNumber(i), entropyBit) + } + err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit) + Expect(err).ToNot(HaveOccurred()) + } + err := handler.ReceivedStopWaiting(&frames.StopWaitingFrame{Entropy: 42, LeastUnacked: protocol.PacketNumber(12)}) + Expect(err).ToNot(HaveOccurred()) + _, e := handler.getNackRanges() + Expect(e).To(Equal(42 ^ expectedAfterStopWaiting)) + Expect(handler.highestInOrderObserved).To(Equal(protocol.PacketNumber(12))) + Expect(handler.highestInOrderObservedEntropy).To(Equal(EntropyAccumulator(42))) + }) + + It("does not emit nack ranges after STOP_WAITING", func() { + err := handler.ReceivedPacket(10, false) + Expect(err).ToNot(HaveOccurred()) + ranges, _ := handler.getNackRanges() + Expect(ranges).To(HaveLen(1)) + err = handler.ReceivedStopWaiting(&frames.StopWaitingFrame{Entropy: 0, LeastUnacked: protocol.PacketNumber(9)}) + Expect(err).ToNot(HaveOccurred()) + ranges, _ = handler.getNackRanges() + Expect(ranges).To(HaveLen(0)) + }) + }) }) diff --git a/ackhandler/interfaces.go b/ackhandler/interfaces.go index df36add0d..1877a1860 100644 --- a/ackhandler/interfaces.go +++ b/ackhandler/interfaces.go @@ -16,6 +16,7 @@ type OutgoingPacketAckHandler interface { // IncomingPacketAckHandler handles ACKs needed to send for incoming packets type IncomingPacketAckHandler interface { ReceivedPacket(packetNumber protocol.PacketNumber, entropyBit bool) error + ReceivedStopWaiting(*frames.StopWaitingFrame) error DequeueAckFrame() *frames.AckFrame } diff --git a/session.go b/session.go index 50b87c0af..e6b628c2e 100644 --- a/session.go +++ b/session.go @@ -83,7 +83,7 @@ func (s *Session) HandlePacket(addr *net.UDPAddr, publicHeaderBinary []byte, pub case *frames.ConnectionCloseFrame: fmt.Printf("%#v\n", frame) case *frames.StopWaitingFrame: - fmt.Printf("%#v\n", frame) + err = s.incomingAckHandler.ReceivedStopWaiting(frame) case *frames.RstStreamFrame: fmt.Printf("%#v\n", frame) case *frames.WindowUpdateFrame: