From 37600e049d147b0a51406f0c96a48559d4e7316d Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sun, 15 Sep 2019 13:13:21 +0700 Subject: [PATCH] implement the active_connection_id_limit transport parameter --- client.go | 1 + internal/handshake/transport_parameter_test.go | 8 ++++++-- internal/handshake/transport_parameters.go | 17 ++++++++++++----- internal/protocol/params.go | 3 +++ server.go | 1 + 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/client.go b/client.go index f9686d943..826ca8f4a 100644 --- a/client.go +++ b/client.go @@ -366,6 +366,7 @@ func (c *client) createNewTLSSession(_ protocol.VersionNumber) { MaxAckDelay: protocol.MaxAckDelayInclGranularity, AckDelayExponent: protocol.AckDelayExponent, DisableMigration: true, + ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs, } c.mutex.Lock() diff --git a/internal/handshake/transport_parameter_test.go b/internal/handshake/transport_parameter_test.go index 1e9001089..913ae0366 100644 --- a/internal/handshake/transport_parameter_test.go +++ b/internal/handshake/transport_parameter_test.go @@ -33,8 +33,9 @@ var _ = Describe("Transport Parameters", func() { AckDelayExponent: 14, MaxAckDelay: 37 * time.Millisecond, StatelessResetToken: &[16]byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}, + ActiveConnectionIDLimit: 123, } - Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, IdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, StatelessResetToken: 0x112233445566778899aabbccddeeff00}")) + Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, IdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, ActiveConnectionIDLimit: 123, StatelessResetToken: 0x112233445566778899aabbccddeeff00}")) }) It("has a string representation, if there's no stateless reset token", func() { @@ -49,8 +50,9 @@ var _ = Describe("Transport Parameters", func() { OriginalConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, AckDelayExponent: 14, MaxAckDelay: 37 * time.Second, + ActiveConnectionIDLimit: 89, } - Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, IdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s}")) + Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, IdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s, ActiveConnectionIDLimit: 89}")) }) It("marshals and unmarshals", func() { @@ -75,6 +77,7 @@ var _ = Describe("Transport Parameters", func() { OriginalConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, AckDelayExponent: 13, MaxAckDelay: 42 * time.Millisecond, + ActiveConnectionIDLimit: getRandomValue(), } data := params.Marshal() @@ -92,6 +95,7 @@ var _ = Describe("Transport Parameters", func() { Expect(p.OriginalConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef})) Expect(p.AckDelayExponent).To(Equal(uint8(13))) Expect(p.MaxAckDelay).To(Equal(42 * time.Millisecond)) + Expect(p.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit)) }) It("errors if the transport parameters are too short to contain the length", func() { diff --git a/internal/handshake/transport_parameters.go b/internal/handshake/transport_parameters.go index f1360f5d8..8adf14914 100644 --- a/internal/handshake/transport_parameters.go +++ b/internal/handshake/transport_parameters.go @@ -36,6 +36,7 @@ const ( ackDelayExponentParameterID transportParameterID = 0xa maxAckDelayParameterID transportParameterID = 0xb disableMigrationParameterID transportParameterID = 0xc + activeConnectionIDLimitParameterId transportParameterID = 0xe ) // TransportParameters are parameters sent to the peer during the handshake @@ -57,8 +58,9 @@ type TransportParameters struct { IdleTimeout time.Duration - StatelessResetToken *[16]byte - OriginalConnectionID protocol.ConnectionID + StatelessResetToken *[16]byte + OriginalConnectionID protocol.ConnectionID + ActiveConnectionIDLimit uint64 } // Unmarshal the transport parameters @@ -108,7 +110,8 @@ func (p *TransportParameters) unmarshal(data []byte, sentBy protocol.Perspective initialMaxStreamsBidiParameterID, initialMaxStreamsUniParameterID, idleTimeoutParameterID, - maxPacketSizeParameterID: + maxPacketSizeParameterID, + activeConnectionIDLimitParameterId: if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil { return err } @@ -214,6 +217,8 @@ func (p *TransportParameters) readNumericTransportParameter( maxAckDelay = utils.InfDuration } p.MaxAckDelay = maxAckDelay + case activeConnectionIDLimitParameterId: + p.ActiveConnectionIDLimit = val default: return fmt.Errorf("TransportParameter BUG: transport parameter %d not found", paramID) } @@ -275,6 +280,8 @@ func (p *TransportParameters) Marshal() []byte { utils.BigEndian.WriteUint16(b, uint16(p.OriginalConnectionID.Len())) b.Write(p.OriginalConnectionID.Bytes()) } + // active_connection_id_limit + p.marshalVarintParam(b, activeConnectionIDLimitParameterId, p.ActiveConnectionIDLimit) data := b.Bytes() binary.BigEndian.PutUint16(data[:2], uint16(b.Len()-2)) @@ -289,8 +296,8 @@ func (p *TransportParameters) marshalVarintParam(b *bytes.Buffer, id transportPa // String returns a string representation, intended for logging. func (p *TransportParameters) String() string { - logString := "&handshake.TransportParameters{OriginalConnectionID: %s, InitialMaxStreamDataBidiLocal: %#x, InitialMaxStreamDataBidiRemote: %#x, InitialMaxStreamDataUni: %#x, InitialMaxData: %#x, MaxBidiStreamNum: %d, MaxUniStreamNum: %d, IdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s" - logParams := []interface{}{p.OriginalConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.IdleTimeout, p.AckDelayExponent, p.MaxAckDelay} + logString := "&handshake.TransportParameters{OriginalConnectionID: %s, InitialMaxStreamDataBidiLocal: %#x, InitialMaxStreamDataBidiRemote: %#x, InitialMaxStreamDataUni: %#x, InitialMaxData: %#x, MaxBidiStreamNum: %d, MaxUniStreamNum: %d, IdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s, ActiveConnectionIDLimit: %d" + logParams := []interface{}{p.OriginalConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.IdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit} if p.StatelessResetToken != nil { // the client never sends a stateless reset token logString += ", StatelessResetToken: %#x" logParams = append(logParams, *p.StatelessResetToken) diff --git a/internal/protocol/params.go b/internal/protocol/params.go index daa4688ee..bd6a2c7ce 100644 --- a/internal/protocol/params.go +++ b/internal/protocol/params.go @@ -133,6 +133,9 @@ const MinPacingDelay time.Duration = 100 * time.Microsecond // if no other value is configured. const DefaultConnectionIDLength = 4 +// MaxActiveConnectionIDs is the number of connection IDs that we're storing. +const MaxActiveConnectionIDs = 4 + // AckDelayExponent is the ack delay exponent used when sending ACKs. const AckDelayExponent = 3 diff --git a/server.go b/server.go index 68c5d4612..07f858c35 100644 --- a/server.go +++ b/server.go @@ -448,6 +448,7 @@ func (s *baseServer) createNewSession( DisableMigration: true, StatelessResetToken: &token, OriginalConnectionID: origDestConnID, + ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs, } sess := s.newSession( &conn{pconn: s.conn, currentAddr: remoteAddr},