diff --git a/flow_controller.go b/flow_controller.go index ad4413ab..2e703ddc 100644 --- a/flow_controller.go +++ b/flow_controller.go @@ -8,8 +8,9 @@ import ( type flowController struct { streamID protocol.StreamID - bytesSent protocol.ByteCount - sendFlowControlWindow protocol.ByteCount + bytesSent protocol.ByteCount + sendFlowControlWindow protocol.ByteCount + lastBlockedSentForOffset protocol.ByteCount bytesRead protocol.ByteCount receiveWindowUpdateThreshold protocol.ByteCount @@ -51,6 +52,21 @@ func (c *flowController) AddBytesRead(n protocol.ByteCount) { c.bytesRead += n } +// MaybeTriggerBlocked determines if it is necessary to send a Blocked for this stream +// it makes sure that only one Blocked is sent for each offset +func (c *flowController) MaybeTriggerBlocked() bool { + if c.SendWindowSize() != 0 { + return false + } + + if c.lastBlockedSentForOffset == c.sendFlowControlWindow { + return false + } + + c.lastBlockedSentForOffset = c.sendFlowControlWindow + return true +} + // MaybeTriggerWindowUpdate determines if it is necessary to send a WindowUpdate // if so, it returns true and the offset of the window func (c *flowController) MaybeTriggerWindowUpdate() (bool, protocol.ByteCount) { diff --git a/flow_controller_test.go b/flow_controller_test.go index 88142bf6..5609f74c 100644 --- a/flow_controller_test.go +++ b/flow_controller_test.go @@ -41,6 +41,34 @@ var _ = Describe("Flow controller", func() { Expect(updateSuccessful).To(BeFalse()) Expect(controller.SendWindowSize()).To(Equal(protocol.ByteCount(20))) }) + + Context("Blocked", func() { + var sendFlowControlWindow protocol.ByteCount = 20 + + BeforeEach(func() { + controller.sendFlowControlWindow = sendFlowControlWindow + }) + + It("sends a Blocked when there's no space left in the window", func() { + controller.bytesSent = sendFlowControlWindow + Expect(controller.MaybeTriggerBlocked()).To(BeTrue()) + }) + + It("does not send a Blocked when there's still space in the window", func() { + controller.bytesSent = sendFlowControlWindow - 1 + Expect(controller.MaybeTriggerBlocked()).To(BeFalse()) + }) + + It("only sends one Blocked for one offset", func() { + controller.bytesSent = sendFlowControlWindow + Expect(controller.MaybeTriggerBlocked()).To(BeTrue()) + Expect(controller.MaybeTriggerBlocked()).To(BeFalse()) + updateSuccessfull := controller.UpdateSendWindow(sendFlowControlWindow + 1) + Expect(updateSuccessfull).To(BeTrue()) + controller.bytesSent = sendFlowControlWindow + 1 + Expect(controller.MaybeTriggerBlocked()).To(BeTrue()) + }) + }) }) Context("receive flow control", func() {