move the max flow control increments out of the params negotiator

The params negotiator was just keeping track of the value set in the
quic.Config. The max flow control increments are not subject to
negotiation, but an independent implementation decision of every peer.
This commit is contained in:
Marten Seemann
2017-10-04 07:11:48 -07:00
parent c54bd857c0
commit 0e1a8a5f8c
12 changed files with 55 additions and 113 deletions

View File

@@ -13,8 +13,9 @@ import (
)
type flowControlManager struct {
connParams handshake.ParamsNegotiator
rttStats *congestion.RTTStats
connParams handshake.ParamsNegotiator
rttStats *congestion.RTTStats
maxReceiveStreamWindow protocol.ByteCount
streamFlowController map[protocol.StreamID]*flowController
connFlowController *flowController
@@ -26,12 +27,18 @@ var _ FlowControlManager = &flowControlManager{}
var errMapAccess = errors.New("Error accessing the flowController map.")
// NewFlowControlManager creates a new flow control manager
func NewFlowControlManager(connParams handshake.ParamsNegotiator, rttStats *congestion.RTTStats) FlowControlManager {
func NewFlowControlManager(
connParams handshake.ParamsNegotiator,
maxReceiveStreamWindow protocol.ByteCount,
maxReceiveConnectionWindow protocol.ByteCount,
rttStats *congestion.RTTStats,
) FlowControlManager {
return &flowControlManager{
connParams: connParams,
rttStats: rttStats,
streamFlowController: make(map[protocol.StreamID]*flowController),
connFlowController: newFlowController(0, false, connParams, rttStats),
connParams: connParams,
rttStats: rttStats,
maxReceiveStreamWindow: maxReceiveStreamWindow,
streamFlowController: make(map[protocol.StreamID]*flowController),
connFlowController: newFlowController(0, false, connParams, maxReceiveConnectionWindow, rttStats),
}
}
@@ -44,8 +51,7 @@ func (f *flowControlManager) NewStream(streamID protocol.StreamID, contributesTo
if _, ok := f.streamFlowController[streamID]; ok {
return
}
f.streamFlowController[streamID] = newFlowController(streamID, contributesToConnection, f.connParams, f.rttStats)
f.streamFlowController[streamID] = newFlowController(streamID, contributesToConnection, f.connParams, f.maxReceiveStreamWindow, f.rttStats)
}
// RemoveStream removes a closed stream from flow control

View File

@@ -18,9 +18,7 @@ var _ = Describe("Flow Control Manager", func() {
mockPn := mocks.NewMockParamsNegotiator(mockCtrl)
mockPn.EXPECT().GetReceiveStreamFlowControlWindow().AnyTimes().Return(protocol.ByteCount(100))
mockPn.EXPECT().GetReceiveConnectionFlowControlWindow().AnyTimes().Return(protocol.ByteCount(200))
mockPn.EXPECT().GetMaxReceiveStreamFlowControlWindow().AnyTimes().Return(protocol.MaxByteCount)
mockPn.EXPECT().GetMaxReceiveConnectionFlowControlWindow().AnyTimes().Return(protocol.MaxByteCount)
fcm = NewFlowControlManager(mockPn, &congestion.RTTStats{}).(*flowControlManager)
fcm = NewFlowControlManager(mockPn, protocol.MaxByteCount, protocol.MaxByteCount, &congestion.RTTStats{}).(*flowControlManager)
})
It("creates a connection level flow controller", func() {

View File

@@ -33,22 +33,27 @@ type flowController struct {
var ErrReceivedSmallerByteOffset = errors.New("Received a smaller byte offset")
// newFlowController gets a new flow controller
func newFlowController(streamID protocol.StreamID, contributesToConnection bool, connParams handshake.ParamsNegotiator, rttStats *congestion.RTTStats) *flowController {
func newFlowController(
streamID protocol.StreamID,
contributesToConnection bool,
connParams handshake.ParamsNegotiator,
maxReceiveWindow protocol.ByteCount,
rttStats *congestion.RTTStats,
) *flowController {
fc := flowController{
streamID: streamID,
contributesToConnection: contributesToConnection,
connParams: connParams,
rttStats: rttStats,
streamID: streamID,
contributesToConnection: contributesToConnection,
connParams: connParams,
rttStats: rttStats,
maxReceiveWindowIncrement: maxReceiveWindow,
}
if streamID == 0 {
fc.receiveWindow = connParams.GetReceiveConnectionFlowControlWindow()
fc.receiveWindowIncrement = fc.receiveWindow
fc.maxReceiveWindowIncrement = connParams.GetMaxReceiveConnectionFlowControlWindow()
} else {
fc.receiveWindow = connParams.GetReceiveStreamFlowControlWindow()
fc.receiveWindowIncrement = fc.receiveWindow
fc.maxReceiveWindowIncrement = connParams.GetMaxReceiveStreamFlowControlWindow()
}
return &fc

View File

@@ -22,45 +22,46 @@ var _ = Describe("Flow controller", func() {
var rttStats *congestion.RTTStats
var mockPn *mocks.MockParamsNegotiator
maxReceiveStreamWindow := protocol.ByteCount(8000)
maxReceiveConnectionWindow := protocol.ByteCount(9000)
BeforeEach(func() {
mockPn = mocks.NewMockParamsNegotiator(mockCtrl)
mockPn.EXPECT().GetSendStreamFlowControlWindow().AnyTimes().Return(protocol.ByteCount(1000))
mockPn.EXPECT().GetReceiveStreamFlowControlWindow().AnyTimes().Return(protocol.ByteCount(2000))
mockPn.EXPECT().GetSendConnectionFlowControlWindow().AnyTimes().Return(protocol.ByteCount(3000))
mockPn.EXPECT().GetReceiveConnectionFlowControlWindow().AnyTimes().Return(protocol.ByteCount(4000))
mockPn.EXPECT().GetMaxReceiveStreamFlowControlWindow().AnyTimes().Return(protocol.ByteCount(8000))
mockPn.EXPECT().GetMaxReceiveConnectionFlowControlWindow().AnyTimes().Return(protocol.ByteCount(9000))
rttStats = &congestion.RTTStats{}
})
It("reads the stream send and receive windows when acting as stream-level flow controller", func() {
fc := newFlowController(5, true, mockPn, rttStats)
fc := newFlowController(5, true, mockPn, maxReceiveStreamWindow, rttStats)
Expect(fc.streamID).To(Equal(protocol.StreamID(5)))
Expect(fc.receiveWindow).To(Equal(protocol.ByteCount(2000)))
Expect(fc.maxReceiveWindowIncrement).To(Equal(mockPn.GetMaxReceiveStreamFlowControlWindow()))
Expect(fc.maxReceiveWindowIncrement).To(Equal(maxReceiveStreamWindow))
})
It("reads the stream send and receive windows when acting as connection-level flow controller", func() {
fc := newFlowController(0, false, mockPn, rttStats)
fc := newFlowController(0, false, mockPn, maxReceiveConnectionWindow, rttStats)
Expect(fc.streamID).To(Equal(protocol.StreamID(0)))
Expect(fc.receiveWindow).To(Equal(protocol.ByteCount(4000)))
Expect(fc.maxReceiveWindowIncrement).To(Equal(mockPn.GetMaxReceiveConnectionFlowControlWindow()))
Expect(fc.maxReceiveWindowIncrement).To(Equal(maxReceiveConnectionWindow))
})
It("does not set the stream flow control windows for sending", func() {
fc := newFlowController(5, true, mockPn, rttStats)
fc := newFlowController(5, true, mockPn, protocol.MaxByteCount, rttStats)
Expect(fc.sendWindow).To(BeZero())
})
It("does not set the connection flow control windows for sending", func() {
fc := newFlowController(0, false, mockPn, rttStats)
fc := newFlowController(0, false, mockPn, protocol.MaxByteCount, rttStats)
Expect(fc.sendWindow).To(BeZero())
})
It("says if it contributes to connection-level flow control", func() {
fc := newFlowController(1, false, mockPn, rttStats)
fc := newFlowController(1, false, mockPn, protocol.MaxByteCount, rttStats)
Expect(fc.ContributesToConnection()).To(BeFalse())
fc = newFlowController(5, true, mockPn, rttStats)
fc = newFlowController(5, true, mockPn, protocol.MaxByteCount, rttStats)
Expect(fc.ContributesToConnection()).To(BeTrue())
})
})

View File

@@ -114,11 +114,7 @@ var _ = Describe("Client Crypto Setup", func() {
0,
version,
nil,
&TransportParameters{
MaxReceiveStreamFlowControlWindow: protocol.DefaultMaxReceiveStreamFlowControlWindowClient,
MaxReceiveConnectionFlowControlWindow: protocol.DefaultMaxReceiveConnectionFlowControlWindowClient,
IdleTimeout: protocol.DefaultIdleTimeout,
},
&TransportParameters{IdleTimeout: protocol.DefaultIdleTimeout},
aeadChanged,
nil,
)

View File

@@ -202,11 +202,7 @@ var _ = Describe("Server Crypto Setup", func() {
remoteAddr,
version,
scfg,
&TransportParameters{
MaxReceiveStreamFlowControlWindow: protocol.DefaultMaxReceiveStreamFlowControlWindowServer,
MaxReceiveConnectionFlowControlWindow: protocol.DefaultMaxReceiveConnectionFlowControlWindowServer,
IdleTimeout: protocol.DefaultIdleTimeout,
},
&TransportParameters{IdleTimeout: protocol.DefaultIdleTimeout},
supportedVersions,
nil,
aeadChanged,

View File

@@ -28,8 +28,6 @@ type CryptoSetup interface {
// TransportParameters are parameters sent to the peer during the handshake
type TransportParameters struct {
RequestConnectionIDOmission bool
MaxReceiveStreamFlowControlWindow protocol.ByteCount
MaxReceiveConnectionFlowControlWindow protocol.ByteCount
IdleTimeout time.Duration
RequestConnectionIDOmission bool
IdleTimeout time.Duration
}

View File

@@ -14,9 +14,7 @@ type ParamsNegotiator interface {
GetSendStreamFlowControlWindow() protocol.ByteCount
GetSendConnectionFlowControlWindow() protocol.ByteCount
GetReceiveStreamFlowControlWindow() protocol.ByteCount
GetMaxReceiveStreamFlowControlWindow() protocol.ByteCount
GetReceiveConnectionFlowControlWindow() protocol.ByteCount
GetMaxReceiveConnectionFlowControlWindow() protocol.ByteCount
GetMaxOutgoingStreams() uint32
GetMaxIncomingStreams() uint32
// get the idle timeout that was sent by the peer
@@ -50,8 +48,6 @@ type paramsNegotiatorBase struct {
sendConnectionFlowControlWindow protocol.ByteCount
receiveStreamFlowControlWindow protocol.ByteCount
receiveConnectionFlowControlWindow protocol.ByteCount
maxReceiveStreamFlowControlWindow protocol.ByteCount
maxReceiveConnectionFlowControlWindow protocol.ByteCount
}
func (h *paramsNegotiatorBase) init(params *TransportParameters) {
@@ -59,8 +55,6 @@ func (h *paramsNegotiatorBase) init(params *TransportParameters) {
h.sendConnectionFlowControlWindow = protocol.InitialConnectionFlowControlWindow // can only be changed by the client
h.receiveStreamFlowControlWindow = protocol.ReceiveStreamFlowControlWindow
h.receiveConnectionFlowControlWindow = protocol.ReceiveConnectionFlowControlWindow
h.maxReceiveStreamFlowControlWindow = params.MaxReceiveStreamFlowControlWindow
h.maxReceiveConnectionFlowControlWindow = params.MaxReceiveConnectionFlowControlWindow
h.requestConnectionIDOmission = params.RequestConnectionIDOmission
h.idleTimeout = params.IdleTimeout
@@ -101,11 +95,6 @@ func (h *paramsNegotiatorBase) GetReceiveStreamFlowControlWindow() protocol.Byte
return h.receiveStreamFlowControlWindow
}
// GetMaxReceiveStreamFlowControlWindow gets the maximum size of the stream-level flow control window for sending data
func (h *paramsNegotiatorBase) GetMaxReceiveStreamFlowControlWindow() protocol.ByteCount {
return h.maxReceiveStreamFlowControlWindow
}
// GetReceiveConnectionFlowControlWindow gets the size of the stream-level flow control window for receiving data
func (h *paramsNegotiatorBase) GetReceiveConnectionFlowControlWindow() protocol.ByteCount {
h.mutex.RLock()
@@ -113,10 +102,6 @@ func (h *paramsNegotiatorBase) GetReceiveConnectionFlowControlWindow() protocol.
return h.receiveConnectionFlowControlWindow
}
func (h *paramsNegotiatorBase) GetMaxReceiveConnectionFlowControlWindow() protocol.ByteCount {
return h.maxReceiveConnectionFlowControlWindow
}
func (h *paramsNegotiatorBase) GetMaxOutgoingStreams() uint32 {
h.mutex.RLock()
defer h.mutex.RUnlock()

View File

@@ -2,7 +2,6 @@ package handshake
import (
"encoding/binary"
"math"
"time"
"github.com/lucas-clemente/quic-go/internal/protocol"
@@ -13,29 +12,20 @@ import (
var _ = Describe("Params Negotiator (for gQUIC)", func() {
var pn *paramsNegotiatorGQUIC // a connectionParametersManager for a server
var pnClient *paramsNegotiatorGQUIC
const MB = 1 << 20
maxReceiveStreamFlowControlWindowServer := protocol.ByteCount(math.Floor(1.1 * MB)) // default is 1 MB
maxReceiveConnectionFlowControlWindowServer := protocol.ByteCount(math.Floor(1.5 * MB)) // default is 1.5 MB
maxReceiveStreamFlowControlWindowClient := protocol.ByteCount(math.Floor(6.4 * MB)) // default is 6 MB
maxReceiveConnectionFlowControlWindowClient := protocol.ByteCount(math.Floor(13 * MB)) // default is 15 MB
idleTimeout := 42 * time.Second
BeforeEach(func() {
pn = newParamsNegotiatorGQUIC(
protocol.PerspectiveServer,
protocol.VersionWhatever,
&TransportParameters{
MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindowServer,
MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindowServer,
IdleTimeout: idleTimeout,
IdleTimeout: idleTimeout,
},
)
pnClient = newParamsNegotiatorGQUIC(
protocol.PerspectiveClient,
protocol.VersionWhatever,
&TransportParameters{
MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindowClient,
MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindowClient,
IdleTimeout: idleTimeout,
IdleTimeout: idleTimeout,
},
)
})
@@ -158,13 +148,6 @@ var _ = Describe("Params Negotiator (for gQUIC)", func() {
Expect(pnClient.GetReceiveConnectionFlowControlWindow()).To(BeEquivalentTo(protocol.ReceiveConnectionFlowControlWindow))
})
It("has the correct maximum flow control windows", func() {
Expect(pn.GetMaxReceiveStreamFlowControlWindow()).To(Equal(maxReceiveStreamFlowControlWindowServer))
Expect(pn.GetMaxReceiveConnectionFlowControlWindow()).To(Equal(maxReceiveConnectionFlowControlWindowServer))
Expect(pnClient.GetMaxReceiveStreamFlowControlWindow()).To(Equal(maxReceiveStreamFlowControlWindowClient))
Expect(pnClient.GetMaxReceiveConnectionFlowControlWindow()).To(Equal(maxReceiveConnectionFlowControlWindowClient))
})
It("sets a new stream-level flow control window for sending", func() {
values := map[Tag][]byte{TagSFCW: {0xDE, 0xAD, 0xBE, 0xEF}}
err := pn.SetFromMap(values)

View File

@@ -5,10 +5,11 @@
package mocks
import (
gomock "github.com/golang/mock/gomock"
protocol "github.com/lucas-clemente/quic-go/internal/protocol"
reflect "reflect"
time "time"
gomock "github.com/golang/mock/gomock"
protocol "github.com/lucas-clemente/quic-go/internal/protocol"
)
// MockParamsNegotiator is a mock of ParamsNegotiator interface
@@ -70,18 +71,6 @@ func (mr *MockParamsNegotiatorMockRecorder) GetReceiveStreamFlowControlWindow()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceiveStreamFlowControlWindow", reflect.TypeOf((*MockParamsNegotiator)(nil).GetReceiveStreamFlowControlWindow))
}
// GetMaxReceiveStreamFlowControlWindow mocks base method
func (m *MockParamsNegotiator) GetMaxReceiveStreamFlowControlWindow() protocol.ByteCount {
ret := m.ctrl.Call(m, "GetMaxReceiveStreamFlowControlWindow")
ret0, _ := ret[0].(protocol.ByteCount)
return ret0
}
// GetMaxReceiveStreamFlowControlWindow indicates an expected call of GetMaxReceiveStreamFlowControlWindow
func (mr *MockParamsNegotiatorMockRecorder) GetMaxReceiveStreamFlowControlWindow() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMaxReceiveStreamFlowControlWindow", reflect.TypeOf((*MockParamsNegotiator)(nil).GetMaxReceiveStreamFlowControlWindow))
}
// GetReceiveConnectionFlowControlWindow mocks base method
func (m *MockParamsNegotiator) GetReceiveConnectionFlowControlWindow() protocol.ByteCount {
ret := m.ctrl.Call(m, "GetReceiveConnectionFlowControlWindow")
@@ -94,18 +83,6 @@ func (mr *MockParamsNegotiatorMockRecorder) GetReceiveConnectionFlowControlWindo
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceiveConnectionFlowControlWindow", reflect.TypeOf((*MockParamsNegotiator)(nil).GetReceiveConnectionFlowControlWindow))
}
// GetMaxReceiveConnectionFlowControlWindow mocks base method
func (m *MockParamsNegotiator) GetMaxReceiveConnectionFlowControlWindow() protocol.ByteCount {
ret := m.ctrl.Call(m, "GetMaxReceiveConnectionFlowControlWindow")
ret0, _ := ret[0].(protocol.ByteCount)
return ret0
}
// GetMaxReceiveConnectionFlowControlWindow indicates an expected call of GetMaxReceiveConnectionFlowControlWindow
func (mr *MockParamsNegotiatorMockRecorder) GetMaxReceiveConnectionFlowControlWindow() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMaxReceiveConnectionFlowControlWindow", reflect.TypeOf((*MockParamsNegotiator)(nil).GetMaxReceiveConnectionFlowControlWindow))
}
// GetMaxOutgoingStreams mocks base method
func (m *MockParamsNegotiator) GetMaxOutgoingStreams() uint32 {
ret := m.ctrl.Call(m, "GetMaxOutgoingStreams")