github.com/quic-go/quic-go@v0.44.0/internal/wire/transport_parameters.go (about)

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