github.com/sagernet/quic-go@v0.43.1-beta.1/internal/wire/transport_parameters.go (about)

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