github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/internal/wire/transport_parameters.go (about)

     1  package wire
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"golang.org/x/exp/slices"
     9  	"io"
    10  	"net/netip"
    11  	"time"
    12  
    13  	"github.com/metacubex/quic-go/internal/protocol"
    14  	"github.com/metacubex/quic-go/internal/qerr"
    15  	"github.com/metacubex/quic-go/internal/utils"
    16  	"github.com/metacubex/quic-go/quicvarint"
    17  )
    18  
    19  // AdditionalTransportParametersClient are additional transport parameters that will be added
    20  // to the client's transport parameters.
    21  // This is not intended for production use, but _only_ to increase the size of the ClientHello beyond
    22  // the usual size of less than 1 MTU.
    23  var AdditionalTransportParametersClient map[uint64][]byte
    24  
    25  const transportParameterMarshalingVersion = 1
    26  
    27  type transportParameterID uint64
    28  
    29  const (
    30  	originalDestinationConnectionIDParameterID transportParameterID = 0x0
    31  	maxIdleTimeoutParameterID                  transportParameterID = 0x1
    32  	statelessResetTokenParameterID             transportParameterID = 0x2
    33  	maxUDPPayloadSizeParameterID               transportParameterID = 0x3
    34  	initialMaxDataParameterID                  transportParameterID = 0x4
    35  	initialMaxStreamDataBidiLocalParameterID   transportParameterID = 0x5
    36  	initialMaxStreamDataBidiRemoteParameterID  transportParameterID = 0x6
    37  	initialMaxStreamDataUniParameterID         transportParameterID = 0x7
    38  	initialMaxStreamsBidiParameterID           transportParameterID = 0x8
    39  	initialMaxStreamsUniParameterID            transportParameterID = 0x9
    40  	ackDelayExponentParameterID                transportParameterID = 0xa
    41  	maxAckDelayParameterID                     transportParameterID = 0xb
    42  	disableActiveMigrationParameterID          transportParameterID = 0xc
    43  	preferredAddressParameterID                transportParameterID = 0xd
    44  	activeConnectionIDLimitParameterID         transportParameterID = 0xe
    45  	initialSourceConnectionIDParameterID       transportParameterID = 0xf
    46  	retrySourceConnectionIDParameterID         transportParameterID = 0x10
    47  	// RFC 9221
    48  	maxDatagramFrameSizeParameterID transportParameterID = 0x20
    49  )
    50  
    51  // PreferredAddress is the value encoding in the preferred_address transport parameter
    52  type PreferredAddress struct {
    53  	IPv4, IPv6          netip.AddrPort
    54  	ConnectionID        protocol.ConnectionID
    55  	StatelessResetToken protocol.StatelessResetToken
    56  }
    57  
    58  // TransportParameters are parameters sent to the peer during the handshake
    59  type TransportParameters struct {
    60  	InitialMaxStreamDataBidiLocal  protocol.ByteCount
    61  	InitialMaxStreamDataBidiRemote protocol.ByteCount
    62  	InitialMaxStreamDataUni        protocol.ByteCount
    63  	InitialMaxData                 protocol.ByteCount
    64  
    65  	MaxAckDelay      time.Duration
    66  	AckDelayExponent uint8
    67  
    68  	DisableActiveMigration bool
    69  
    70  	MaxUDPPayloadSize protocol.ByteCount
    71  
    72  	MaxUniStreamNum  protocol.StreamNum
    73  	MaxBidiStreamNum protocol.StreamNum
    74  
    75  	MaxIdleTimeout time.Duration
    76  
    77  	PreferredAddress *PreferredAddress
    78  
    79  	OriginalDestinationConnectionID protocol.ConnectionID
    80  	InitialSourceConnectionID       protocol.ConnectionID
    81  	RetrySourceConnectionID         *protocol.ConnectionID // use a pointer here to distinguish zero-length connection IDs from missing transport parameters
    82  
    83  	StatelessResetToken     *protocol.StatelessResetToken
    84  	ActiveConnectionIDLimit uint64
    85  
    86  	MaxDatagramFrameSize protocol.ByteCount
    87  }
    88  
    89  // Unmarshal the transport parameters
    90  func (p *TransportParameters) Unmarshal(data []byte, sentBy protocol.Perspective) error {
    91  	if err := p.unmarshal(data, sentBy, false); err != nil {
    92  		return &qerr.TransportError{
    93  			ErrorCode:    qerr.TransportParameterError,
    94  			ErrorMessage: err.Error(),
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  func (p *TransportParameters) unmarshal(b []byte, sentBy protocol.Perspective, fromSessionTicket bool) error {
   101  	// needed to check that every parameter is only sent at most once
   102  	parameterIDs := make([]transportParameterID, 0, 32)
   103  
   104  	var (
   105  		readOriginalDestinationConnectionID bool
   106  		readInitialSourceConnectionID       bool
   107  		readActiveConnectionIDLimit         bool
   108  	)
   109  
   110  	p.AckDelayExponent = protocol.DefaultAckDelayExponent
   111  	p.MaxAckDelay = protocol.DefaultMaxAckDelay
   112  	p.MaxDatagramFrameSize = protocol.InvalidByteCount
   113  
   114  	for len(b) > 0 {
   115  		paramIDInt, l, err := quicvarint.Parse(b)
   116  		if err != nil {
   117  			return err
   118  		}
   119  		paramID := transportParameterID(paramIDInt)
   120  		b = b[l:]
   121  		paramLen, l, err := quicvarint.Parse(b)
   122  		if err != nil {
   123  			return err
   124  		}
   125  		b = b[l:]
   126  		if uint64(len(b)) < paramLen {
   127  			return fmt.Errorf("remaining length (%d) smaller than parameter length (%d)", len(b), paramLen)
   128  		}
   129  		parameterIDs = append(parameterIDs, paramID)
   130  		switch paramID {
   131  		case activeConnectionIDLimitParameterID:
   132  			readActiveConnectionIDLimit = true
   133  			fallthrough
   134  		case maxIdleTimeoutParameterID,
   135  			maxUDPPayloadSizeParameterID,
   136  			initialMaxDataParameterID,
   137  			initialMaxStreamDataBidiLocalParameterID,
   138  			initialMaxStreamDataBidiRemoteParameterID,
   139  			initialMaxStreamDataUniParameterID,
   140  			initialMaxStreamsBidiParameterID,
   141  			initialMaxStreamsUniParameterID,
   142  			maxAckDelayParameterID,
   143  			maxDatagramFrameSizeParameterID,
   144  			ackDelayExponentParameterID:
   145  			if err := p.readNumericTransportParameter(b, paramID, int(paramLen)); err != nil {
   146  				return err
   147  			}
   148  			b = b[paramLen:]
   149  		case preferredAddressParameterID:
   150  			if sentBy == protocol.PerspectiveClient {
   151  				return errors.New("client sent a preferred_address")
   152  			}
   153  			if err := p.readPreferredAddress(b, int(paramLen)); err != nil {
   154  				return err
   155  			}
   156  			b = b[paramLen:]
   157  		case disableActiveMigrationParameterID:
   158  			if paramLen != 0 {
   159  				return fmt.Errorf("wrong length for disable_active_migration: %d (expected empty)", paramLen)
   160  			}
   161  			p.DisableActiveMigration = true
   162  		case statelessResetTokenParameterID:
   163  			if sentBy == protocol.PerspectiveClient {
   164  				return errors.New("client sent a stateless_reset_token")
   165  			}
   166  			if paramLen != 16 {
   167  				return fmt.Errorf("wrong length for stateless_reset_token: %d (expected 16)", paramLen)
   168  			}
   169  			var token protocol.StatelessResetToken
   170  			if len(b) < len(token) {
   171  				return io.EOF
   172  			}
   173  			copy(token[:], b)
   174  			b = b[len(token):]
   175  			p.StatelessResetToken = &token
   176  		case originalDestinationConnectionIDParameterID:
   177  			if sentBy == protocol.PerspectiveClient {
   178  				return errors.New("client sent an original_destination_connection_id")
   179  			}
   180  			if paramLen > protocol.MaxConnIDLen {
   181  				return protocol.ErrInvalidConnectionIDLen
   182  			}
   183  			p.OriginalDestinationConnectionID = protocol.ParseConnectionID(b[:paramLen])
   184  			b = b[paramLen:]
   185  			readOriginalDestinationConnectionID = true
   186  		case initialSourceConnectionIDParameterID:
   187  			if paramLen > protocol.MaxConnIDLen {
   188  				return protocol.ErrInvalidConnectionIDLen
   189  			}
   190  			p.InitialSourceConnectionID = protocol.ParseConnectionID(b[:paramLen])
   191  			b = b[paramLen:]
   192  			readInitialSourceConnectionID = true
   193  		case retrySourceConnectionIDParameterID:
   194  			if sentBy == protocol.PerspectiveClient {
   195  				return errors.New("client sent a retry_source_connection_id")
   196  			}
   197  			if paramLen > protocol.MaxConnIDLen {
   198  				return protocol.ErrInvalidConnectionIDLen
   199  			}
   200  			connID := protocol.ParseConnectionID(b[:paramLen])
   201  			b = b[paramLen:]
   202  			p.RetrySourceConnectionID = &connID
   203  		default:
   204  			b = b[paramLen:]
   205  		}
   206  	}
   207  
   208  	if !readActiveConnectionIDLimit {
   209  		p.ActiveConnectionIDLimit = protocol.DefaultActiveConnectionIDLimit
   210  	}
   211  	if !fromSessionTicket {
   212  		if sentBy == protocol.PerspectiveServer && !readOriginalDestinationConnectionID {
   213  			return errors.New("missing original_destination_connection_id")
   214  		}
   215  		if p.MaxUDPPayloadSize == 0 {
   216  			p.MaxUDPPayloadSize = protocol.MaxByteCount
   217  		}
   218  		if !readInitialSourceConnectionID {
   219  			return errors.New("missing initial_source_connection_id")
   220  		}
   221  	}
   222  
   223  	// check that every transport parameter was sent at most once
   224  	slices.SortFunc(parameterIDs, func(a, b transportParameterID) int {
   225  		if a < b {
   226  			return -1
   227  		}
   228  		return 1
   229  	})
   230  	for i := 0; i < len(parameterIDs)-1; i++ {
   231  		if parameterIDs[i] == parameterIDs[i+1] {
   232  			return fmt.Errorf("received duplicate transport parameter %#x", parameterIDs[i])
   233  		}
   234  	}
   235  
   236  	return nil
   237  }
   238  
   239  func (p *TransportParameters) readPreferredAddress(b []byte, expectedLen int) error {
   240  	remainingLen := len(b)
   241  	pa := &PreferredAddress{}
   242  	if len(b) < 4+2+16+2+1 {
   243  		return io.EOF
   244  	}
   245  	var ipv4 [4]byte
   246  	copy(ipv4[:], b[:4])
   247  	port4 := binary.BigEndian.Uint16(b[4:])
   248  	b = b[4+2:]
   249  	pa.IPv4 = netip.AddrPortFrom(netip.AddrFrom4(ipv4), port4)
   250  	var ipv6 [16]byte
   251  	copy(ipv6[:], b[:16])
   252  	port6 := binary.BigEndian.Uint16(b[16:])
   253  	pa.IPv6 = netip.AddrPortFrom(netip.AddrFrom16(ipv6), port6)
   254  	b = b[16+2:]
   255  	connIDLen := int(b[0])
   256  	b = b[1:]
   257  	if connIDLen == 0 || connIDLen > protocol.MaxConnIDLen {
   258  		return fmt.Errorf("invalid connection ID length: %d", connIDLen)
   259  	}
   260  	if len(b) < connIDLen+len(pa.StatelessResetToken) {
   261  		return io.EOF
   262  	}
   263  	pa.ConnectionID = protocol.ParseConnectionID(b[:connIDLen])
   264  	b = b[connIDLen:]
   265  	copy(pa.StatelessResetToken[:], b)
   266  	b = b[len(pa.StatelessResetToken):]
   267  	if bytesRead := remainingLen - len(b); bytesRead != expectedLen {
   268  		return fmt.Errorf("expected preferred_address to be %d long, read %d bytes", expectedLen, bytesRead)
   269  	}
   270  	p.PreferredAddress = pa
   271  	return nil
   272  }
   273  
   274  func (p *TransportParameters) readNumericTransportParameter(b []byte, paramID transportParameterID, expectedLen int) error {
   275  	val, l, err := quicvarint.Parse(b)
   276  	if err != nil {
   277  		return fmt.Errorf("error while reading transport parameter %d: %s", paramID, err)
   278  	}
   279  	if l != expectedLen {
   280  		return fmt.Errorf("inconsistent transport parameter length for transport parameter %#x", paramID)
   281  	}
   282  	//nolint:exhaustive // This only covers the numeric transport parameters.
   283  	switch paramID {
   284  	case initialMaxStreamDataBidiLocalParameterID:
   285  		p.InitialMaxStreamDataBidiLocal = protocol.ByteCount(val)
   286  	case initialMaxStreamDataBidiRemoteParameterID:
   287  		p.InitialMaxStreamDataBidiRemote = protocol.ByteCount(val)
   288  	case initialMaxStreamDataUniParameterID:
   289  		p.InitialMaxStreamDataUni = protocol.ByteCount(val)
   290  	case initialMaxDataParameterID:
   291  		p.InitialMaxData = protocol.ByteCount(val)
   292  	case initialMaxStreamsBidiParameterID:
   293  		p.MaxBidiStreamNum = protocol.StreamNum(val)
   294  		if p.MaxBidiStreamNum > protocol.MaxStreamCount {
   295  			return fmt.Errorf("initial_max_streams_bidi too large: %d (maximum %d)", p.MaxBidiStreamNum, protocol.MaxStreamCount)
   296  		}
   297  	case initialMaxStreamsUniParameterID:
   298  		p.MaxUniStreamNum = protocol.StreamNum(val)
   299  		if p.MaxUniStreamNum > protocol.MaxStreamCount {
   300  			return fmt.Errorf("initial_max_streams_uni too large: %d (maximum %d)", p.MaxUniStreamNum, protocol.MaxStreamCount)
   301  		}
   302  	case maxIdleTimeoutParameterID:
   303  		p.MaxIdleTimeout = utils.Max(protocol.MinRemoteIdleTimeout, time.Duration(val)*time.Millisecond)
   304  	case maxUDPPayloadSizeParameterID:
   305  		if val < 1200 {
   306  			return fmt.Errorf("invalid value for max_udp_payload_size: %d (minimum 1200)", val)
   307  		}
   308  		p.MaxUDPPayloadSize = protocol.ByteCount(val)
   309  	case ackDelayExponentParameterID:
   310  		if val > protocol.MaxAckDelayExponent {
   311  			return fmt.Errorf("invalid value for ack_delay_exponent: %d (maximum %d)", val, protocol.MaxAckDelayExponent)
   312  		}
   313  		p.AckDelayExponent = uint8(val)
   314  	case maxAckDelayParameterID:
   315  		if val > uint64(protocol.MaxMaxAckDelay/time.Millisecond) {
   316  			return fmt.Errorf("invalid value for max_ack_delay: %dms (maximum %dms)", val, protocol.MaxMaxAckDelay/time.Millisecond)
   317  		}
   318  		p.MaxAckDelay = time.Duration(val) * time.Millisecond
   319  	case activeConnectionIDLimitParameterID:
   320  		if val < 2 {
   321  			return fmt.Errorf("invalid value for active_connection_id_limit: %d (minimum 2)", val)
   322  		}
   323  		p.ActiveConnectionIDLimit = val
   324  	case maxDatagramFrameSizeParameterID:
   325  		p.MaxDatagramFrameSize = protocol.ByteCount(val)
   326  	default:
   327  		return fmt.Errorf("TransportParameter BUG: transport parameter %d not found", paramID)
   328  	}
   329  	return nil
   330  }
   331  
   332  // Marshal the transport parameters
   333  func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte {
   334  	// Typical Transport Parameters consume around 110 bytes, depending on the exact values,
   335  	// especially the lengths of the Connection IDs.
   336  	// Allocate 256 bytes, so we won't have to grow the slice in any case.
   337  	b := make([]byte, 0, 256)
   338  
   339  	// add a greased value
   340  	random := make([]byte, 18)
   341  	rand.Read(random)
   342  	b = quicvarint.Append(b, 27+31*uint64(random[0]))
   343  	length := random[1] % 16
   344  	b = quicvarint.Append(b, uint64(length))
   345  	b = append(b, random[2:2+length]...)
   346  
   347  	// initial_max_stream_data_bidi_local
   348  	b = p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
   349  	// initial_max_stream_data_bidi_remote
   350  	b = p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
   351  	// initial_max_stream_data_uni
   352  	b = p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
   353  	// initial_max_data
   354  	b = p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
   355  	// initial_max_bidi_streams
   356  	b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
   357  	// initial_max_uni_streams
   358  	b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
   359  	// idle_timeout
   360  	b = p.marshalVarintParam(b, maxIdleTimeoutParameterID, uint64(p.MaxIdleTimeout/time.Millisecond))
   361  	// max_udp_payload_size
   362  	if p.MaxUDPPayloadSize > 0 {
   363  		b = p.marshalVarintParam(b, maxUDPPayloadSizeParameterID, uint64(p.MaxUDPPayloadSize))
   364  	}
   365  	// max_ack_delay
   366  	// Only send it if is different from the default value.
   367  	if p.MaxAckDelay != protocol.DefaultMaxAckDelay {
   368  		b = p.marshalVarintParam(b, maxAckDelayParameterID, uint64(p.MaxAckDelay/time.Millisecond))
   369  	}
   370  	// ack_delay_exponent
   371  	// Only send it if is different from the default value.
   372  	if p.AckDelayExponent != protocol.DefaultAckDelayExponent {
   373  		b = p.marshalVarintParam(b, ackDelayExponentParameterID, uint64(p.AckDelayExponent))
   374  	}
   375  	// disable_active_migration
   376  	if p.DisableActiveMigration {
   377  		b = quicvarint.Append(b, uint64(disableActiveMigrationParameterID))
   378  		b = quicvarint.Append(b, 0)
   379  	}
   380  	if pers == protocol.PerspectiveServer {
   381  		// stateless_reset_token
   382  		if p.StatelessResetToken != nil {
   383  			b = quicvarint.Append(b, uint64(statelessResetTokenParameterID))
   384  			b = quicvarint.Append(b, 16)
   385  			b = append(b, p.StatelessResetToken[:]...)
   386  		}
   387  		// original_destination_connection_id
   388  		b = quicvarint.Append(b, uint64(originalDestinationConnectionIDParameterID))
   389  		b = quicvarint.Append(b, uint64(p.OriginalDestinationConnectionID.Len()))
   390  		b = append(b, p.OriginalDestinationConnectionID.Bytes()...)
   391  		// preferred_address
   392  		if p.PreferredAddress != nil {
   393  			b = quicvarint.Append(b, uint64(preferredAddressParameterID))
   394  			b = quicvarint.Append(b, 4+2+16+2+1+uint64(p.PreferredAddress.ConnectionID.Len())+16)
   395  			ip4 := p.PreferredAddress.IPv4.Addr().As4()
   396  			b = append(b, ip4[:]...)
   397  			b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv4.Port())
   398  			ip6 := p.PreferredAddress.IPv6.Addr().As16()
   399  			b = append(b, ip6[:]...)
   400  			b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv6.Port())
   401  			b = append(b, uint8(p.PreferredAddress.ConnectionID.Len()))
   402  			b = append(b, p.PreferredAddress.ConnectionID.Bytes()...)
   403  			b = append(b, p.PreferredAddress.StatelessResetToken[:]...)
   404  		}
   405  	}
   406  	// active_connection_id_limit
   407  	if p.ActiveConnectionIDLimit != protocol.DefaultActiveConnectionIDLimit {
   408  		b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
   409  	}
   410  	// initial_source_connection_id
   411  	b = quicvarint.Append(b, uint64(initialSourceConnectionIDParameterID))
   412  	b = quicvarint.Append(b, uint64(p.InitialSourceConnectionID.Len()))
   413  	b = append(b, p.InitialSourceConnectionID.Bytes()...)
   414  	// retry_source_connection_id
   415  	if pers == protocol.PerspectiveServer && p.RetrySourceConnectionID != nil {
   416  		b = quicvarint.Append(b, uint64(retrySourceConnectionIDParameterID))
   417  		b = quicvarint.Append(b, uint64(p.RetrySourceConnectionID.Len()))
   418  		b = append(b, p.RetrySourceConnectionID.Bytes()...)
   419  	}
   420  	if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
   421  		b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
   422  	}
   423  
   424  	if pers == protocol.PerspectiveClient && len(AdditionalTransportParametersClient) > 0 {
   425  		for k, v := range AdditionalTransportParametersClient {
   426  			b = quicvarint.Append(b, k)
   427  			b = quicvarint.Append(b, uint64(len(v)))
   428  			b = append(b, v...)
   429  		}
   430  	}
   431  
   432  	return b
   433  }
   434  
   435  func (p *TransportParameters) marshalVarintParam(b []byte, id transportParameterID, val uint64) []byte {
   436  	b = quicvarint.Append(b, uint64(id))
   437  	b = quicvarint.Append(b, uint64(quicvarint.Len(val)))
   438  	return quicvarint.Append(b, val)
   439  }
   440  
   441  // MarshalForSessionTicket marshals the transport parameters we save in the session ticket.
   442  // When sending a 0-RTT enabled TLS session tickets, we need to save the transport parameters.
   443  // The client will remember the transport parameters used in the last session,
   444  // and apply those to the 0-RTT data it sends.
   445  // Saving the transport parameters in the ticket gives the server the option to reject 0-RTT
   446  // if the transport parameters changed.
   447  // Since the session ticket is encrypted, the serialization format is defined by the server.
   448  // For convenience, we use the same format that we also use for sending the transport parameters.
   449  func (p *TransportParameters) MarshalForSessionTicket(b []byte) []byte {
   450  	b = quicvarint.Append(b, transportParameterMarshalingVersion)
   451  
   452  	// initial_max_stream_data_bidi_local
   453  	b = p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
   454  	// initial_max_stream_data_bidi_remote
   455  	b = p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
   456  	// initial_max_stream_data_uni
   457  	b = p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
   458  	// initial_max_data
   459  	b = p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
   460  	// initial_max_bidi_streams
   461  	b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
   462  	// initial_max_uni_streams
   463  	b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
   464  	// max_datagram_frame_size
   465  	if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
   466  		b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
   467  	}
   468  	// active_connection_id_limit
   469  	return p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
   470  }
   471  
   472  // UnmarshalFromSessionTicket unmarshals transport parameters from a session ticket.
   473  func (p *TransportParameters) UnmarshalFromSessionTicket(b []byte) error {
   474  	version, l, err := quicvarint.Parse(b)
   475  	if err != nil {
   476  		return err
   477  	}
   478  	if version != transportParameterMarshalingVersion {
   479  		return fmt.Errorf("unknown transport parameter marshaling version: %d", version)
   480  	}
   481  	return p.unmarshal(b[l:], protocol.PerspectiveServer, true)
   482  }
   483  
   484  // ValidFor0RTT checks if the transport parameters match those saved in the session ticket.
   485  func (p *TransportParameters) ValidFor0RTT(saved *TransportParameters) bool {
   486  	if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) {
   487  		return false
   488  	}
   489  	return p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal &&
   490  		p.InitialMaxStreamDataBidiRemote >= saved.InitialMaxStreamDataBidiRemote &&
   491  		p.InitialMaxStreamDataUni >= saved.InitialMaxStreamDataUni &&
   492  		p.InitialMaxData >= saved.InitialMaxData &&
   493  		p.MaxBidiStreamNum >= saved.MaxBidiStreamNum &&
   494  		p.MaxUniStreamNum >= saved.MaxUniStreamNum &&
   495  		p.ActiveConnectionIDLimit == saved.ActiveConnectionIDLimit
   496  }
   497  
   498  // ValidForUpdate checks that the new transport parameters don't reduce limits after resuming a 0-RTT connection.
   499  // It is only used on the client side.
   500  func (p *TransportParameters) ValidForUpdate(saved *TransportParameters) bool {
   501  	if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) {
   502  		return false
   503  	}
   504  	return p.ActiveConnectionIDLimit >= saved.ActiveConnectionIDLimit &&
   505  		p.InitialMaxData >= saved.InitialMaxData &&
   506  		p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal &&
   507  		p.InitialMaxStreamDataBidiRemote >= saved.InitialMaxStreamDataBidiRemote &&
   508  		p.InitialMaxStreamDataUni >= saved.InitialMaxStreamDataUni &&
   509  		p.MaxBidiStreamNum >= saved.MaxBidiStreamNum &&
   510  		p.MaxUniStreamNum >= saved.MaxUniStreamNum
   511  }
   512  
   513  // String returns a string representation, intended for logging.
   514  func (p *TransportParameters) String() string {
   515  	logString := "&wire.TransportParameters{OriginalDestinationConnectionID: %s, InitialSourceConnectionID: %s, "
   516  	logParams := []interface{}{p.OriginalDestinationConnectionID, p.InitialSourceConnectionID}
   517  	if p.RetrySourceConnectionID != nil {
   518  		logString += "RetrySourceConnectionID: %s, "
   519  		logParams = append(logParams, p.RetrySourceConnectionID)
   520  	}
   521  	logString += "InitialMaxStreamDataBidiLocal: %d, InitialMaxStreamDataBidiRemote: %d, InitialMaxStreamDataUni: %d, InitialMaxData: %d, MaxBidiStreamNum: %d, MaxUniStreamNum: %d, MaxIdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s, ActiveConnectionIDLimit: %d"
   522  	logParams = append(logParams, []interface{}{p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.MaxIdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit}...)
   523  	if p.StatelessResetToken != nil { // the client never sends a stateless reset token
   524  		logString += ", StatelessResetToken: %#x"
   525  		logParams = append(logParams, *p.StatelessResetToken)
   526  	}
   527  	if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
   528  		logString += ", MaxDatagramFrameSize: %d"
   529  		logParams = append(logParams, p.MaxDatagramFrameSize)
   530  	}
   531  	logString += "}"
   532  	return fmt.Sprintf(logString, logParams...)
   533  }