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