Merge pull request #297 from lucas-clemente/version-35

Add support for version 35
This commit is contained in:
Lucas Clemente
2016-08-23 18:11:22 +02:00
committed by GitHub
10 changed files with 41 additions and 27 deletions

View File

@@ -13,7 +13,7 @@ quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) p
Done:
- Basic protocol with support for QUIC version 32-34
- Basic protocol with support for QUIC version 32-35
- HTTP/2 support
- Crypto (RSA / ECDSA certificates, Curve25519 for key exchange, AES-GCM or Chacha20-Poly1305 as stream cipher)
- Loss detection and retransmission (currently fast retransmission & RTO)

View File

@@ -196,7 +196,7 @@ var _ = Describe("H2 server", func() {
Context("setting http headers", func() {
expected := http.Header{
"Alt-Svc": {`quic=":443"; ma=2592000; v="34,33,32"`},
"Alt-Svc": {`quic=":443"; ma=2592000; v="35,34,33,32"`},
"Alternate-Protocol": {`443:quic`},
}

View File

@@ -130,12 +130,15 @@ func (h *ConnectionParametersManager) GetSHLOMap() map[Tag][]byte {
utils.WriteUint32(cfcw, uint32(h.GetReceiveConnectionFlowControlWindow()))
mspc := bytes.NewBuffer([]byte{})
utils.WriteUint32(mspc, h.GetMaxStreamsPerConnection())
mids := bytes.NewBuffer([]byte{})
utils.WriteUint32(mids, protocol.MaxIncomingDynamicStreams)
icsl := bytes.NewBuffer([]byte{})
utils.WriteUint32(icsl, uint32(h.GetIdleConnectionStateLifetime()/time.Second))
return map[Tag][]byte{
TagICSL: icsl.Bytes(),
TagMSPC: mspc.Bytes(),
TagMIDS: mids.Bytes(),
TagCFCW: cfcw.Bytes(),
TagSFCW: sfcw.Bytes(),
}
@@ -145,7 +148,6 @@ func (h *ConnectionParametersManager) GetSHLOMap() map[Tag][]byte {
func (h *ConnectionParametersManager) GetSendStreamFlowControlWindow() protocol.ByteCount {
h.mutex.RLock()
defer h.mutex.RUnlock()
return h.sendStreamFlowControlWindow
}
@@ -153,7 +155,6 @@ func (h *ConnectionParametersManager) GetSendStreamFlowControlWindow() protocol.
func (h *ConnectionParametersManager) GetSendConnectionFlowControlWindow() protocol.ByteCount {
h.mutex.RLock()
defer h.mutex.RUnlock()
return h.sendConnectionFlowControlWindow
}
@@ -161,7 +162,6 @@ func (h *ConnectionParametersManager) GetSendConnectionFlowControlWindow() proto
func (h *ConnectionParametersManager) GetReceiveStreamFlowControlWindow() protocol.ByteCount {
h.mutex.RLock()
defer h.mutex.RUnlock()
return h.receiveStreamFlowControlWindow
}
@@ -169,7 +169,6 @@ func (h *ConnectionParametersManager) GetReceiveStreamFlowControlWindow() protoc
func (h *ConnectionParametersManager) GetReceiveConnectionFlowControlWindow() protocol.ByteCount {
h.mutex.RLock()
defer h.mutex.RUnlock()
return h.receiveConnectionFlowControlWindow
}
@@ -177,7 +176,6 @@ func (h *ConnectionParametersManager) GetReceiveConnectionFlowControlWindow() pr
func (h *ConnectionParametersManager) GetMaxStreamsPerConnection() uint32 {
h.mutex.RLock()
defer h.mutex.RUnlock()
return h.maxStreamsPerConnection
}
@@ -185,7 +183,6 @@ func (h *ConnectionParametersManager) GetMaxStreamsPerConnection() uint32 {
func (h *ConnectionParametersManager) GetIdleConnectionStateLifetime() time.Duration {
h.mutex.RLock()
defer h.mutex.RUnlock()
return h.idleConnectionStateLifetime
}

View File

@@ -37,6 +37,7 @@ var _ = Describe("ConnectionsParameterManager", func() {
entryMap := cpm.GetSHLOMap()
Expect(entryMap).To(HaveKey(TagICSL))
Expect(entryMap).To(HaveKey(TagMSPC))
Expect(entryMap).To(HaveKey(TagMIDS))
})
It("sets the stream-level flow control windows in SHLO", func() {
@@ -66,6 +67,12 @@ var _ = Describe("ConnectionsParameterManager", func() {
Expect(entryMap).To(HaveKey(TagMSPC))
Expect(entryMap[TagMSPC]).To(Equal([]byte{0xEF, 0xBE, 0xAD, 0xDE}))
})
It("sets the maximum incoming dynamic streams per connection in SHLO", func() {
entryMap := cpm.GetSHLOMap()
Expect(entryMap).To(HaveKey(TagMIDS))
Expect(entryMap[TagMIDS]).To(Equal([]byte{100, 0, 0, 0}))
})
})
Context("Truncated connection IDs", func() {

View File

@@ -23,6 +23,8 @@ const (
TagCCRT Tag = 'C' + 'C'<<8 + 'R'<<16 + 'T'<<24
// TagMSPC is max streams per connection
TagMSPC Tag = 'M' + 'S'<<8 + 'P'<<16 + 'C'<<24
// TagMIDS is max incoming dyanamic streams
TagMIDS Tag = 'M' + 'I'<<8 + 'D'<<16 + 'S'<<24
// TagUAID is the user agent ID
TagUAID Tag = 'U' + 'A'<<8 + 'I'<<16 + 'D'<<24
// TagTCID is truncation of the connection ID

View File

@@ -31,9 +31,15 @@ const ReceiveConnectionFlowControlWindow ByteCount = (1 << 20) * 1.5 // 1.5 MB
// MaxStreamsPerConnection is the maximum value accepted for the number of streams per connection
const MaxStreamsPerConnection uint32 = 100
// MaxStreamsMultiplier is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped.
// MaxIncomingDynamicStreams is the maximum value accepted for the incoming number of dynamic streams per connection
const MaxIncomingDynamicStreams uint32 = 100
// MaxStreamsMultiplier is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this procentual increase and the absolute increment specified by MaxStreamsMinimumIncrement is used.
const MaxStreamsMultiplier = 1.1
// MaxStreamsMinimumIncrement is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this absolute increment and the procentual increase specified by MaxStreamsMultiplier is used.
const MaxStreamsMinimumIncrement = 10
// MaxIdleConnectionStateLifetime is the maximum value accepted for the idle connection state lifetime
// TODO: set a reasonable value here
const MaxIdleConnectionStateLifetime = 60 * time.Second

View File

@@ -14,12 +14,13 @@ const (
Version32 VersionNumber = 32 + iota
Version33
Version34
Version35
VersionWhatever = 0 // for when the version doesn't matter
)
// SupportedVersions lists the versions that the server supports
var SupportedVersions = []VersionNumber{
Version32, Version33, Version34,
Version32, Version33, Version34, Version35,
}
// SupportedVersionsAsTags is needed for the SHLO crypto message

View File

@@ -17,11 +17,11 @@ var _ = Describe("Version", func() {
})
It("has proper tag list", func() {
Expect(SupportedVersionsAsTags).To(Equal([]byte("Q032Q033Q034")))
Expect(SupportedVersionsAsTags).To(Equal([]byte("Q032Q033Q034Q035")))
})
It("has proper version list", func() {
Expect(SupportedVersionsAsString).To(Equal("34,33,32"))
Expect(SupportedVersionsAsString).To(Equal("35,34,33,32"))
})
It("recognizes supported versions", func() {

View File

@@ -7,17 +7,15 @@ import (
"github.com/lucas-clemente/quic-go/protocol"
"github.com/lucas-clemente/quic-go/qerr"
)
const (
maxNumStreams = int(float32(protocol.MaxStreamsPerConnection) * protocol.MaxStreamsMultiplier)
"github.com/lucas-clemente/quic-go/utils"
)
type streamsMap struct {
streams map[protocol.StreamID]*stream
openStreams []protocol.StreamID
mutex sync.RWMutex
newStream newStreamLambda
streams map[protocol.StreamID]*stream
openStreams []protocol.StreamID
mutex sync.RWMutex
newStream newStreamLambda
maxNumStreams int
roundRobinIndex int
}
@@ -30,10 +28,13 @@ var (
)
func newStreamsMap(newStream newStreamLambda) *streamsMap {
maxNumStreams := utils.Max(int(float32(protocol.MaxIncomingDynamicStreams)*protocol.MaxStreamsMultiplier), int(protocol.MaxIncomingDynamicStreams))
return &streamsMap{
streams: map[protocol.StreamID]*stream{},
openStreams: make([]protocol.StreamID, 0, maxNumStreams),
newStream: newStream,
streams: map[protocol.StreamID]*stream{},
openStreams: make([]protocol.StreamID, 0, maxNumStreams),
newStream: newStream,
maxNumStreams: maxNumStreams,
}
}
@@ -54,7 +55,7 @@ func (m *streamsMap) GetOrOpenStream(id protocol.StreamID) (*stream, error) {
if ok {
return s, nil
}
if len(m.openStreams) == maxNumStreams {
if len(m.openStreams) == m.maxNumStreams {
return nil, qerr.TooManyOpenStreams
}
if id%2 == 0 {

View File

@@ -60,16 +60,16 @@ var _ = Describe("Streams Map", func() {
Context("counting streams", func() {
It("errors when too many streams are opened", func() {
for i := 0; i < maxNumStreams; i++ {
for i := 0; i < m.maxNumStreams; i++ {
_, err := m.GetOrOpenStream(protocol.StreamID(i*2 + 1))
Expect(err).NotTo(HaveOccurred())
}
_, err := m.GetOrOpenStream(protocol.StreamID(maxNumStreams))
_, err := m.GetOrOpenStream(protocol.StreamID(m.maxNumStreams))
Expect(err).To(MatchError(qerr.TooManyOpenStreams))
})
It("does not error when many streams are opened and closed", func() {
for i := 2; i < 10*maxNumStreams; i++ {
for i := 2; i < 10*m.maxNumStreams; i++ {
_, err := m.GetOrOpenStream(protocol.StreamID(i*2 + 1))
Expect(err).NotTo(HaveOccurred())
m.RemoveStream(protocol.StreamID(i*2 + 1))