diff --git a/client.go b/client.go index e89ea0eee..eaac3eea1 100644 --- a/client.go +++ b/client.go @@ -397,12 +397,14 @@ func (c *client) handleRetryPacket(hdr *wire.Header) { func (c *client) createNewTLSSession(version protocol.VersionNumber) error { params := &handshake.TransportParameters{ - InitialMaxStreamData: protocol.InitialMaxStreamData, - InitialMaxData: protocol.InitialMaxData, - IdleTimeout: c.config.IdleTimeout, - MaxBidiStreams: uint16(c.config.MaxIncomingStreams), - MaxUniStreams: uint16(c.config.MaxIncomingUniStreams), - DisableMigration: true, + InitialMaxStreamDataBidiRemote: protocol.InitialMaxStreamData, + InitialMaxStreamDataBidiLocal: protocol.InitialMaxStreamData, + InitialMaxStreamDataUni: protocol.InitialMaxStreamData, + InitialMaxData: protocol.InitialMaxData, + IdleTimeout: c.config.IdleTimeout, + MaxBidiStreams: uint16(c.config.MaxIncomingStreams), + MaxUniStreams: uint16(c.config.MaxIncomingUniStreams), + DisableMigration: true, } c.mutex.Lock() diff --git a/internal/handshake/tls_extension_test.go b/internal/handshake/tls_extension_test.go index 5169dc4f9..8b60c6333 100644 --- a/internal/handshake/tls_extension_test.go +++ b/internal/handshake/tls_extension_test.go @@ -16,14 +16,14 @@ var _ = Describe("QUIC TLS Extension", func() { chtp := &clientHelloTransportParameters{ InitialVersion: 0x123456, Parameters: TransportParameters{ - InitialMaxStreamData: 0x42, - IdleTimeout: 0x1337 * time.Second, + InitialMaxStreamDataUni: 0x42, + IdleTimeout: 0x1337 * time.Second, }, } chtp2 := &clientHelloTransportParameters{} Expect(chtp2.Unmarshal(chtp.Marshal())).To(Succeed()) Expect(chtp2.InitialVersion).To(Equal(chtp.InitialVersion)) - Expect(chtp2.Parameters.InitialMaxStreamData).To(Equal(chtp.Parameters.InitialMaxStreamData)) + Expect(chtp2.Parameters.InitialMaxStreamDataUni).To(Equal(chtp.Parameters.InitialMaxStreamDataUni)) Expect(chtp2.Parameters.IdleTimeout).To(Equal(chtp.Parameters.IdleTimeout)) }) @@ -44,15 +44,15 @@ var _ = Describe("QUIC TLS Extension", func() { NegotiatedVersion: 0x123456, SupportedVersions: []protocol.VersionNumber{0x42, 0x4242}, Parameters: TransportParameters{ - InitialMaxStreamData: 0x42, - IdleTimeout: 0x1337 * time.Second, + InitialMaxStreamDataBidiLocal: 0x42, + IdleTimeout: 0x1337 * time.Second, }, } eetp2 := &encryptedExtensionsTransportParameters{} Expect(eetp2.Unmarshal(eetp.Marshal())).To(Succeed()) Expect(eetp2.NegotiatedVersion).To(Equal(eetp.NegotiatedVersion)) Expect(eetp2.SupportedVersions).To(Equal(eetp.SupportedVersions)) - Expect(eetp2.Parameters.InitialMaxStreamData).To(Equal(eetp.Parameters.InitialMaxStreamData)) + Expect(eetp2.Parameters.InitialMaxStreamDataBidiLocal).To(Equal(eetp.Parameters.InitialMaxStreamDataBidiLocal)) Expect(eetp2.Parameters.IdleTimeout).To(Equal(eetp.Parameters.IdleTimeout)) }) diff --git a/internal/handshake/transport_parameter_test.go b/internal/handshake/transport_parameter_test.go index c1a87a2b1..7ed94ffc0 100644 --- a/internal/handshake/transport_parameter_test.go +++ b/internal/handshake/transport_parameter_test.go @@ -14,13 +14,15 @@ import ( var _ = Describe("Transport Parameters", func() { It("has a string representation", func() { p := &TransportParameters{ - InitialMaxStreamData: 0x1234, - InitialMaxData: 0x4321, - MaxBidiStreams: 1337, - MaxUniStreams: 7331, - IdleTimeout: 42 * time.Second, + InitialMaxStreamDataBidiLocal: 0x1234, + InitialMaxStreamDataBidiRemote: 0x2345, + InitialMaxStreamDataUni: 0x3456, + InitialMaxData: 0x4567, + MaxBidiStreams: 1337, + MaxUniStreams: 7331, + IdleTimeout: 42 * time.Second, } - Expect(p.String()).To(Equal("&handshake.TransportParameters{InitialMaxStreamData: 0x1234, InitialMaxData: 0x4321, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s}")) + Expect(p.String()).To(Equal("&handshake.TransportParameters{InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s}")) }) Context("parsing", func() { @@ -44,21 +46,24 @@ var _ = Describe("Transport Parameters", func() { params = &TransportParameters{} statelessResetToken = bytes.Repeat([]byte{42}, 16) parameters = map[transportParameterID][]byte{ - initialMaxStreamDataParameterID: {0x11, 0x22, 0x33, 0x44}, - initialMaxDataParameterID: {0x22, 0x33, 0x44, 0x55}, - initialMaxBidiStreamsParameterID: {0x33, 0x44}, - initialMaxUniStreamsParameterID: {0x44, 0x55}, - idleTimeoutParameterID: {0x13, 0x37}, - maxPacketSizeParameterID: {0x73, 0x31}, - disableMigrationParameterID: {}, - statelessResetTokenParameterID: statelessResetToken, + initialMaxStreamDataBidiLocalParameterID: {0x11, 0x22, 0x33, 0x44}, + initialMaxStreamDataBidiRemoteParameterID: {0x22, 0x33, 0x44, 0x55}, + initialMaxStreamDataUniParameterID: {0x33, 0x44, 0x55, 0x66}, + initialMaxDataParameterID: {0x44, 0x55, 0x66, 0x77}, + initialMaxBidiStreamsParameterID: {0x33, 0x44}, + initialMaxUniStreamsParameterID: {0x44, 0x55}, + idleTimeoutParameterID: {0x13, 0x37}, + maxPacketSizeParameterID: {0x73, 0x31}, + disableMigrationParameterID: {}, + statelessResetTokenParameterID: statelessResetToken, } }) It("reads parameters", func() { - err := params.unmarshal(marshal(parameters)) - Expect(err).ToNot(HaveOccurred()) - Expect(params.InitialMaxStreamData).To(Equal(protocol.ByteCount(0x11223344))) - Expect(params.InitialMaxData).To(Equal(protocol.ByteCount(0x22334455))) + Expect(params.unmarshal(marshal(parameters))).To(Succeed()) + Expect(params.InitialMaxStreamDataBidiLocal).To(Equal(protocol.ByteCount(0x11223344))) + Expect(params.InitialMaxStreamDataBidiRemote).To(Equal(protocol.ByteCount(0x22334455))) + Expect(params.InitialMaxStreamDataUni).To(Equal(protocol.ByteCount(0x33445566))) + Expect(params.InitialMaxData).To(Equal(protocol.ByteCount(0x44556677))) Expect(params.MaxBidiStreams).To(Equal(uint16(0x3344))) Expect(params.MaxUniStreams).To(Equal(uint16(0x4455))) Expect(params.IdleTimeout).To(Equal(0x1337 * time.Second)) @@ -86,10 +91,22 @@ var _ = Describe("Transport Parameters", func() { Expect(params.IdleTimeout).To(Equal(protocol.MinRemoteIdleTimeout)) }) - It("rejects the parameters if the initial_max_stream_data has the wrong length", func() { - parameters[initialMaxStreamDataParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes + It("rejects the parameters if the initial_max_stream_data_bidi_local has the wrong length", func() { + parameters[initialMaxStreamDataBidiLocalParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes err := params.unmarshal(marshal(parameters)) - Expect(err).To(MatchError("wrong length for initial_max_stream_data: 3 (expected 4)")) + Expect(err).To(MatchError("wrong length for initial_max_stream_data_bidi_local: 3 (expected 4)")) + }) + + It("rejects the parameters if the initial_max_stream_data_bidi_remote has the wrong length", func() { + parameters[initialMaxStreamDataBidiRemoteParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for initial_max_stream_data_bidi_remote: 3 (expected 4)")) + }) + + It("rejects the parameters if the initial_max_stream_data_uni has the wrong length", func() { + parameters[initialMaxStreamDataUniParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes + err := params.unmarshal(marshal(parameters)) + Expect(err).To(MatchError("wrong length for initial_max_stream_data_uni: 3 (expected 4)")) }) It("rejects the parameters if the initial_max_data has the wrong length", func() { @@ -150,20 +167,24 @@ var _ = Describe("Transport Parameters", func() { Context("marshalling", func() { It("marshals", func() { params := &TransportParameters{ - InitialMaxStreamData: 0xdeadbeef, - InitialMaxData: 0xdecafbad, - IdleTimeout: 0xcafe * time.Second, - MaxBidiStreams: 0x1234, - MaxUniStreams: 0x4321, - DisableMigration: true, - StatelessResetToken: bytes.Repeat([]byte{100}, 16), + InitialMaxStreamDataBidiLocal: 0xdeadbeef, + InitialMaxStreamDataBidiRemote: 0xbeef, + InitialMaxStreamDataUni: 0xcafe, + InitialMaxData: 0xdecafbad, + IdleTimeout: 0xcafe * time.Second, + MaxBidiStreams: 0x1234, + MaxUniStreams: 0x4321, + DisableMigration: true, + StatelessResetToken: bytes.Repeat([]byte{100}, 16), } b := &bytes.Buffer{} params.marshal(b) p := &TransportParameters{} Expect(p.unmarshal(b.Bytes())).To(Succeed()) - Expect(p.InitialMaxStreamData).To(Equal(params.InitialMaxStreamData)) + Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal)) + Expect(p.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote)) + Expect(p.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni)) Expect(p.InitialMaxData).To(Equal(params.InitialMaxData)) Expect(p.MaxUniStreams).To(Equal(params.MaxUniStreams)) Expect(p.MaxBidiStreams).To(Equal(params.MaxBidiStreams)) diff --git a/internal/handshake/transport_parameters.go b/internal/handshake/transport_parameters.go index 2e85fdb6a..e3fea7fd2 100644 --- a/internal/handshake/transport_parameters.go +++ b/internal/handshake/transport_parameters.go @@ -14,20 +14,24 @@ import ( type transportParameterID uint16 const ( - initialMaxStreamDataParameterID transportParameterID = 0x0 - initialMaxDataParameterID transportParameterID = 0x1 - initialMaxBidiStreamsParameterID transportParameterID = 0x2 - idleTimeoutParameterID transportParameterID = 0x3 - maxPacketSizeParameterID transportParameterID = 0x5 - statelessResetTokenParameterID transportParameterID = 0x6 - initialMaxUniStreamsParameterID transportParameterID = 0x8 - disableMigrationParameterID transportParameterID = 0x9 + initialMaxStreamDataBidiLocalParameterID transportParameterID = 0x0 + initialMaxDataParameterID transportParameterID = 0x1 + initialMaxBidiStreamsParameterID transportParameterID = 0x2 + idleTimeoutParameterID transportParameterID = 0x3 + maxPacketSizeParameterID transportParameterID = 0x5 + statelessResetTokenParameterID transportParameterID = 0x6 + initialMaxUniStreamsParameterID transportParameterID = 0x8 + disableMigrationParameterID transportParameterID = 0x9 + initialMaxStreamDataBidiRemoteParameterID transportParameterID = 0xa + initialMaxStreamDataUniParameterID transportParameterID = 0xb ) // TransportParameters are parameters sent to the peer during the handshake type TransportParameters struct { - InitialMaxStreamData protocol.ByteCount - InitialMaxData protocol.ByteCount + InitialMaxStreamDataBidiLocal protocol.ByteCount + InitialMaxStreamDataBidiRemote protocol.ByteCount + InitialMaxStreamDataUni protocol.ByteCount + InitialMaxData protocol.ByteCount MaxPacketSize protocol.ByteCount @@ -52,11 +56,21 @@ func (p *TransportParameters) unmarshal(data []byte) error { } parameterIDs = append(parameterIDs, paramID) switch paramID { - case initialMaxStreamDataParameterID: + case initialMaxStreamDataBidiLocalParameterID: if paramLen != 4 { - return fmt.Errorf("wrong length for initial_max_stream_data: %d (expected 4)", paramLen) + return fmt.Errorf("wrong length for initial_max_stream_data_bidi_local: %d (expected 4)", paramLen) } - p.InitialMaxStreamData = protocol.ByteCount(binary.BigEndian.Uint32(data[:4])) + p.InitialMaxStreamDataBidiLocal = protocol.ByteCount(binary.BigEndian.Uint32(data[:4])) + case initialMaxStreamDataBidiRemoteParameterID: + if paramLen != 4 { + return fmt.Errorf("wrong length for initial_max_stream_data_bidi_remote: %d (expected 4)", paramLen) + } + p.InitialMaxStreamDataBidiRemote = protocol.ByteCount(binary.BigEndian.Uint32(data[:4])) + case initialMaxStreamDataUniParameterID: + if paramLen != 4 { + return fmt.Errorf("wrong length for initial_max_stream_data_uni: %d (expected 4)", paramLen) + } + p.InitialMaxStreamDataUni = protocol.ByteCount(binary.BigEndian.Uint32(data[:4])) case initialMaxDataParameterID: if paramLen != 4 { return fmt.Errorf("wrong length for initial_max_data: %d (expected 4)", paramLen) @@ -115,10 +129,18 @@ func (p *TransportParameters) unmarshal(data []byte) error { } func (p *TransportParameters) marshal(b *bytes.Buffer) { - // initial_max_stream_data - utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataParameterID)) + // initial_max_stream_data_bidi_local + utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID)) utils.BigEndian.WriteUint16(b, 4) - utils.BigEndian.WriteUint32(b, uint32(p.InitialMaxStreamData)) + utils.BigEndian.WriteUint32(b, uint32(p.InitialMaxStreamDataBidiLocal)) + // initial_max_stream_data_bidi_remote + utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiRemoteParameterID)) + utils.BigEndian.WriteUint16(b, 4) + utils.BigEndian.WriteUint32(b, uint32(p.InitialMaxStreamDataBidiRemote)) + // initial_max_stream_data_uni + utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataUniParameterID)) + utils.BigEndian.WriteUint16(b, 4) + utils.BigEndian.WriteUint32(b, uint32(p.InitialMaxStreamDataUni)) // initial_max_data utils.BigEndian.WriteUint16(b, uint16(initialMaxDataParameterID)) utils.BigEndian.WriteUint16(b, 4) @@ -153,5 +175,5 @@ func (p *TransportParameters) marshal(b *bytes.Buffer) { // String returns a string representation, intended for logging. func (p *TransportParameters) String() string { - return fmt.Sprintf("&handshake.TransportParameters{InitialMaxStreamData: %#x, InitialMaxData: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, IdleTimeout: %s}", p.InitialMaxStreamData, p.InitialMaxData, p.MaxBidiStreams, p.MaxUniStreams, p.IdleTimeout) + return fmt.Sprintf("&handshake.TransportParameters{InitialMaxStreamDataBidiLocal: %#x, InitialMaxStreamDataBidiRemote: %#x, InitialMaxStreamDataUni: %#x, InitialMaxData: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, IdleTimeout: %s}", p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreams, p.MaxUniStreams, p.IdleTimeout) } diff --git a/server.go b/server.go index 76f9393de..e4ca11454 100644 --- a/server.go +++ b/server.go @@ -375,12 +375,14 @@ func (s *server) createNewSession( version protocol.VersionNumber, ) (quicSession, error) { params := &handshake.TransportParameters{ - InitialMaxStreamData: protocol.InitialMaxStreamData, - InitialMaxData: protocol.InitialMaxData, - IdleTimeout: s.config.IdleTimeout, - MaxBidiStreams: uint16(s.config.MaxIncomingStreams), - MaxUniStreams: uint16(s.config.MaxIncomingUniStreams), - DisableMigration: true, + InitialMaxStreamDataBidiLocal: protocol.InitialMaxStreamData, + InitialMaxStreamDataBidiRemote: protocol.InitialMaxStreamData, + InitialMaxStreamDataUni: protocol.InitialMaxStreamData, + InitialMaxData: protocol.InitialMaxData, + IdleTimeout: s.config.IdleTimeout, + MaxBidiStreams: uint16(s.config.MaxIncomingStreams), + MaxUniStreams: uint16(s.config.MaxIncomingUniStreams), + DisableMigration: true, // TODO(#855): generate a real token StatelessResetToken: bytes.Repeat([]byte{42}, 16), } diff --git a/session.go b/session.go index 31227b33f..d6a2716bb 100644 --- a/session.go +++ b/session.go @@ -992,7 +992,15 @@ func (s *session) newStream(id protocol.StreamID) streamI { func (s *session) newFlowController(id protocol.StreamID) flowcontrol.StreamFlowController { var initialSendWindow protocol.ByteCount if s.peerParams != nil { - initialSendWindow = s.peerParams.InitialMaxStreamData + if id.IsUniDirectional() { + initialSendWindow = s.peerParams.InitialMaxStreamDataUni + } else { + if id.InitiatedBy() == s.perspective { + initialSendWindow = s.peerParams.InitialMaxStreamDataBidiLocal + } else { + initialSendWindow = s.peerParams.InitialMaxStreamDataBidiRemote + } + } } return flowcontrol.NewStreamFlowController( id, diff --git a/session_test.go b/session_test.go index 0b7860d65..5cd10553c 100644 --- a/session_test.go +++ b/session_test.go @@ -995,10 +995,10 @@ var _ = Describe("Session", func() { sess.run() }() params := &handshake.TransportParameters{ - IdleTimeout: 90 * time.Second, - InitialMaxStreamData: 0x5000, - InitialMaxData: 0x5000, - MaxPacketSize: 0x42, + IdleTimeout: 90 * time.Second, + InitialMaxStreamDataBidiLocal: 0x5000, + InitialMaxData: 0x5000, + MaxPacketSize: 0x42, } streamManager.EXPECT().UpdateLimits(params) packer.EXPECT().HandleTransportParameters(params)