github.com/tumi8/quic-go@v0.37.4-tum/noninternal/wire/transport_parameter_test.go (about)

     1  package wire
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math"
     7  	"net"
     8  	"time"
     9  
    10  	"golang.org/x/exp/rand"
    11  	"github.com/tumi8/quic-go/noninternal/protocol"
    12  	"github.com/tumi8/quic-go/noninternal/qerr"
    13  	"github.com/tumi8/quic-go/quicvarint"
    14  
    15  	. "github.com/onsi/ginkgo/v2"
    16  	. "github.com/onsi/gomega"
    17  )
    18  
    19  var _ = Describe("Transport Parameters", func() {
    20  	getRandomValueUpTo := func(max int64) uint64 {
    21  		maxVals := []int64{math.MaxUint8 / 4, math.MaxUint16 / 4, math.MaxUint32 / 4, math.MaxUint64 / 4}
    22  		m := maxVals[int(rand.Int31n(4))]
    23  		if m > max {
    24  			m = max
    25  		}
    26  		return uint64(rand.Int63n(m))
    27  	}
    28  
    29  	getRandomValue := func() uint64 {
    30  		return getRandomValueUpTo(math.MaxInt64)
    31  	}
    32  
    33  	BeforeEach(func() {
    34  		rand.Seed(uint64(GinkgoRandomSeed()))
    35  	})
    36  
    37  	appendInitialSourceConnectionID := func(b []byte) []byte {
    38  		b = quicvarint.Append(b, uint64(initialSourceConnectionIDParameterID))
    39  		b = quicvarint.Append(b, 6)
    40  		return append(b, []byte("foobar")...)
    41  	}
    42  
    43  	It("has a string representation", func() {
    44  		rcid := protocol.ParseConnectionID([]byte{0xde, 0xad, 0xc0, 0xde})
    45  		p := &TransportParameters{
    46  			InitialMaxStreamDataBidiLocal:   1234,
    47  			InitialMaxStreamDataBidiRemote:  2345,
    48  			InitialMaxStreamDataUni:         3456,
    49  			InitialMaxData:                  4567,
    50  			MaxBidiStreamNum:                1337,
    51  			MaxUniStreamNum:                 7331,
    52  			MaxIdleTimeout:                  42 * time.Second,
    53  			OriginalDestinationConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
    54  			InitialSourceConnectionID:       protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}),
    55  			RetrySourceConnectionID:         &rcid,
    56  			AckDelayExponent:                14,
    57  			MaxAckDelay:                     37 * time.Millisecond,
    58  			StatelessResetToken:             &protocol.StatelessResetToken{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00},
    59  			ActiveConnectionIDLimit:         123,
    60  			MaxDatagramFrameSize:            876,
    61  		}
    62  		Expect(p.String()).To(Equal("&wire.TransportParameters{OriginalDestinationConnectionID: deadbeef, InitialSourceConnectionID: decafbad, RetrySourceConnectionID: deadc0de, InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, ActiveConnectionIDLimit: 123, StatelessResetToken: 0x112233445566778899aabbccddeeff00, MaxDatagramFrameSize: 876}"))
    63  	})
    64  
    65  	It("has a string representation, if there's no stateless reset token, no Retry source connection id and no datagram support", func() {
    66  		p := &TransportParameters{
    67  			InitialMaxStreamDataBidiLocal:   1234,
    68  			InitialMaxStreamDataBidiRemote:  2345,
    69  			InitialMaxStreamDataUni:         3456,
    70  			InitialMaxData:                  4567,
    71  			MaxBidiStreamNum:                1337,
    72  			MaxUniStreamNum:                 7331,
    73  			MaxIdleTimeout:                  42 * time.Second,
    74  			OriginalDestinationConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
    75  			InitialSourceConnectionID:       protocol.ParseConnectionID([]byte{}),
    76  			AckDelayExponent:                14,
    77  			MaxAckDelay:                     37 * time.Second,
    78  			ActiveConnectionIDLimit:         89,
    79  			MaxDatagramFrameSize:            protocol.InvalidByteCount,
    80  		}
    81  		Expect(p.String()).To(Equal("&wire.TransportParameters{OriginalDestinationConnectionID: deadbeef, InitialSourceConnectionID: (empty), InitialMaxStreamDataBidiLocal: 1234, InitialMaxStreamDataBidiRemote: 2345, InitialMaxStreamDataUni: 3456, InitialMaxData: 4567, MaxBidiStreamNum: 1337, MaxUniStreamNum: 7331, MaxIdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s, ActiveConnectionIDLimit: 89}"))
    82  	})
    83  
    84  	It("marshals and unmarshals", func() {
    85  		var token protocol.StatelessResetToken
    86  		rand.Read(token[:])
    87  		rcid := protocol.ParseConnectionID([]byte{0xde, 0xad, 0xc0, 0xde})
    88  		params := &TransportParameters{
    89  			InitialMaxStreamDataBidiLocal:   protocol.ByteCount(getRandomValue()),
    90  			InitialMaxStreamDataBidiRemote:  protocol.ByteCount(getRandomValue()),
    91  			InitialMaxStreamDataUni:         protocol.ByteCount(getRandomValue()),
    92  			InitialMaxData:                  protocol.ByteCount(getRandomValue()),
    93  			MaxIdleTimeout:                  0xcafe * time.Second,
    94  			MaxBidiStreamNum:                protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))),
    95  			MaxUniStreamNum:                 protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))),
    96  			DisableActiveMigration:          true,
    97  			StatelessResetToken:             &token,
    98  			OriginalDestinationConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
    99  			InitialSourceConnectionID:       protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}),
   100  			RetrySourceConnectionID:         &rcid,
   101  			AckDelayExponent:                13,
   102  			MaxAckDelay:                     42 * time.Millisecond,
   103  			ActiveConnectionIDLimit:         2 + getRandomValueUpTo(math.MaxInt64-2),
   104  			MaxDatagramFrameSize:            protocol.ByteCount(getRandomValue()),
   105  		}
   106  		data := params.Marshal(protocol.PerspectiveServer)
   107  
   108  		p := &TransportParameters{}
   109  		Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed())
   110  		Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal))
   111  		Expect(p.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote))
   112  		Expect(p.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni))
   113  		Expect(p.InitialMaxData).To(Equal(params.InitialMaxData))
   114  		Expect(p.MaxUniStreamNum).To(Equal(params.MaxUniStreamNum))
   115  		Expect(p.MaxBidiStreamNum).To(Equal(params.MaxBidiStreamNum))
   116  		Expect(p.MaxIdleTimeout).To(Equal(params.MaxIdleTimeout))
   117  		Expect(p.DisableActiveMigration).To(Equal(params.DisableActiveMigration))
   118  		Expect(p.StatelessResetToken).To(Equal(params.StatelessResetToken))
   119  		Expect(p.OriginalDestinationConnectionID).To(Equal(protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef})))
   120  		Expect(p.InitialSourceConnectionID).To(Equal(protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad})))
   121  		Expect(p.RetrySourceConnectionID).To(Equal(&rcid))
   122  		Expect(p.AckDelayExponent).To(Equal(uint8(13)))
   123  		Expect(p.MaxAckDelay).To(Equal(42 * time.Millisecond))
   124  		Expect(p.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit))
   125  		Expect(p.MaxDatagramFrameSize).To(Equal(params.MaxDatagramFrameSize))
   126  	})
   127  
   128  	It("marshals additional transport parameters (used for testing large ClientHellos)", func() {
   129  		origAdditionalTransportParametersClient := AdditionalTransportParametersClient
   130  		defer func() {
   131  			AdditionalTransportParametersClient = origAdditionalTransportParametersClient
   132  		}()
   133  		AdditionalTransportParametersClient = map[uint64][]byte{1337: []byte("foobar")}
   134  
   135  		result := quicvarint.Append([]byte{}, 1337)
   136  		result = quicvarint.Append(result, 6)
   137  		result = append(result, []byte("foobar")...)
   138  
   139  		params := &TransportParameters{}
   140  		Expect(bytes.Contains(params.Marshal(protocol.PerspectiveClient), result)).To(BeTrue())
   141  		Expect(bytes.Contains(params.Marshal(protocol.PerspectiveServer), result)).To(BeFalse())
   142  	})
   143  
   144  	It("doesn't marshal a retry_source_connection_id, if no Retry was performed", func() {
   145  		data := (&TransportParameters{
   146  			StatelessResetToken:     &protocol.StatelessResetToken{},
   147  			ActiveConnectionIDLimit: 2,
   148  		}).Marshal(protocol.PerspectiveServer)
   149  		p := &TransportParameters{}
   150  		Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed())
   151  		Expect(p.RetrySourceConnectionID).To(BeNil())
   152  	})
   153  
   154  	It("marshals a zero-length retry_source_connection_id", func() {
   155  		rcid := protocol.ParseConnectionID([]byte{})
   156  		data := (&TransportParameters{
   157  			RetrySourceConnectionID: &rcid,
   158  			StatelessResetToken:     &protocol.StatelessResetToken{},
   159  			ActiveConnectionIDLimit: 2,
   160  		}).Marshal(protocol.PerspectiveServer)
   161  		p := &TransportParameters{}
   162  		Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed())
   163  		Expect(p.RetrySourceConnectionID).ToNot(BeNil())
   164  		Expect(p.RetrySourceConnectionID.Len()).To(BeZero())
   165  	})
   166  
   167  	It("errors when the stateless_reset_token has the wrong length", func() {
   168  		b := quicvarint.Append(nil, uint64(statelessResetTokenParameterID))
   169  		b = quicvarint.Append(b, 15)
   170  		b = append(b, make([]byte, 15)...)
   171  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   172  			ErrorCode:    qerr.TransportParameterError,
   173  			ErrorMessage: "wrong length for stateless_reset_token: 15 (expected 16)",
   174  		}))
   175  	})
   176  
   177  	It("errors when the max_packet_size is too small", func() {
   178  		b := quicvarint.Append(nil, uint64(maxUDPPayloadSizeParameterID))
   179  		b = quicvarint.Append(b, uint64(quicvarint.Len(1199)))
   180  		b = quicvarint.Append(b, 1199)
   181  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   182  			ErrorCode:    qerr.TransportParameterError,
   183  			ErrorMessage: "invalid value for max_packet_size: 1199 (minimum 1200)",
   184  		}))
   185  	})
   186  
   187  	It("errors when disable_active_migration has content", func() {
   188  		b := quicvarint.Append(nil, uint64(disableActiveMigrationParameterID))
   189  		b = quicvarint.Append(b, 6)
   190  		b = append(b, []byte("foobar")...)
   191  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   192  			ErrorCode:    qerr.TransportParameterError,
   193  			ErrorMessage: "wrong length for disable_active_migration: 6 (expected empty)",
   194  		}))
   195  	})
   196  
   197  	It("errors when the server doesn't set the original_destination_connection_id", func() {
   198  		b := quicvarint.Append(nil, uint64(statelessResetTokenParameterID))
   199  		b = quicvarint.Append(b, 16)
   200  		b = append(b, make([]byte, 16)...)
   201  		b = appendInitialSourceConnectionID(b)
   202  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   203  			ErrorCode:    qerr.TransportParameterError,
   204  			ErrorMessage: "missing original_destination_connection_id",
   205  		}))
   206  	})
   207  
   208  	It("errors when the initial_source_connection_id is missing", func() {
   209  		Expect((&TransportParameters{}).Unmarshal([]byte{}, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{
   210  			ErrorCode:    qerr.TransportParameterError,
   211  			ErrorMessage: "missing initial_source_connection_id",
   212  		}))
   213  	})
   214  
   215  	It("errors when the max_ack_delay is too large", func() {
   216  		data := (&TransportParameters{
   217  			MaxAckDelay:         1 << 14 * time.Millisecond,
   218  			StatelessResetToken: &protocol.StatelessResetToken{},
   219  		}).Marshal(protocol.PerspectiveServer)
   220  		p := &TransportParameters{}
   221  		Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   222  			ErrorCode:    qerr.TransportParameterError,
   223  			ErrorMessage: "invalid value for max_ack_delay: 16384ms (maximum 16383ms)",
   224  		}))
   225  	})
   226  
   227  	It("doesn't send the max_ack_delay, if it has the default value", func() {
   228  		const num = 1000
   229  		var defaultLen, dataLen int
   230  		// marshal 1000 times to average out the greasing transport parameter
   231  		maxAckDelay := protocol.DefaultMaxAckDelay + time.Millisecond
   232  		for i := 0; i < num; i++ {
   233  			dataDefault := (&TransportParameters{
   234  				MaxAckDelay:         protocol.DefaultMaxAckDelay,
   235  				StatelessResetToken: &protocol.StatelessResetToken{},
   236  			}).Marshal(protocol.PerspectiveServer)
   237  			defaultLen += len(dataDefault)
   238  			data := (&TransportParameters{
   239  				MaxAckDelay:         maxAckDelay,
   240  				StatelessResetToken: &protocol.StatelessResetToken{},
   241  			}).Marshal(protocol.PerspectiveServer)
   242  			dataLen += len(data)
   243  		}
   244  		entryLen := quicvarint.Len(uint64(ackDelayExponentParameterID)) /* parameter id */ + quicvarint.Len(uint64(quicvarint.Len(uint64(maxAckDelay.Milliseconds())))) /*length */ + quicvarint.Len(uint64(maxAckDelay.Milliseconds())) /* value */
   245  		Expect(float32(dataLen) / num).To(BeNumerically("~", float32(defaultLen)/num+float32(entryLen), 1))
   246  	})
   247  
   248  	It("errors when the active_connection_id_limit is too small", func() {
   249  		data := (&TransportParameters{
   250  			ActiveConnectionIDLimit: 1,
   251  			StatelessResetToken:     &protocol.StatelessResetToken{},
   252  		}).Marshal(protocol.PerspectiveServer)
   253  		p := &TransportParameters{}
   254  		Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   255  			ErrorCode:    qerr.TransportParameterError,
   256  			ErrorMessage: "invalid value for active_connection_id_limit: 1 (minimum 2)",
   257  		}))
   258  	})
   259  
   260  	It("errors when the ack_delay_exponenent is too large", func() {
   261  		data := (&TransportParameters{
   262  			AckDelayExponent:    21,
   263  			StatelessResetToken: &protocol.StatelessResetToken{},
   264  		}).Marshal(protocol.PerspectiveServer)
   265  		p := &TransportParameters{}
   266  		Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   267  			ErrorCode:    qerr.TransportParameterError,
   268  			ErrorMessage: "invalid value for ack_delay_exponent: 21 (maximum 20)",
   269  		}))
   270  	})
   271  
   272  	It("doesn't send the ack_delay_exponent, if it has the default value", func() {
   273  		const num = 1000
   274  		var defaultLen, dataLen int
   275  		// marshal 1000 times to average out the greasing transport parameter
   276  		for i := 0; i < num; i++ {
   277  			dataDefault := (&TransportParameters{
   278  				AckDelayExponent:    protocol.DefaultAckDelayExponent,
   279  				StatelessResetToken: &protocol.StatelessResetToken{},
   280  			}).Marshal(protocol.PerspectiveServer)
   281  			defaultLen += len(dataDefault)
   282  			data := (&TransportParameters{
   283  				AckDelayExponent:    protocol.DefaultAckDelayExponent + 1,
   284  				StatelessResetToken: &protocol.StatelessResetToken{},
   285  			}).Marshal(protocol.PerspectiveServer)
   286  			dataLen += len(data)
   287  		}
   288  		entryLen := quicvarint.Len(uint64(ackDelayExponentParameterID)) /* parameter id */ + quicvarint.Len(uint64(quicvarint.Len(protocol.DefaultAckDelayExponent+1))) /* length */ + quicvarint.Len(protocol.DefaultAckDelayExponent+1) /* value */
   289  		Expect(float32(dataLen) / num).To(BeNumerically("~", float32(defaultLen)/num+float32(entryLen), 1))
   290  	})
   291  
   292  	It("sets the default value for the ack_delay_exponent and max_active_connection_id_limit, when no values were sent", func() {
   293  		data := (&TransportParameters{
   294  			AckDelayExponent:        protocol.DefaultAckDelayExponent,
   295  			StatelessResetToken:     &protocol.StatelessResetToken{},
   296  			ActiveConnectionIDLimit: protocol.DefaultActiveConnectionIDLimit,
   297  		}).Marshal(protocol.PerspectiveServer)
   298  		p := &TransportParameters{}
   299  		Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed())
   300  		Expect(p.AckDelayExponent).To(BeEquivalentTo(protocol.DefaultAckDelayExponent))
   301  		Expect(p.ActiveConnectionIDLimit).To(BeEquivalentTo(protocol.DefaultActiveConnectionIDLimit))
   302  	})
   303  
   304  	It("errors when the varint value has the wrong length", func() {
   305  		b := quicvarint.Append(nil, uint64(initialMaxStreamDataBidiLocalParameterID))
   306  		b = quicvarint.Append(b, 2)
   307  		val := uint64(0xdeadbeef)
   308  		Expect(quicvarint.Len(val)).ToNot(BeEquivalentTo(2))
   309  		b = quicvarint.Append(b, val)
   310  		b = appendInitialSourceConnectionID(b)
   311  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   312  			ErrorCode:    qerr.TransportParameterError,
   313  			ErrorMessage: fmt.Sprintf("inconsistent transport parameter length for transport parameter %#x", initialMaxStreamDataBidiLocalParameterID),
   314  		}))
   315  	})
   316  
   317  	It("errors if initial_max_streams_bidi is too large", func() {
   318  		b := quicvarint.Append(nil, uint64(initialMaxStreamsBidiParameterID))
   319  		b = quicvarint.Append(b, uint64(quicvarint.Len(uint64(protocol.MaxStreamCount+1))))
   320  		b = quicvarint.Append(b, uint64(protocol.MaxStreamCount+1))
   321  		b = appendInitialSourceConnectionID(b)
   322  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   323  			ErrorCode:    qerr.TransportParameterError,
   324  			ErrorMessage: "initial_max_streams_bidi too large: 1152921504606846977 (maximum 1152921504606846976)",
   325  		}))
   326  	})
   327  
   328  	It("errors if initial_max_streams_uni is too large", func() {
   329  		b := quicvarint.Append(nil, uint64(initialMaxStreamsUniParameterID))
   330  		b = quicvarint.Append(b, uint64(quicvarint.Len(uint64(protocol.MaxStreamCount+1))))
   331  		b = quicvarint.Append(b, uint64(protocol.MaxStreamCount+1))
   332  		b = appendInitialSourceConnectionID(b)
   333  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   334  			ErrorCode:    qerr.TransportParameterError,
   335  			ErrorMessage: "initial_max_streams_uni too large: 1152921504606846977 (maximum 1152921504606846976)",
   336  		}))
   337  	})
   338  
   339  	It("handles huge max_ack_delay values", func() {
   340  		val := uint64(math.MaxUint64) / 5
   341  		b := quicvarint.Append(nil, uint64(maxAckDelayParameterID))
   342  		b = quicvarint.Append(b, uint64(quicvarint.Len(val)))
   343  		b = quicvarint.Append(b, val)
   344  		b = appendInitialSourceConnectionID(b)
   345  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{
   346  			ErrorCode:    qerr.TransportParameterError,
   347  			ErrorMessage: "invalid value for max_ack_delay: 3689348814741910323ms (maximum 16383ms)",
   348  		}))
   349  	})
   350  
   351  	It("skips unknown parameters", func() {
   352  		// write a known parameter
   353  		b := quicvarint.Append(nil, uint64(initialMaxStreamDataBidiLocalParameterID))
   354  		b = quicvarint.Append(b, uint64(quicvarint.Len(0x1337)))
   355  		b = quicvarint.Append(b, 0x1337)
   356  		// write an unknown parameter
   357  		b = quicvarint.Append(b, 0x42)
   358  		b = quicvarint.Append(b, 6)
   359  		b = append(b, []byte("foobar")...)
   360  		// write a known parameter
   361  		b = quicvarint.Append(b, uint64(initialMaxStreamDataBidiRemoteParameterID))
   362  		b = quicvarint.Append(b, uint64(quicvarint.Len(0x42)))
   363  		b = quicvarint.Append(b, 0x42)
   364  		b = appendInitialSourceConnectionID(b)
   365  		p := &TransportParameters{}
   366  		Expect(p.Unmarshal(b, protocol.PerspectiveClient)).To(Succeed())
   367  		Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(protocol.ByteCount(0x1337)))
   368  		Expect(p.InitialMaxStreamDataBidiRemote).To(Equal(protocol.ByteCount(0x42)))
   369  	})
   370  
   371  	It("rejects duplicate parameters", func() {
   372  		// write first parameter
   373  		b := quicvarint.Append(nil, uint64(initialMaxStreamDataBidiLocalParameterID))
   374  		b = quicvarint.Append(b, uint64(quicvarint.Len(0x1337)))
   375  		b = quicvarint.Append(b, 0x1337)
   376  		// write a second parameter
   377  		b = quicvarint.Append(b, uint64(initialMaxStreamDataBidiRemoteParameterID))
   378  		b = quicvarint.Append(b, uint64(quicvarint.Len(0x42)))
   379  		b = quicvarint.Append(b, 0x42)
   380  		// write first parameter again
   381  		b = quicvarint.Append(b, uint64(initialMaxStreamDataBidiLocalParameterID))
   382  		b = quicvarint.Append(b, uint64(quicvarint.Len(0x1337)))
   383  		b = quicvarint.Append(b, 0x1337)
   384  		b = appendInitialSourceConnectionID(b)
   385  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{
   386  			ErrorCode:    qerr.TransportParameterError,
   387  			ErrorMessage: fmt.Sprintf("received duplicate transport parameter %#x", initialMaxStreamDataBidiLocalParameterID),
   388  		}))
   389  	})
   390  
   391  	It("errors if there's not enough data to read", func() {
   392  		b := quicvarint.Append(nil, 0x42)
   393  		b = quicvarint.Append(b, 7)
   394  		b = append(b, []byte("foobar")...)
   395  		p := &TransportParameters{}
   396  		Expect(p.Unmarshal(b, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   397  			ErrorCode:    qerr.TransportParameterError,
   398  			ErrorMessage: "remaining length (6) smaller than parameter length (7)",
   399  		}))
   400  	})
   401  
   402  	It("errors if the client sent a stateless_reset_token", func() {
   403  		b := quicvarint.Append(nil, uint64(statelessResetTokenParameterID))
   404  		b = quicvarint.Append(b, uint64(quicvarint.Len(16)))
   405  		b = append(b, make([]byte, 16)...)
   406  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{
   407  			ErrorCode:    qerr.TransportParameterError,
   408  			ErrorMessage: "client sent a stateless_reset_token",
   409  		}))
   410  	})
   411  
   412  	It("errors if the client sent the original_destination_connection_id", func() {
   413  		b := quicvarint.Append(nil, uint64(originalDestinationConnectionIDParameterID))
   414  		b = quicvarint.Append(b, 6)
   415  		b = append(b, []byte("foobar")...)
   416  		Expect((&TransportParameters{}).Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{
   417  			ErrorCode:    qerr.TransportParameterError,
   418  			ErrorMessage: "client sent an original_destination_connection_id",
   419  		}))
   420  	})
   421  
   422  	Context("preferred address", func() {
   423  		var pa *PreferredAddress
   424  
   425  		BeforeEach(func() {
   426  			pa = &PreferredAddress{
   427  				IPv4:                net.IPv4(127, 0, 0, 1),
   428  				IPv4Port:            42,
   429  				IPv6:                net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
   430  				IPv6Port:            13,
   431  				ConnectionID:        protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
   432  				StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
   433  			}
   434  		})
   435  
   436  		It("marshals and unmarshals", func() {
   437  			data := (&TransportParameters{
   438  				PreferredAddress:        pa,
   439  				StatelessResetToken:     &protocol.StatelessResetToken{},
   440  				ActiveConnectionIDLimit: 2,
   441  			}).Marshal(protocol.PerspectiveServer)
   442  			p := &TransportParameters{}
   443  			Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(Succeed())
   444  			Expect(p.PreferredAddress.IPv4.String()).To(Equal(pa.IPv4.String()))
   445  			Expect(p.PreferredAddress.IPv4Port).To(Equal(pa.IPv4Port))
   446  			Expect(p.PreferredAddress.IPv6.String()).To(Equal(pa.IPv6.String()))
   447  			Expect(p.PreferredAddress.IPv6Port).To(Equal(pa.IPv6Port))
   448  			Expect(p.PreferredAddress.ConnectionID).To(Equal(pa.ConnectionID))
   449  			Expect(p.PreferredAddress.StatelessResetToken).To(Equal(pa.StatelessResetToken))
   450  		})
   451  
   452  		It("errors if the client sent a preferred_address", func() {
   453  			b := quicvarint.Append(nil, uint64(preferredAddressParameterID))
   454  			b = quicvarint.Append(b, 6)
   455  			b = append(b, []byte("foobar")...)
   456  			p := &TransportParameters{}
   457  			Expect(p.Unmarshal(b, protocol.PerspectiveClient)).To(MatchError(&qerr.TransportError{
   458  				ErrorCode:    qerr.TransportParameterError,
   459  				ErrorMessage: "client sent a preferred_address",
   460  			}))
   461  		})
   462  
   463  		It("errors on zero-length connection IDs", func() {
   464  			pa.ConnectionID = protocol.ParseConnectionID([]byte{})
   465  			data := (&TransportParameters{
   466  				PreferredAddress:    pa,
   467  				StatelessResetToken: &protocol.StatelessResetToken{},
   468  			}).Marshal(protocol.PerspectiveServer)
   469  			p := &TransportParameters{}
   470  			Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError(&qerr.TransportError{
   471  				ErrorCode:    qerr.TransportParameterError,
   472  				ErrorMessage: "invalid connection ID length: 0",
   473  			}))
   474  		})
   475  
   476  		It("errors on EOF", func() {
   477  			raw := []byte{
   478  				127, 0, 0, 1, // IPv4
   479  				0, 42, // IPv4 Port
   480  				1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, // IPv6
   481  				13, 37, // IPv6 Port,
   482  				4, // conn ID len
   483  				0xde, 0xad, 0xbe, 0xef,
   484  				16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, // stateless reset token
   485  			}
   486  			for i := 1; i < len(raw); i++ {
   487  				b := quicvarint.Append(nil, uint64(preferredAddressParameterID))
   488  				b = append(b, raw[:i]...)
   489  				p := &TransportParameters{}
   490  				Expect(p.Unmarshal(b, protocol.PerspectiveServer)).ToNot(Succeed())
   491  			}
   492  		})
   493  	})
   494  
   495  	Context("saving and retrieving from a session ticket", func() {
   496  		It("saves and retrieves the parameters", func() {
   497  			params := &TransportParameters{
   498  				InitialMaxStreamDataBidiLocal:  protocol.ByteCount(getRandomValue()),
   499  				InitialMaxStreamDataBidiRemote: protocol.ByteCount(getRandomValue()),
   500  				InitialMaxStreamDataUni:        protocol.ByteCount(getRandomValue()),
   501  				InitialMaxData:                 protocol.ByteCount(getRandomValue()),
   502  				MaxBidiStreamNum:               protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))),
   503  				MaxUniStreamNum:                protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))),
   504  				ActiveConnectionIDLimit:        2 + getRandomValueUpTo(math.MaxInt64-2),
   505  			}
   506  			Expect(params.ValidFor0RTT(params)).To(BeTrue())
   507  			b := params.MarshalForSessionTicket(nil)
   508  			var tp TransportParameters
   509  			Expect(tp.UnmarshalFromSessionTicket(bytes.NewReader(b))).To(Succeed())
   510  			Expect(tp.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal))
   511  			Expect(tp.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote))
   512  			Expect(tp.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni))
   513  			Expect(tp.InitialMaxData).To(Equal(params.InitialMaxData))
   514  			Expect(tp.MaxBidiStreamNum).To(Equal(params.MaxBidiStreamNum))
   515  			Expect(tp.MaxUniStreamNum).To(Equal(params.MaxUniStreamNum))
   516  			Expect(tp.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit))
   517  		})
   518  
   519  		It("rejects the parameters if it can't parse them", func() {
   520  			var p TransportParameters
   521  			Expect(p.UnmarshalFromSessionTicket(bytes.NewReader([]byte("foobar")))).ToNot(Succeed())
   522  		})
   523  
   524  		It("rejects the parameters if the version changed", func() {
   525  			var p TransportParameters
   526  			data := p.MarshalForSessionTicket(nil)
   527  			b := quicvarint.Append(nil, transportParameterMarshalingVersion+1)
   528  			b = append(b, data[quicvarint.Len(transportParameterMarshalingVersion):]...)
   529  			Expect(p.UnmarshalFromSessionTicket(bytes.NewReader(b))).To(MatchError(fmt.Sprintf("unknown transport parameter marshaling version: %d", transportParameterMarshalingVersion+1)))
   530  		})
   531  
   532  		Context("rejects the parameters if they changed", func() {
   533  			var p TransportParameters
   534  			saved := &TransportParameters{
   535  				InitialMaxStreamDataBidiLocal:  1,
   536  				InitialMaxStreamDataBidiRemote: 2,
   537  				InitialMaxStreamDataUni:        3,
   538  				InitialMaxData:                 4,
   539  				MaxBidiStreamNum:               5,
   540  				MaxUniStreamNum:                6,
   541  				ActiveConnectionIDLimit:        7,
   542  			}
   543  
   544  			BeforeEach(func() {
   545  				p = *saved
   546  				Expect(p.ValidFor0RTT(saved)).To(BeTrue())
   547  			})
   548  
   549  			It("rejects the parameters if the InitialMaxStreamDataBidiLocal was reduced", func() {
   550  				p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal - 1
   551  				Expect(p.ValidFor0RTT(saved)).To(BeFalse())
   552  			})
   553  
   554  			It("doesn't reject the parameters if the InitialMaxStreamDataBidiLocal was increased", func() {
   555  				p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal + 1
   556  				Expect(p.ValidFor0RTT(saved)).To(BeTrue())
   557  			})
   558  
   559  			It("rejects the parameters if the InitialMaxStreamDataBidiRemote was reduced", func() {
   560  				p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote - 1
   561  				Expect(p.ValidFor0RTT(saved)).To(BeFalse())
   562  			})
   563  
   564  			It("doesn't reject the parameters if the InitialMaxStreamDataBidiRemote was increased", func() {
   565  				p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote + 1
   566  				Expect(p.ValidFor0RTT(saved)).To(BeTrue())
   567  			})
   568  
   569  			It("rejects the parameters if the InitialMaxStreamDataUni was reduced", func() {
   570  				p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni - 1
   571  				Expect(p.ValidFor0RTT(saved)).To(BeFalse())
   572  			})
   573  
   574  			It("doesn't reject the parameters if the InitialMaxStreamDataUni was increased", func() {
   575  				p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni + 1
   576  				Expect(p.ValidFor0RTT(saved)).To(BeTrue())
   577  			})
   578  
   579  			It("rejects the parameters if the InitialMaxData was reduced", func() {
   580  				p.InitialMaxData = saved.InitialMaxData - 1
   581  				Expect(p.ValidFor0RTT(saved)).To(BeFalse())
   582  			})
   583  
   584  			It("doesn't reject the parameters if the InitialMaxData was increased", func() {
   585  				p.InitialMaxData = saved.InitialMaxData + 1
   586  				Expect(p.ValidFor0RTT(saved)).To(BeTrue())
   587  			})
   588  
   589  			It("rejects the parameters if the MaxBidiStreamNum was reduced", func() {
   590  				p.MaxBidiStreamNum = saved.MaxBidiStreamNum - 1
   591  				Expect(p.ValidFor0RTT(saved)).To(BeFalse())
   592  			})
   593  
   594  			It("accepts the parameters if the MaxBidiStreamNum was increased", func() {
   595  				p.MaxBidiStreamNum = saved.MaxBidiStreamNum + 1
   596  				Expect(p.ValidFor0RTT(saved)).To(BeTrue())
   597  			})
   598  
   599  			It("rejects the parameters if the MaxUniStreamNum changed", func() {
   600  				p.MaxUniStreamNum = saved.MaxUniStreamNum - 1
   601  				Expect(p.ValidFor0RTT(saved)).To(BeFalse())
   602  			})
   603  
   604  			It("accepts the parameters if the MaxUniStreamNum was increased", func() {
   605  				p.MaxUniStreamNum = saved.MaxUniStreamNum + 1
   606  				Expect(p.ValidFor0RTT(saved)).To(BeTrue())
   607  			})
   608  
   609  			It("rejects the parameters if the ActiveConnectionIDLimit changed", func() {
   610  				p.ActiveConnectionIDLimit = 0
   611  				Expect(p.ValidFor0RTT(saved)).To(BeFalse())
   612  			})
   613  		})
   614  
   615  		Context("client checks the parameters after successfully sending 0-RTT data", func() {
   616  			var p TransportParameters
   617  			saved := &TransportParameters{
   618  				InitialMaxStreamDataBidiLocal:  1,
   619  				InitialMaxStreamDataBidiRemote: 2,
   620  				InitialMaxStreamDataUni:        3,
   621  				InitialMaxData:                 4,
   622  				MaxBidiStreamNum:               5,
   623  				MaxUniStreamNum:                6,
   624  				ActiveConnectionIDLimit:        7,
   625  			}
   626  
   627  			BeforeEach(func() {
   628  				p = *saved
   629  				Expect(p.ValidForUpdate(saved)).To(BeTrue())
   630  			})
   631  
   632  			It("rejects the parameters if the InitialMaxStreamDataBidiLocal was reduced", func() {
   633  				p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal - 1
   634  				Expect(p.ValidForUpdate(saved)).To(BeFalse())
   635  			})
   636  
   637  			It("doesn't reject the parameters if the InitialMaxStreamDataBidiLocal was increased", func() {
   638  				p.InitialMaxStreamDataBidiLocal = saved.InitialMaxStreamDataBidiLocal + 1
   639  				Expect(p.ValidForUpdate(saved)).To(BeTrue())
   640  			})
   641  
   642  			It("rejects the parameters if the InitialMaxStreamDataBidiRemote was reduced", func() {
   643  				p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote - 1
   644  				Expect(p.ValidForUpdate(saved)).To(BeFalse())
   645  			})
   646  
   647  			It("doesn't reject the parameters if the InitialMaxStreamDataBidiRemote was increased", func() {
   648  				p.InitialMaxStreamDataBidiRemote = saved.InitialMaxStreamDataBidiRemote + 1
   649  				Expect(p.ValidForUpdate(saved)).To(BeTrue())
   650  			})
   651  
   652  			It("rejects the parameters if the InitialMaxStreamDataUni was reduced", func() {
   653  				p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni - 1
   654  				Expect(p.ValidForUpdate(saved)).To(BeFalse())
   655  			})
   656  
   657  			It("doesn't reject the parameters if the InitialMaxStreamDataUni was increased", func() {
   658  				p.InitialMaxStreamDataUni = saved.InitialMaxStreamDataUni + 1
   659  				Expect(p.ValidForUpdate(saved)).To(BeTrue())
   660  			})
   661  
   662  			It("rejects the parameters if the InitialMaxData was reduced", func() {
   663  				p.InitialMaxData = saved.InitialMaxData - 1
   664  				Expect(p.ValidForUpdate(saved)).To(BeFalse())
   665  			})
   666  
   667  			It("doesn't reject the parameters if the InitialMaxData was increased", func() {
   668  				p.InitialMaxData = saved.InitialMaxData + 1
   669  				Expect(p.ValidForUpdate(saved)).To(BeTrue())
   670  			})
   671  
   672  			It("rejects the parameters if the MaxBidiStreamNum was reduced", func() {
   673  				p.MaxBidiStreamNum = saved.MaxBidiStreamNum - 1
   674  				Expect(p.ValidForUpdate(saved)).To(BeFalse())
   675  			})
   676  
   677  			It("doesn't reject the parameters if the MaxBidiStreamNum was increased", func() {
   678  				p.MaxBidiStreamNum = saved.MaxBidiStreamNum + 1
   679  				Expect(p.ValidForUpdate(saved)).To(BeTrue())
   680  			})
   681  
   682  			It("rejects the parameters if the MaxUniStreamNum reduced", func() {
   683  				p.MaxUniStreamNum = saved.MaxUniStreamNum - 1
   684  				Expect(p.ValidForUpdate(saved)).To(BeFalse())
   685  			})
   686  
   687  			It("doesn't reject the parameters if the MaxUniStreamNum was increased", func() {
   688  				p.MaxUniStreamNum = saved.MaxUniStreamNum + 1
   689  				Expect(p.ValidForUpdate(saved)).To(BeTrue())
   690  			})
   691  
   692  			It("rejects the parameters if the ActiveConnectionIDLimit reduced", func() {
   693  				p.ActiveConnectionIDLimit = saved.ActiveConnectionIDLimit - 1
   694  				Expect(p.ValidForUpdate(saved)).To(BeFalse())
   695  			})
   696  
   697  			It("doesn't reject the parameters if the ActiveConnectionIDLimit increased", func() {
   698  				p.ActiveConnectionIDLimit = saved.ActiveConnectionIDLimit + 1
   699  				Expect(p.ValidForUpdate(saved)).To(BeTrue())
   700  			})
   701  		})
   702  	})
   703  })