remove the flow control manager

This commit is contained in:
Marten Seemann 2017-10-17 11:14:58 +07:00
parent 6dc453caa3
commit 268c3859fc
25 changed files with 1710 additions and 1942 deletions

View file

@ -12,7 +12,6 @@ import (
"time"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@ -256,357 +255,241 @@ var _ = Describe("Session", func() {
})
})
Context("when handling stream frames", func() {
Context("frame handling", func() {
BeforeEach(func() {
sess.streamsMap.UpdateMaxStreamLimit(100)
sess.streamsMap.newStream = func(id protocol.StreamID) streamI {
str := mocks.NewMockStreamI(mockCtrl)
str.EXPECT().StreamID().Return(id).AnyTimes()
if id == 1 {
str.EXPECT().Finished().AnyTimes()
}
return str
}
})
It("makes new streams", func() {
sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Data: []byte{0xde, 0xca, 0xfb, 0xad},
Context("when handling STREAM frames", func() {
BeforeEach(func() {
sess.streamsMap.UpdateMaxStreamLimit(100)
})
It("makes new streams", func() {
f := &wire.StreamFrame{
StreamID: 5,
Data: []byte{0xde, 0xca, 0xfb, 0xad},
}
newStreamLambda := sess.streamsMap.newStream
sess.streamsMap.newStream = func(id protocol.StreamID) streamI {
str := newStreamLambda(id)
if id == 5 {
str.(*mocks.MockStreamI).EXPECT().AddStreamFrame(f)
}
return str
}
err := sess.handleStreamFrame(f)
Expect(err).ToNot(HaveOccurred())
str, err := sess.streamsMap.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
Expect(str).ToNot(BeNil())
})
It("handles existing streams", func() {
f1 := &wire.StreamFrame{
StreamID: 5,
Data: []byte{0xde, 0xca},
}
f2 := &wire.StreamFrame{
StreamID: 5,
Offset: 2,
Data: []byte{0xfb, 0xad},
}
newStreamLambda := sess.streamsMap.newStream
sess.streamsMap.newStream = func(id protocol.StreamID) streamI {
str := newStreamLambda(id)
if id == 5 {
str.(*mocks.MockStreamI).EXPECT().AddStreamFrame(f1)
str.(*mocks.MockStreamI).EXPECT().AddStreamFrame(f2)
}
return str
}
sess.handleStreamFrame(f1)
numOpenStreams := len(sess.streamsMap.openStreams)
sess.handleStreamFrame(f2)
Expect(sess.streamsMap.openStreams).To(HaveLen(numOpenStreams))
})
It("ignores STREAM frames for closed streams", func() {
sess.streamsMap.streams[5] = nil
str, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
Expect(str).To(BeNil()) // make sure the stream is gone
err = sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Data: []byte("foobar"),
})
Expect(err).ToNot(HaveOccurred())
})
p := make([]byte, 4)
str, err := sess.streamsMap.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
Expect(str).ToNot(BeNil())
_, err = str.Read(p)
Expect(err).ToNot(HaveOccurred())
Expect(p).To(Equal([]byte{0xde, 0xca, 0xfb, 0xad}))
})
It("does not reject existing streams with even StreamIDs", func() {
Context("handling RST_STREAM frames", func() {
It("closes the streams for writing", func() {
str, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
str.(*mocks.MockStreamI).EXPECT().RegisterRemoteError(
errors.New("RST_STREAM received with code 42"),
protocol.ByteCount(0x1337),
)
err = sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
ErrorCode: 42,
ByteOffset: 0x1337,
})
Expect(err).ToNot(HaveOccurred())
})
It("queues a RST_STERAM frame", func() {
sess.queueResetStreamFrame(5, 0x1337)
Expect(sess.packer.controlFrames).To(HaveLen(1))
Expect(sess.packer.controlFrames[0].(*wire.RstStreamFrame)).To(Equal(&wire.RstStreamFrame{
StreamID: 5,
ByteOffset: 0x1337,
}))
})
It("returns errors", func() {
testErr := errors.New("flow control violation")
str, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
str.(*mocks.MockStreamI).EXPECT().RegisterRemoteError(gomock.Any(), gomock.Any()).Return(testErr)
err = sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
ByteOffset: 0x1337,
})
Expect(err).To(MatchError(testErr))
})
It("ignores the error when the stream is not known", func() {
str, err := sess.GetOrOpenStream(3)
Expect(err).ToNot(HaveOccurred())
str.(*mocks.MockStreamI).EXPECT().Finished().Return(true)
sess.streamsMap.DeleteClosedStreams()
str, err = sess.GetOrOpenStream(3)
Expect(err).ToNot(HaveOccurred())
Expect(str).To(BeNil())
err = sess.handleFrames([]wire.Frame{&wire.RstStreamFrame{
StreamID: 3,
ErrorCode: 42,
}})
Expect(err).NotTo(HaveOccurred())
})
})
Context("handling WINDOW_UPDATE frames", func() {
var connFC *mocks.MockConnectionFlowController
BeforeEach(func() {
connFC = mocks.NewMockConnectionFlowController(mockCtrl)
sess.connFlowController = connFC
})
It("updates the flow control window of a stream", func() {
offset := protocol.ByteCount(0x1234)
str, err := sess.GetOrOpenStream(5)
str.(*mocks.MockStreamI).EXPECT().UpdateSendWindow(offset)
Expect(err).ToNot(HaveOccurred())
err = sess.handleWindowUpdateFrame(&wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: offset,
})
Expect(err).ToNot(HaveOccurred())
})
It("updates the flow control window of the connection", func() {
offset := protocol.ByteCount(0x800000)
connFC.EXPECT().UpdateSendWindow(offset)
err := sess.handleWindowUpdateFrame(&wire.WindowUpdateFrame{
StreamID: 0,
ByteOffset: offset,
})
Expect(err).ToNot(HaveOccurred())
})
It("opens a new stream when receiving a WINDOW_UPDATE for an unknown stream", func() {
newStreamLambda := sess.streamsMap.newStream
sess.streamsMap.newStream = func(id protocol.StreamID) streamI {
str := newStreamLambda(id)
if id == 5 {
str.(*mocks.MockStreamI).EXPECT().UpdateSendWindow(protocol.ByteCount(0x1337))
}
return str
}
err := sess.handleWindowUpdateFrame(&wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: 0x1337,
})
Expect(err).ToNot(HaveOccurred())
str, err := sess.streamsMap.GetOrOpenStream(5)
Expect(err).NotTo(HaveOccurred())
Expect(str).ToNot(BeNil())
})
It("ignores WINDOW_UPDATEs for a closed stream", func() {
str, err := sess.GetOrOpenStream(3)
Expect(err).ToNot(HaveOccurred())
str.(*mocks.MockStreamI).EXPECT().Finished().Return(true)
err = sess.streamsMap.DeleteClosedStreams()
Expect(err).ToNot(HaveOccurred())
str, err = sess.GetOrOpenStream(3)
Expect(err).ToNot(HaveOccurred())
Expect(str).To(BeNil())
err = sess.handleFrames([]wire.Frame{&wire.WindowUpdateFrame{
StreamID: 3,
ByteOffset: 1337,
}})
Expect(err).NotTo(HaveOccurred())
})
})
It("handles PING frames", func() {
err := sess.handleFrames([]wire.Frame{&wire.PingFrame{}})
Expect(err).NotTo(HaveOccurred())
})
It("handles BLOCKED frames", func() {
err := sess.handleFrames([]wire.Frame{&wire.BlockedFrame{}})
Expect(err).NotTo(HaveOccurred())
})
It("errors on GOAWAY frames", func() {
err := sess.handleFrames([]wire.Frame{&wire.GoawayFrame{}})
Expect(err).To(MatchError("unimplemented: handling GOAWAY frames"))
})
It("handles STOP_WAITING frames", func() {
err := sess.handleFrames([]wire.Frame{&wire.StopWaitingFrame{LeastUnacked: 10}})
Expect(err).NotTo(HaveOccurred())
})
It("handles CONNECTION_CLOSE frames", func() {
done := make(chan struct{})
go func() {
defer GinkgoRecover()
err := sess.run()
Expect(err).To(MatchError("ProofInvalid: foobar"))
close(done)
}()
_, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
err = sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Data: []byte{0xde, 0xca, 0xfb, 0xad},
sess.streamsMap.Range(func(s streamI) {
if s.StreamID() == 1 { // the crypto stream is created by the session setup and is not a mock stream
return
}
s.(*mocks.MockStreamI).EXPECT().Cancel(gomock.Any())
})
Expect(err).ToNot(HaveOccurred())
})
It("handles existing streams", func() {
sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Data: []byte{0xde, 0xca},
})
numOpenStreams := len(sess.streamsMap.openStreams)
sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Offset: 2,
Data: []byte{0xfb, 0xad},
})
Expect(sess.streamsMap.openStreams).To(HaveLen(numOpenStreams))
p := make([]byte, 4)
str, _ := sess.streamsMap.GetOrOpenStream(5)
Expect(str).ToNot(BeNil())
_, err := str.Read(p)
Expect(err).ToNot(HaveOccurred())
Expect(p).To(Equal([]byte{0xde, 0xca, 0xfb, 0xad}))
})
It("cancels streams with error", func() {
testErr := errors.New("test")
sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Data: []byte{0xde, 0xca, 0xfb, 0xad},
})
str, err := sess.streamsMap.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
Expect(str).ToNot(BeNil())
p := make([]byte, 4)
_, err = str.Read(p)
Expect(err).ToNot(HaveOccurred())
sess.handleCloseError(closeError{err: testErr, remote: true})
_, err = str.Read(p)
Expect(err).To(MatchError(qerr.Error(qerr.InternalError, testErr.Error())))
})
It("cancels empty streams with error", func() {
testErr := errors.New("test")
sess.GetOrOpenStream(5)
str, err := sess.streamsMap.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
Expect(str).ToNot(BeNil())
sess.handleCloseError(closeError{err: testErr, remote: true})
_, err = str.Read([]byte{0})
Expect(err).To(MatchError(qerr.Error(qerr.InternalError, testErr.Error())))
})
It("informs the FlowControlManager about new streams", func() {
// since the stream doesn't yet exist, this will throw an error
err := sess.flowControlManager.UpdateHighestReceived(5, 1000)
Expect(err).To(HaveOccurred())
sess.GetOrOpenStream(5)
err = sess.flowControlManager.UpdateHighestReceived(5, 2000)
Expect(err).ToNot(HaveOccurred())
})
It("ignores STREAM frames for closed streams (client-side)", func() {
sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
FinBit: true,
})
str, _ := sess.streamsMap.GetOrOpenStream(5)
Expect(str).ToNot(BeNil())
_, err := str.Read([]byte{0})
Expect(err).To(MatchError(io.EOF))
str.Close()
str.sentFin()
err = sess.streamsMap.DeleteClosedStreams()
Expect(err).ToNot(HaveOccurred())
str, _ = sess.streamsMap.GetOrOpenStream(5)
Expect(str).To(BeNil()) // make sure the stream is gone
err = sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Data: []byte("foobar"),
})
Expect(err).ToNot(HaveOccurred())
})
It("ignores STREAM frames for closed streams (server-side)", func() {
ostr, err := sess.OpenStream()
Expect(err).ToNot(HaveOccurred())
Expect(ostr.StreamID()).To(Equal(protocol.StreamID(2)))
err = sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 2,
FinBit: true,
})
Expect(err).ToNot(HaveOccurred())
str, _ := sess.streamsMap.GetOrOpenStream(2)
Expect(str).ToNot(BeNil())
_, err = str.Read([]byte{0})
Expect(err).To(MatchError(io.EOF))
str.Close()
str.sentFin()
err = sess.streamsMap.DeleteClosedStreams()
Expect(err).ToNot(HaveOccurred())
str, _ = sess.streamsMap.GetOrOpenStream(2)
Expect(str).To(BeNil()) // make sure the stream is gone
err = sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 2,
FinBit: true,
})
Expect(err).ToNot(HaveOccurred())
})
})
Context("handling RST_STREAM frames", func() {
It("closes the streams for writing", func() {
s, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
err = sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
ErrorCode: 42,
})
Expect(err).ToNot(HaveOccurred())
n, err := s.Write([]byte{0})
Expect(n).To(BeZero())
Expect(err).To(MatchError("RST_STREAM received with code 42"))
})
It("doesn't close the stream for reading", func() {
s, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Data: []byte("foobar"),
})
err = sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
ErrorCode: 42,
ByteOffset: 6,
})
Expect(err).ToNot(HaveOccurred())
b := make([]byte, 3)
n, err := s.Read(b)
Expect(n).To(Equal(3))
Expect(err).ToNot(HaveOccurred())
})
It("queues a RST_STERAM frame with the correct offset", func() {
str, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
str.(*stream).writeOffset = 0x1337
err = sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
})
Expect(err).ToNot(HaveOccurred())
Expect(sess.packer.controlFrames).To(HaveLen(1))
Expect(sess.packer.controlFrames[0].(*wire.RstStreamFrame)).To(Equal(&wire.RstStreamFrame{
StreamID: 5,
ByteOffset: 0x1337,
}))
Expect(str.(*stream).finished()).To(BeTrue())
})
It("doesn't queue a RST_STREAM for a stream that it already sent a FIN on", func() {
str, err := sess.GetOrOpenStream(5)
err = sess.handleFrames([]wire.Frame{&wire.ConnectionCloseFrame{ErrorCode: qerr.ProofInvalid, ReasonPhrase: "foobar"}})
Expect(err).NotTo(HaveOccurred())
str.(*stream).sentFin()
str.Close()
err = sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
})
Expect(err).ToNot(HaveOccurred())
Expect(sess.packer.controlFrames).To(BeEmpty())
Expect(str.(*stream).finished()).To(BeTrue())
Eventually(sess.Context().Done()).Should(BeClosed())
Eventually(done).Should(BeClosed())
})
It("passes the byte offset to the flow controller", func() {
sess.streamsMap.GetOrOpenStream(5)
fcm := mocks.NewMockFlowControlManager(mockCtrl)
sess.flowControlManager = fcm
fcm.EXPECT().ResetStream(protocol.StreamID(5), protocol.ByteCount(0x1337))
err := sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
ByteOffset: 0x1337,
})
Expect(err).ToNot(HaveOccurred())
})
It("returns errors from the flow controller", func() {
testErr := errors.New("flow control violation")
sess.streamsMap.GetOrOpenStream(5)
fcm := mocks.NewMockFlowControlManager(mockCtrl)
sess.flowControlManager = fcm
fcm.EXPECT().ResetStream(protocol.StreamID(5), protocol.ByteCount(0x1337)).Return(testErr)
err := sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
ByteOffset: 0x1337,
})
Expect(err).To(MatchError(testErr))
})
It("ignores the error when the stream is not known", func() {
err := sess.handleFrames([]wire.Frame{&wire.RstStreamFrame{
StreamID: 5,
ErrorCode: 42,
}})
Expect(err).NotTo(HaveOccurred())
})
It("queues a RST_STREAM when a stream gets reset locally", func() {
testErr := errors.New("testErr")
str, err := sess.streamsMap.GetOrOpenStream(5)
str.writeOffset = 0x1337
Expect(err).ToNot(HaveOccurred())
str.Reset(testErr)
Expect(sess.packer.controlFrames).To(HaveLen(1))
Expect(sess.packer.controlFrames[0]).To(Equal(&wire.RstStreamFrame{
StreamID: 5,
ByteOffset: 0x1337,
}))
Expect(str.finished()).To(BeFalse())
})
It("doesn't queue another RST_STREAM, when it receives an RST_STREAM as a response for the first", func() {
testErr := errors.New("testErr")
str, err := sess.streamsMap.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
str.Reset(testErr)
Expect(sess.packer.controlFrames).To(HaveLen(1))
err = sess.handleRstStreamFrame(&wire.RstStreamFrame{
StreamID: 5,
ByteOffset: 0x42,
})
Expect(err).ToNot(HaveOccurred())
Expect(sess.packer.controlFrames).To(HaveLen(1))
})
})
Context("handling WINDOW_UPDATE frames", func() {
var fcm *mocks.MockFlowControlManager
BeforeEach(func() {
fcm = mocks.NewMockFlowControlManager(mockCtrl)
sess.flowControlManager = fcm
fcm.EXPECT().NewStream(gomock.Any(), gomock.Any()).AnyTimes()
})
It("updates the Flow Control Window of a stream", func() {
offset := protocol.ByteCount(0x1234)
fcm.EXPECT().UpdateStreamWindow(protocol.StreamID(5), offset)
_, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
err = sess.handleWindowUpdateFrame(&wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: offset,
})
Expect(err).ToNot(HaveOccurred())
})
It("updates the Flow Control Window of the connection", func() {
offset := protocol.ByteCount(0x800000)
fcm.EXPECT().UpdateConnectionWindow(offset)
err := sess.handleWindowUpdateFrame(&wire.WindowUpdateFrame{
StreamID: 0,
ByteOffset: offset,
})
Expect(err).ToNot(HaveOccurred())
})
It("opens a new stream when receiving a WINDOW_UPDATE for an unknown stream", func() {
offset := protocol.ByteCount(0x1337)
fcm.EXPECT().UpdateStreamWindow(protocol.StreamID(5), offset)
err := sess.handleWindowUpdateFrame(&wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: offset,
})
Expect(err).ToNot(HaveOccurred())
str, err := sess.streamsMap.GetOrOpenStream(5)
Expect(err).NotTo(HaveOccurred())
Expect(str).ToNot(BeNil())
})
It("ignores WINDOW_UPDATEs for a closed stream", func() {
str, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
str.Close()
str.(*stream).Cancel(nil)
Expect(str.(*stream).finished()).To(BeTrue())
err = sess.streamsMap.DeleteClosedStreams()
Expect(err).ToNot(HaveOccurred())
str, err = sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
Expect(str).To(BeNil())
err = sess.handleFrames([]wire.Frame{&wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: 1337,
}})
Expect(err).NotTo(HaveOccurred())
})
})
It("handles PING frames", func() {
err := sess.handleFrames([]wire.Frame{&wire.PingFrame{}})
Expect(err).NotTo(HaveOccurred())
})
It("handles BLOCKED frames", func() {
err := sess.handleFrames([]wire.Frame{&wire.BlockedFrame{}})
Expect(err).NotTo(HaveOccurred())
})
It("errors on GOAWAY frames", func() {
err := sess.handleFrames([]wire.Frame{&wire.GoawayFrame{}})
Expect(err).To(MatchError("unimplemented: handling GOAWAY frames"))
})
It("handles STOP_WAITING frames", func() {
err := sess.handleFrames([]wire.Frame{&wire.StopWaitingFrame{LeastUnacked: 10}})
Expect(err).NotTo(HaveOccurred())
})
It("handles CONNECTION_CLOSE frames", func(done Done) {
go sess.run()
str, _ := sess.GetOrOpenStream(5)
err := sess.handleFrames([]wire.Frame{&wire.ConnectionCloseFrame{ErrorCode: 42, ReasonPhrase: "foobar"}})
Expect(err).NotTo(HaveOccurred())
Eventually(sess.Context().Done()).Should(BeClosed())
_, err = str.Read([]byte{0})
Expect(err).To(MatchError(qerr.Error(42, "foobar")))
close(done)
})
It("tells its versions", func() {
@ -615,22 +498,24 @@ var _ = Describe("Session", func() {
})
Context("waiting until the handshake completes", func() {
It("waits until the handshake is complete", func(done Done) {
go sess.run()
It("waits until the handshake is complete", func() {
go func() {
defer GinkgoRecover()
sess.run()
}()
var waitReturned bool
done := make(chan struct{})
go func() {
defer GinkgoRecover()
err := sess.WaitUntilHandshakeComplete()
Expect(err).ToNot(HaveOccurred())
waitReturned = true
close(done)
}()
aeadChanged <- protocol.EncryptionForwardSecure
Consistently(func() bool { return waitReturned }).Should(BeFalse())
Consistently(done).ShouldNot(BeClosed())
close(aeadChanged)
Eventually(func() bool { return waitReturned }).Should(BeTrue())
Eventually(done).Should(BeClosed())
Expect(sess.Close(nil)).To(Succeed())
close(done)
})
It("errors if the handshake fails", func(done Done) {
@ -668,6 +553,11 @@ var _ = Describe("Session", func() {
})
Context("accepting streams", func() {
BeforeEach(func() {
// don't use the mock here
sess.streamsMap.newStream = sess.newStream
})
It("waits for new streams", func() {
strChan := make(chan Stream)
// accept two streams
@ -680,10 +570,8 @@ var _ = Describe("Session", func() {
}
}()
Consistently(strChan).ShouldNot(Receive())
err := sess.handleStreamFrame(&wire.StreamFrame{
StreamID: 5,
Data: []byte("foobar"),
})
// this could happen e.g. by receiving a STREAM frame
_, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
var str Stream
Eventually(strChan).Should(Receive(&str))
@ -924,18 +812,26 @@ var _ = Describe("Session", func() {
})
It("sends two WindowUpdate frames", func() {
_, err := sess.GetOrOpenStream(5)
mockFC := mocks.NewMockStreamFlowController(mockCtrl)
mockFC.EXPECT().GetWindowUpdate().Return(protocol.ByteCount(0x1000))
mockFC.EXPECT().GetWindowUpdate().Return(protocol.ByteCount(0)).Times(2)
str, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
sess.flowControlManager.AddBytesRead(5, protocol.ReceiveStreamFlowControlWindow)
str.(*stream).flowController = mockFC
err = sess.sendPacket()
Expect(err).NotTo(HaveOccurred())
err = sess.sendPacket()
Expect(err).NotTo(HaveOccurred())
err = sess.sendPacket()
Expect(err).NotTo(HaveOccurred())
buf := &bytes.Buffer{}
(&wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: 0x1000,
}).Write(buf, protocol.VersionWhatever)
Expect(mconn.written).To(HaveLen(2))
Expect(mconn.written).To(Receive(ContainSubstring(string([]byte{0x04, 0x05, 0, 0, 0}))))
Expect(mconn.written).To(Receive(ContainSubstring(string([]byte{0x04, 0x05, 0, 0, 0}))))
Expect(mconn.written).To(Receive(ContainSubstring(string(buf.Bytes()))))
Expect(mconn.written).To(Receive(ContainSubstring(string(buf.Bytes()))))
})
It("sends public reset", func() {
@ -1093,69 +989,6 @@ var _ = Describe("Session", func() {
_, ok = sentPackets[1].Frames[0].(*wire.StopWaitingFrame)
Expect(ok).To(BeTrue())
})
It("retransmits a WindowUpdate if it hasn't already sent a WindowUpdate with a higher ByteOffset", func() {
_, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
fcm := mocks.NewMockFlowControlManager(mockCtrl)
sess.flowControlManager = fcm
fcm.EXPECT().GetWindowUpdates()
fcm.EXPECT().GetReceiveWindow(protocol.StreamID(5)).Return(protocol.ByteCount(0x1000), nil)
wuf := &wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: 0x1000,
}
sph.retransmissionQueue = []*ackhandler.Packet{{
Frames: []wire.Frame{wuf},
EncryptionLevel: protocol.EncryptionForwardSecure,
}}
err = sess.sendPacket()
Expect(err).ToNot(HaveOccurred())
Expect(sph.sentPackets).To(HaveLen(1))
Expect(sph.sentPackets[0].Frames).To(ContainElement(wuf))
})
It("doesn't retransmit WindowUpdates if it already sent a WindowUpdate with a higher ByteOffset", func() {
_, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
fcm := mocks.NewMockFlowControlManager(mockCtrl)
sess.flowControlManager = fcm
fcm.EXPECT().GetWindowUpdates()
fcm.EXPECT().GetReceiveWindow(protocol.StreamID(5)).Return(protocol.ByteCount(0x2000), nil)
sph.retransmissionQueue = []*ackhandler.Packet{{
Frames: []wire.Frame{&wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: 0x1000,
}},
EncryptionLevel: protocol.EncryptionForwardSecure,
}}
err = sess.sendPacket()
Expect(err).ToNot(HaveOccurred())
Expect(sph.sentPackets).To(BeEmpty())
})
It("doesn't retransmit WindowUpdates for closed streams", func() {
str, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
// close the stream
str.(*stream).sentFin()
str.Close()
str.(*stream).RegisterRemoteError(nil)
err = sess.streamsMap.DeleteClosedStreams()
Expect(err).ToNot(HaveOccurred())
_, err = sess.flowControlManager.SendWindowSize(5)
Expect(err).To(MatchError("Error accessing the flowController map"))
sph.retransmissionQueue = []*ackhandler.Packet{{
Frames: []wire.Frame{&wire.WindowUpdateFrame{
StreamID: 5,
ByteOffset: 0x1337,
}},
EncryptionLevel: protocol.EncryptionForwardSecure,
}}
err = sess.sendPacket()
Expect(err).ToNot(HaveOccurred())
Expect(sph.sentPackets).To(BeEmpty())
})
})
})
@ -1204,7 +1037,7 @@ var _ = Describe("Session", func() {
close(done)
}()
Eventually(sess.sendingScheduled).Should(Receive())
s.(*stream).getDataForWriting(1000) // unblock
s.(*stream).GetDataForWriting(1000) // unblock
})
It("sets the timer to the ack timer", func() {
@ -1435,16 +1268,17 @@ var _ = Describe("Session", func() {
_, err := sess.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
go sess.run()
paramsChan <- handshake.TransportParameters{
params := handshake.TransportParameters{
MaxStreams: 123,
IdleTimeout: 90 * time.Second,
StreamFlowControlWindow: 0x5000,
ConnectionFlowControlWindow: 0x5000,
OmitConnectionID: true,
}
Eventually(func() time.Duration { return sess.remoteIdleTimeout }).Should(Equal(90 * time.Second))
paramsChan <- params
Eventually(func() *handshake.TransportParameters { return sess.peerParams }).Should(Equal(&params))
Eventually(func() uint32 { return sess.streamsMap.maxOutgoingStreams }).Should(Equal(uint32(123)))
Eventually(func() (protocol.ByteCount, error) { return sess.flowControlManager.SendWindowSize(5) }).Should(Equal(protocol.ByteCount(0x5000)))
// Eventually(func() (protocol.ByteCount, error) { return sess.flowControlManager.SendWindowSize(5) }).Should(Equal(protocol.ByteCount(0x5000)))
Eventually(func() bool { return sess.packer.omitConnectionID }).Should(BeTrue())
Expect(sess.Close(nil)).To(Succeed())
})
@ -1455,7 +1289,7 @@ var _ = Describe("Session", func() {
remoteIdleTimeout := 20 * time.Second
BeforeEach(func() {
sess.remoteIdleTimeout = remoteIdleTimeout
sess.peerParams = &handshake.TransportParameters{IdleTimeout: remoteIdleTimeout}
})
It("sends a PING", func() {
@ -1565,7 +1399,7 @@ var _ = Describe("Session", func() {
Expect(err).ToNot(HaveOccurred())
str.Close()
str.(*stream).Cancel(nil)
Expect(str.(*stream).finished()).To(BeTrue())
Expect(str.(*stream).Finished()).To(BeTrue())
err = sess.streamsMap.DeleteClosedStreams()
Expect(err).ToNot(HaveOccurred())
Expect(sess.streamsMap.GetOrOpenStream(9)).To(BeNil())
@ -1601,7 +1435,7 @@ var _ = Describe("Session", func() {
Expect(err).NotTo(HaveOccurred())
err = s.Close()
Expect(err).NotTo(HaveOccurred())
s.(*stream).sentFin()
s.(*stream).SentFin()
s.(*stream).CloseRemote(0)
_, err = s.Read([]byte("a"))
Expect(err).To(MatchError(io.EOF))
@ -1627,29 +1461,29 @@ var _ = Describe("Session", func() {
})
})
Context("window updates", func() {
It("gets stream level window updates", func() {
_, err := sess.GetOrOpenStream(3)
Expect(err).ToNot(HaveOccurred())
err = sess.flowControlManager.AddBytesRead(3, protocol.ReceiveStreamFlowControlWindow)
Expect(err).NotTo(HaveOccurred())
frames := sess.getWindowUpdateFrames()
Expect(frames).To(HaveLen(1))
Expect(frames[0].StreamID).To(Equal(protocol.StreamID(3)))
Expect(frames[0].ByteOffset).To(BeEquivalentTo(protocol.ReceiveStreamFlowControlWindow * 2))
})
// Context("window updates", func() {
// It("gets stream level window updates", func() {
// _, err := sess.GetOrOpenStream(3)
// Expect(err).ToNot(HaveOccurred())
// err = sess.flowControlManager.AddBytesRead(3, protocol.ReceiveStreamFlowControlWindow)
// Expect(err).NotTo(HaveOccurred())
// frames := sess.getWindowUpdateFrames()
// Expect(frames).To(HaveLen(1))
// Expect(frames[0].StreamID).To(Equal(protocol.StreamID(3)))
// Expect(frames[0].ByteOffset).To(BeEquivalentTo(protocol.ReceiveStreamFlowControlWindow * 2))
// })
It("gets connection level window updates", func() {
_, err := sess.GetOrOpenStream(5)
Expect(err).NotTo(HaveOccurred())
err = sess.flowControlManager.AddBytesRead(5, protocol.ReceiveConnectionFlowControlWindow)
Expect(err).NotTo(HaveOccurred())
frames := sess.getWindowUpdateFrames()
Expect(frames).To(HaveLen(1))
Expect(frames[0].StreamID).To(Equal(protocol.StreamID(0)))
Expect(frames[0].ByteOffset).To(BeEquivalentTo(protocol.ReceiveConnectionFlowControlWindow * 2))
})
})
// It("gets connection level window updates", func() {
// _, err := sess.GetOrOpenStream(5)
// Expect(err).NotTo(HaveOccurred())
// err = sess.flowControlManager.AddBytesRead(5, protocol.ReceiveConnectionFlowControlWindow)
// Expect(err).NotTo(HaveOccurred())
// frames := sess.getWindowUpdateFrames()
// Expect(frames).To(HaveLen(1))
// Expect(frames[0].StreamID).To(Equal(protocol.StreamID(0)))
// Expect(frames[0].ByteOffset).To(BeEquivalentTo(protocol.ReceiveConnectionFlowControlWindow * 2))
// })
// })
It("returns the local address", func() {
addr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1337}