diff --git a/connection.go b/connection.go index 6833a7b9..c4a91a35 100644 --- a/connection.go +++ b/connection.go @@ -312,9 +312,14 @@ var newConnection = func( DisableActiveMigration: true, StatelessResetToken: &statelessResetToken, OriginalDestinationConnectionID: origDestConnID, - ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs, - InitialSourceConnectionID: srcConnID, - RetrySourceConnectionID: retrySrcConnID, + // For interoperability with quic-go versions before May 2023, this value must be set to a value + // different from protocol.DefaultActiveConnectionIDLimit. + // If set to the default value, it will be omitted from the transport parameters, which will make + // old quic-go versions interpret it as 0, instead of the default value of 2. + // See https://github.com/quic-go/quic-go/pull/3806. + ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs, + InitialSourceConnectionID: srcConnID, + RetrySourceConnectionID: retrySrcConnID, } if s.config.EnableDatagrams { params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize @@ -426,8 +431,13 @@ var newClientConnection = func( MaxAckDelay: protocol.MaxAckDelayInclGranularity, AckDelayExponent: protocol.AckDelayExponent, DisableActiveMigration: true, - ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs, - InitialSourceConnectionID: srcConnID, + // For interoperability with quic-go versions before May 2023, this value must be set to a value + // different from protocol.DefaultActiveConnectionIDLimit. + // If set to the default value, it will be omitted from the transport parameters, which will make + // old quic-go versions interpret it as 0, instead of the default value of 2. + // See https://github.com/quic-go/quic-go/pull/3806. + ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs, + InitialSourceConnectionID: srcConnID, } if s.config.EnableDatagrams { params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize diff --git a/internal/protocol/protocol.go b/internal/protocol/protocol.go index 8241e274..93ad96cc 100644 --- a/internal/protocol/protocol.go +++ b/internal/protocol/protocol.go @@ -77,6 +77,9 @@ const MinConnectionIDLenInitial = 8 // DefaultAckDelayExponent is the default ack delay exponent const DefaultAckDelayExponent = 3 +// DefaultActiveConnectionIDLimit is the default active connection ID limit +const DefaultActiveConnectionIDLimit = 2 + // MaxAckDelayExponent is the maximum ack delay exponent const MaxAckDelayExponent = 20 diff --git a/internal/wire/transport_parameter_test.go b/internal/wire/transport_parameter_test.go index f4c39603..5526750e 100644 --- a/internal/wire/transport_parameter_test.go +++ b/internal/wire/transport_parameter_test.go @@ -289,15 +289,16 @@ var _ = Describe("Transport Parameters", func() { Expect(float32(dataLen) / num).To(BeNumerically("~", float32(defaultLen)/num+float32(entryLen), 1)) }) - It("sets the default value for the ack_delay_exponent, when no value was sent", func() { + It("sets the default value for the ack_delay_exponent and max_active_connection_id_limit, when no values were sent", func() { data := (&TransportParameters{ AckDelayExponent: protocol.DefaultAckDelayExponent, StatelessResetToken: &protocol.StatelessResetToken{}, - ActiveConnectionIDLimit: 2, + ActiveConnectionIDLimit: protocol.DefaultActiveConnectionIDLimit, }).Marshal(protocol.PerspectiveServer) p := &TransportParameters{} Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed()) Expect(p.AckDelayExponent).To(BeEquivalentTo(protocol.DefaultAckDelayExponent)) + Expect(p.ActiveConnectionIDLimit).To(BeEquivalentTo(protocol.DefaultActiveConnectionIDLimit)) }) It("errors when the varint value has the wrong length", func() { diff --git a/internal/wire/transport_parameters.go b/internal/wire/transport_parameters.go index 8eb4cf46..dc1f2b95 100644 --- a/internal/wire/transport_parameters.go +++ b/internal/wire/transport_parameters.go @@ -118,6 +118,7 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec var ( readOriginalDestinationConnectionID bool readInitialSourceConnectionID bool + readActiveConnectionIDLimit bool ) p.AckDelayExponent = protocol.DefaultAckDelayExponent @@ -139,6 +140,9 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec } parameterIDs = append(parameterIDs, paramID) switch paramID { + case activeConnectionIDLimitParameterID: + readActiveConnectionIDLimit = true + fallthrough case maxIdleTimeoutParameterID, maxUDPPayloadSizeParameterID, initialMaxDataParameterID, @@ -148,7 +152,6 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec initialMaxStreamsBidiParameterID, initialMaxStreamsUniParameterID, maxAckDelayParameterID, - activeConnectionIDLimitParameterID, maxDatagramFrameSizeParameterID, ackDelayExponentParameterID: if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil { @@ -196,6 +199,9 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec } } + if !readActiveConnectionIDLimit { + p.ActiveConnectionIDLimit = protocol.DefaultActiveConnectionIDLimit + } if !fromSessionTicket { if sentBy == protocol.PerspectiveServer && !readOriginalDestinationConnectionID { return errors.New("missing original_destination_connection_id") @@ -402,7 +408,9 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte { } } // active_connection_id_limit - b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit) + if p.ActiveConnectionIDLimit != protocol.DefaultActiveConnectionIDLimit { + b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit) + } // initial_source_connection_id b = quicvarint.Append(b, uint64(initialSourceConnectionIDParameterID)) b = quicvarint.Append(b, uint64(p.InitialSourceConnectionID.Len()))