github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/integrationtests/self/zero_rtt_oldgo_test.go (about)

     1  //go:build !go1.21
     2  
     3  package self_test
     4  
     5  import (
     6  	"context"
     7  	"crypto/tls"
     8  	"fmt"
     9  	"io"
    10  	mrand "math/rand"
    11  	"net"
    12  	"sync"
    13  	"sync/atomic"
    14  	"time"
    15  
    16  	"github.com/metacubex/quic-go"
    17  	quicproxy "github.com/metacubex/quic-go/integrationtests/tools/proxy"
    18  	"github.com/metacubex/quic-go/internal/protocol"
    19  	"github.com/metacubex/quic-go/internal/wire"
    20  	"github.com/metacubex/quic-go/logging"
    21  
    22  	. "github.com/onsi/ginkgo/v2"
    23  	. "github.com/onsi/gomega"
    24  )
    25  
    26  var _ = Describe("0-RTT", func() {
    27  	rtt := scaleDuration(5 * time.Millisecond)
    28  
    29  	runCountingProxy := func(serverPort int) (*quicproxy.QuicProxy, *atomic.Uint32) {
    30  		var num0RTTPackets atomic.Uint32
    31  		proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
    32  			RemoteAddr: fmt.Sprintf("localhost:%d", serverPort),
    33  			DelayPacket: func(_ quicproxy.Direction, data []byte) time.Duration {
    34  				for len(data) > 0 {
    35  					if !wire.IsLongHeaderPacket(data[0]) {
    36  						break
    37  					}
    38  					hdr, _, rest, err := wire.ParsePacket(data)
    39  					Expect(err).ToNot(HaveOccurred())
    40  					if hdr.Type == protocol.PacketType0RTT {
    41  						num0RTTPackets.Add(1)
    42  						break
    43  					}
    44  					data = rest
    45  				}
    46  				return rtt / 2
    47  			},
    48  		})
    49  		Expect(err).ToNot(HaveOccurred())
    50  
    51  		return proxy, &num0RTTPackets
    52  	}
    53  
    54  	dialAndReceiveSessionTicket := func(serverConf *quic.Config) (*tls.Config, *tls.Config) {
    55  		tlsConf := getTLSConfig()
    56  		if serverConf == nil {
    57  			serverConf = getQuicConfig(nil)
    58  		}
    59  		serverConf.Allow0RTT = true
    60  		ln, err := quic.ListenAddrEarly(
    61  			"localhost:0",
    62  			tlsConf,
    63  			serverConf,
    64  		)
    65  		Expect(err).ToNot(HaveOccurred())
    66  		defer ln.Close()
    67  
    68  		proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
    69  			RemoteAddr:  fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port),
    70  			DelayPacket: func(_ quicproxy.Direction, data []byte) time.Duration { return rtt / 2 },
    71  		})
    72  		Expect(err).ToNot(HaveOccurred())
    73  		defer proxy.Close()
    74  
    75  		// dial the first connection in order to receive a session ticket
    76  		done := make(chan struct{})
    77  		go func() {
    78  			defer GinkgoRecover()
    79  			defer close(done)
    80  			conn, err := ln.Accept(context.Background())
    81  			Expect(err).ToNot(HaveOccurred())
    82  			<-conn.Context().Done()
    83  		}()
    84  
    85  		clientConf := getTLSClientConfig()
    86  		gets := make(chan string, 100)
    87  		puts := make(chan string, 100)
    88  		clientConf.ClientSessionCache = newClientSessionCache(tls.NewLRUClientSessionCache(100), gets, puts)
    89  		conn, err := quic.DialAddr(
    90  			context.Background(),
    91  			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
    92  			clientConf,
    93  			getQuicConfig(nil),
    94  		)
    95  		Expect(err).ToNot(HaveOccurred())
    96  		Eventually(puts).Should(Receive())
    97  		// received the session ticket. We're done here.
    98  		Expect(conn.CloseWithError(0, "")).To(Succeed())
    99  		Eventually(done).Should(BeClosed())
   100  		return tlsConf, clientConf
   101  	}
   102  
   103  	transfer0RTTData := func(
   104  		ln *quic.EarlyListener,
   105  		proxyPort int,
   106  		connIDLen int,
   107  		clientTLSConf *tls.Config,
   108  		clientConf *quic.Config,
   109  		testdata []byte, // data to transfer
   110  	) {
   111  		// accept the second connection, and receive the data sent in 0-RTT
   112  		done := make(chan struct{})
   113  		go func() {
   114  			defer GinkgoRecover()
   115  			conn, err := ln.Accept(context.Background())
   116  			Expect(err).ToNot(HaveOccurred())
   117  			str, err := conn.AcceptStream(context.Background())
   118  			Expect(err).ToNot(HaveOccurred())
   119  			data, err := io.ReadAll(str)
   120  			Expect(err).ToNot(HaveOccurred())
   121  			Expect(data).To(Equal(testdata))
   122  			Expect(str.Close()).To(Succeed())
   123  			Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
   124  			<-conn.Context().Done()
   125  			close(done)
   126  		}()
   127  
   128  		if clientConf == nil {
   129  			clientConf = getQuicConfig(nil)
   130  		}
   131  		var conn quic.EarlyConnection
   132  		if connIDLen == 0 {
   133  			var err error
   134  			conn, err = quic.DialAddrEarly(
   135  				context.Background(),
   136  				fmt.Sprintf("localhost:%d", proxyPort),
   137  				clientTLSConf,
   138  				clientConf,
   139  			)
   140  			Expect(err).ToNot(HaveOccurred())
   141  		} else {
   142  			addr, err := net.ResolveUDPAddr("udp", "localhost:0")
   143  			Expect(err).ToNot(HaveOccurred())
   144  			udpConn, err := net.ListenUDP("udp", addr)
   145  			Expect(err).ToNot(HaveOccurred())
   146  			defer udpConn.Close()
   147  			tr := &quic.Transport{
   148  				Conn:               udpConn,
   149  				ConnectionIDLength: connIDLen,
   150  			}
   151  			defer tr.Close()
   152  			conn, err = tr.DialEarly(
   153  				context.Background(),
   154  				&net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: proxyPort},
   155  				clientTLSConf,
   156  				clientConf,
   157  			)
   158  			Expect(err).ToNot(HaveOccurred())
   159  		}
   160  		defer conn.CloseWithError(0, "")
   161  		str, err := conn.OpenStream()
   162  		Expect(err).ToNot(HaveOccurred())
   163  		_, err = str.Write(testdata)
   164  		Expect(err).ToNot(HaveOccurred())
   165  		Expect(str.Close()).To(Succeed())
   166  		<-conn.HandshakeComplete()
   167  		Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
   168  		io.ReadAll(str) // wait for the EOF from the server to arrive before closing the conn
   169  		conn.CloseWithError(0, "")
   170  		Eventually(done).Should(BeClosed())
   171  		Eventually(conn.Context().Done()).Should(BeClosed())
   172  	}
   173  
   174  	check0RTTRejected := func(
   175  		ln *quic.EarlyListener,
   176  		proxyPort int,
   177  		clientConf *tls.Config,
   178  	) {
   179  		conn, err := quic.DialAddrEarly(
   180  			context.Background(),
   181  			fmt.Sprintf("localhost:%d", proxyPort),
   182  			clientConf,
   183  			getQuicConfig(nil),
   184  		)
   185  		Expect(err).ToNot(HaveOccurred())
   186  		str, err := conn.OpenUniStream()
   187  		Expect(err).ToNot(HaveOccurred())
   188  		_, err = str.Write(make([]byte, 3000))
   189  		Expect(err).ToNot(HaveOccurred())
   190  		Expect(str.Close()).To(Succeed())
   191  		Expect(conn.ConnectionState().Used0RTT).To(BeFalse())
   192  
   193  		// make sure the server doesn't process the data
   194  		ctx, cancel := context.WithTimeout(context.Background(), scaleDuration(50*time.Millisecond))
   195  		defer cancel()
   196  		serverConn, err := ln.Accept(ctx)
   197  		Expect(err).ToNot(HaveOccurred())
   198  		Expect(serverConn.ConnectionState().Used0RTT).To(BeFalse())
   199  		_, err = serverConn.AcceptUniStream(ctx)
   200  		Expect(err).To(Equal(context.DeadlineExceeded))
   201  		Expect(serverConn.CloseWithError(0, "")).To(Succeed())
   202  		Eventually(conn.Context().Done()).Should(BeClosed())
   203  	}
   204  
   205  	// can be used to extract 0-RTT from a packetCounter
   206  	get0RTTPackets := func(packets []packet) []protocol.PacketNumber {
   207  		var zeroRTTPackets []protocol.PacketNumber
   208  		for _, p := range packets {
   209  			if p.hdr.Type == protocol.PacketType0RTT {
   210  				zeroRTTPackets = append(zeroRTTPackets, p.hdr.PacketNumber)
   211  			}
   212  		}
   213  		return zeroRTTPackets
   214  	}
   215  
   216  	for _, l := range []int{0, 15} {
   217  		connIDLen := l
   218  
   219  		It(fmt.Sprintf("transfers 0-RTT data, with %d byte connection IDs", connIDLen), func() {
   220  			tlsConf, clientTLSConf := dialAndReceiveSessionTicket(nil)
   221  
   222  			counter, tracer := newPacketTracer()
   223  			ln, err := quic.ListenAddrEarly(
   224  				"localhost:0",
   225  				tlsConf,
   226  				getQuicConfig(&quic.Config{
   227  					Allow0RTT: true,
   228  					Tracer:    newTracer(tracer),
   229  				}),
   230  			)
   231  			Expect(err).ToNot(HaveOccurred())
   232  			defer ln.Close()
   233  
   234  			proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   235  			defer proxy.Close()
   236  
   237  			transfer0RTTData(
   238  				ln,
   239  				proxy.LocalPort(),
   240  				connIDLen,
   241  				clientTLSConf,
   242  				getQuicConfig(nil),
   243  				PRData,
   244  			)
   245  
   246  			var numNewConnIDs int
   247  			for _, p := range counter.getRcvdLongHeaderPackets() {
   248  				for _, f := range p.frames {
   249  					if _, ok := f.(*logging.NewConnectionIDFrame); ok {
   250  						numNewConnIDs++
   251  					}
   252  				}
   253  			}
   254  			if connIDLen == 0 {
   255  				Expect(numNewConnIDs).To(BeZero())
   256  			} else {
   257  				Expect(numNewConnIDs).ToNot(BeZero())
   258  			}
   259  
   260  			num0RTT := num0RTTPackets.Load()
   261  			fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
   262  			Expect(num0RTT).ToNot(BeZero())
   263  			zeroRTTPackets := get0RTTPackets(counter.getRcvdLongHeaderPackets())
   264  			Expect(len(zeroRTTPackets)).To(BeNumerically(">", 10))
   265  			Expect(zeroRTTPackets).To(ContainElement(protocol.PacketNumber(0)))
   266  		})
   267  	}
   268  
   269  	// Test that data intended to be sent with 1-RTT protection is not sent in 0-RTT packets.
   270  	It("waits for a connection until the handshake is done", func() {
   271  		tlsConf, clientConf := dialAndReceiveSessionTicket(nil)
   272  
   273  		zeroRTTData := GeneratePRData(5 << 10)
   274  		oneRTTData := PRData
   275  
   276  		counter, tracer := newPacketTracer()
   277  		ln, err := quic.ListenAddrEarly(
   278  			"localhost:0",
   279  			tlsConf,
   280  			getQuicConfig(&quic.Config{
   281  				Allow0RTT: true,
   282  				Tracer:    newTracer(tracer),
   283  			}),
   284  		)
   285  		Expect(err).ToNot(HaveOccurred())
   286  		defer ln.Close()
   287  
   288  		// now accept the second connection, and receive the 0-RTT data
   289  		go func() {
   290  			defer GinkgoRecover()
   291  			conn, err := ln.Accept(context.Background())
   292  			Expect(err).ToNot(HaveOccurred())
   293  			str, err := conn.AcceptUniStream(context.Background())
   294  			Expect(err).ToNot(HaveOccurred())
   295  			data, err := io.ReadAll(str)
   296  			Expect(err).ToNot(HaveOccurred())
   297  			Expect(data).To(Equal(zeroRTTData))
   298  			str, err = conn.AcceptUniStream(context.Background())
   299  			Expect(err).ToNot(HaveOccurred())
   300  			data, err = io.ReadAll(str)
   301  			Expect(err).ToNot(HaveOccurred())
   302  			Expect(data).To(Equal(oneRTTData))
   303  			Expect(conn.CloseWithError(0, "")).To(Succeed())
   304  		}()
   305  
   306  		proxy, _ := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   307  		defer proxy.Close()
   308  
   309  		conn, err := quic.DialAddrEarly(
   310  			context.Background(),
   311  			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
   312  			clientConf,
   313  			getQuicConfig(nil),
   314  		)
   315  		Expect(err).ToNot(HaveOccurred())
   316  		firstStr, err := conn.OpenUniStream()
   317  		Expect(err).ToNot(HaveOccurred())
   318  		_, err = firstStr.Write(zeroRTTData)
   319  		Expect(err).ToNot(HaveOccurred())
   320  		Expect(firstStr.Close()).To(Succeed())
   321  
   322  		// wait for the handshake to complete
   323  		Eventually(conn.HandshakeComplete()).Should(BeClosed())
   324  		str, err := conn.OpenUniStream()
   325  		Expect(err).ToNot(HaveOccurred())
   326  		_, err = str.Write(PRData)
   327  		Expect(err).ToNot(HaveOccurred())
   328  		Expect(str.Close()).To(Succeed())
   329  		<-conn.Context().Done()
   330  
   331  		// check that 0-RTT packets only contain STREAM frames for the first stream
   332  		var num0RTT int
   333  		for _, p := range counter.getRcvdLongHeaderPackets() {
   334  			if p.hdr.Header.Type != protocol.PacketType0RTT {
   335  				continue
   336  			}
   337  			for _, f := range p.frames {
   338  				sf, ok := f.(*logging.StreamFrame)
   339  				if !ok {
   340  					continue
   341  				}
   342  				num0RTT++
   343  				Expect(sf.StreamID).To(Equal(firstStr.StreamID()))
   344  			}
   345  		}
   346  		fmt.Fprintf(GinkgoWriter, "received %d STREAM frames in 0-RTT packets\n", num0RTT)
   347  		Expect(num0RTT).ToNot(BeZero())
   348  	})
   349  
   350  	It("transfers 0-RTT data, when 0-RTT packets are lost", func() {
   351  		var num0RTTPackets, num0RTTDropped atomic.Uint32
   352  
   353  		tlsConf, clientConf := dialAndReceiveSessionTicket(nil)
   354  
   355  		counter, tracer := newPacketTracer()
   356  		ln, err := quic.ListenAddrEarly(
   357  			"localhost:0",
   358  			tlsConf,
   359  			getQuicConfig(&quic.Config{
   360  				Allow0RTT: true,
   361  				Tracer:    newTracer(tracer),
   362  			}),
   363  		)
   364  		Expect(err).ToNot(HaveOccurred())
   365  		defer ln.Close()
   366  
   367  		proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
   368  			RemoteAddr: fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port),
   369  			DelayPacket: func(_ quicproxy.Direction, data []byte) time.Duration {
   370  				if wire.IsLongHeaderPacket(data[0]) {
   371  					hdr, _, _, err := wire.ParsePacket(data)
   372  					Expect(err).ToNot(HaveOccurred())
   373  					if hdr.Type == protocol.PacketType0RTT {
   374  						num0RTTPackets.Add(1)
   375  					}
   376  				}
   377  				return rtt / 2
   378  			},
   379  			DropPacket: func(_ quicproxy.Direction, data []byte) bool {
   380  				if !wire.IsLongHeaderPacket(data[0]) {
   381  					return false
   382  				}
   383  				hdr, _, _, err := wire.ParsePacket(data)
   384  				Expect(err).ToNot(HaveOccurred())
   385  				if hdr.Type == protocol.PacketType0RTT {
   386  					// drop 25% of the 0-RTT packets
   387  					drop := mrand.Intn(4) == 0
   388  					if drop {
   389  						num0RTTDropped.Add(1)
   390  					}
   391  					return drop
   392  				}
   393  				return false
   394  			},
   395  		})
   396  		Expect(err).ToNot(HaveOccurred())
   397  		defer proxy.Close()
   398  
   399  		transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, PRData)
   400  
   401  		num0RTT := num0RTTPackets.Load()
   402  		numDropped := num0RTTDropped.Load()
   403  		fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets. Dropped %d of those.", num0RTT, numDropped)
   404  		Expect(numDropped).ToNot(BeZero())
   405  		Expect(num0RTT).ToNot(BeZero())
   406  		Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).ToNot(BeEmpty())
   407  	})
   408  
   409  	It("retransmits all 0-RTT data when the server performs a Retry", func() {
   410  		var mutex sync.Mutex
   411  		var firstConnID, secondConnID *protocol.ConnectionID
   412  		var firstCounter, secondCounter protocol.ByteCount
   413  
   414  		tlsConf, clientConf := dialAndReceiveSessionTicket(nil)
   415  
   416  		countZeroRTTBytes := func(data []byte) (n protocol.ByteCount) {
   417  			for len(data) > 0 {
   418  				hdr, _, rest, err := wire.ParsePacket(data)
   419  				if err != nil {
   420  					return
   421  				}
   422  				data = rest
   423  				if hdr.Type == protocol.PacketType0RTT {
   424  					n += hdr.Length - 16 /* AEAD tag */
   425  				}
   426  			}
   427  			return
   428  		}
   429  
   430  		counter, tracer := newPacketTracer()
   431  		ln, err := quic.ListenAddrEarly(
   432  			"localhost:0",
   433  			tlsConf,
   434  			getQuicConfig(&quic.Config{
   435  				RequireAddressValidation: func(net.Addr) bool { return true },
   436  				Allow0RTT:                true,
   437  				Tracer:                   newTracer(tracer),
   438  			}),
   439  		)
   440  		Expect(err).ToNot(HaveOccurred())
   441  		defer ln.Close()
   442  
   443  		proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
   444  			RemoteAddr: fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port),
   445  			DelayPacket: func(dir quicproxy.Direction, data []byte) time.Duration {
   446  				connID, err := wire.ParseConnectionID(data, 0)
   447  				Expect(err).ToNot(HaveOccurred())
   448  
   449  				mutex.Lock()
   450  				defer mutex.Unlock()
   451  
   452  				if zeroRTTBytes := countZeroRTTBytes(data); zeroRTTBytes > 0 {
   453  					if firstConnID == nil {
   454  						firstConnID = &connID
   455  						firstCounter += zeroRTTBytes
   456  					} else if firstConnID != nil && *firstConnID == connID {
   457  						Expect(secondConnID).To(BeNil())
   458  						firstCounter += zeroRTTBytes
   459  					} else if secondConnID == nil {
   460  						secondConnID = &connID
   461  						secondCounter += zeroRTTBytes
   462  					} else if secondConnID != nil && *secondConnID == connID {
   463  						secondCounter += zeroRTTBytes
   464  					} else {
   465  						Fail("received 3 connection IDs on 0-RTT packets")
   466  					}
   467  				}
   468  				return rtt / 2
   469  			},
   470  		})
   471  		Expect(err).ToNot(HaveOccurred())
   472  		defer proxy.Close()
   473  
   474  		transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, GeneratePRData(5000)) // ~5 packets
   475  
   476  		mutex.Lock()
   477  		defer mutex.Unlock()
   478  		Expect(firstCounter).To(BeNumerically("~", 5000+100 /* framing overhead */, 100)) // the FIN bit might be sent extra
   479  		Expect(secondCounter).To(BeNumerically("~", firstCounter, 20))
   480  		zeroRTTPackets := get0RTTPackets(counter.getRcvdLongHeaderPackets())
   481  		Expect(len(zeroRTTPackets)).To(BeNumerically(">=", 5))
   482  		Expect(zeroRTTPackets[0]).To(BeNumerically(">=", protocol.PacketNumber(5)))
   483  	})
   484  
   485  	It("doesn't use 0-RTT when Dial is used for the resumed connection", func() {
   486  		tlsConf, clientConf := dialAndReceiveSessionTicket(nil)
   487  
   488  		ln, err := quic.ListenAddrEarly(
   489  			"localhost:0",
   490  			tlsConf,
   491  			getQuicConfig(&quic.Config{Allow0RTT: true}),
   492  		)
   493  		Expect(err).ToNot(HaveOccurred())
   494  		defer ln.Close()
   495  		proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   496  		defer proxy.Close()
   497  
   498  		conn, err := quic.DialAddr(
   499  			context.Background(),
   500  			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
   501  			clientConf,
   502  			getQuicConfig(nil),
   503  		)
   504  		Expect(err).ToNot(HaveOccurred())
   505  		defer conn.CloseWithError(0, "")
   506  		Expect(conn.ConnectionState().TLS.DidResume).To(BeTrue())
   507  		Expect(conn.ConnectionState().Used0RTT).To(BeFalse())
   508  		Expect(num0RTTPackets.Load()).To(BeZero())
   509  
   510  		serverConn, err := ln.Accept(context.Background())
   511  		Expect(err).ToNot(HaveOccurred())
   512  		Expect(serverConn.ConnectionState().TLS.DidResume).To(BeTrue())
   513  		Expect(serverConn.ConnectionState().Used0RTT).To(BeFalse())
   514  	})
   515  
   516  	It("doesn't reject 0-RTT when the server's transport stream limit increased", func() {
   517  		const maxStreams = 1
   518  		tlsConf, clientConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{
   519  			MaxIncomingUniStreams: maxStreams,
   520  		}))
   521  
   522  		ln, err := quic.ListenAddrEarly(
   523  			"localhost:0",
   524  			tlsConf,
   525  			getQuicConfig(&quic.Config{
   526  				MaxIncomingUniStreams: maxStreams + 1,
   527  				Allow0RTT:             true,
   528  			}),
   529  		)
   530  		Expect(err).ToNot(HaveOccurred())
   531  		defer ln.Close()
   532  		proxy, _ := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   533  		defer proxy.Close()
   534  
   535  		conn, err := quic.DialAddrEarly(
   536  			context.Background(),
   537  			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
   538  			clientConf,
   539  			getQuicConfig(nil),
   540  		)
   541  		Expect(err).ToNot(HaveOccurred())
   542  		str, err := conn.OpenUniStream()
   543  		Expect(err).ToNot(HaveOccurred())
   544  		_, err = str.Write([]byte("foobar"))
   545  		Expect(err).ToNot(HaveOccurred())
   546  		Expect(str.Close()).To(Succeed())
   547  		// The client remembers the old limit and refuses to open a new stream.
   548  		_, err = conn.OpenUniStream()
   549  		Expect(err).To(HaveOccurred())
   550  		Expect(err.Error()).To(ContainSubstring("too many open streams"))
   551  		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   552  		defer cancel()
   553  		_, err = conn.OpenUniStreamSync(ctx)
   554  		Expect(err).ToNot(HaveOccurred())
   555  		Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
   556  		Expect(conn.CloseWithError(0, "")).To(Succeed())
   557  	})
   558  
   559  	It("rejects 0-RTT when the server's stream limit decreased", func() {
   560  		const maxStreams = 42
   561  		tlsConf, clientConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{
   562  			MaxIncomingStreams: maxStreams,
   563  		}))
   564  
   565  		counter, tracer := newPacketTracer()
   566  		ln, err := quic.ListenAddrEarly(
   567  			"localhost:0",
   568  			tlsConf,
   569  			getQuicConfig(&quic.Config{
   570  				MaxIncomingStreams: maxStreams - 1,
   571  				Allow0RTT:          true,
   572  				Tracer:             newTracer(tracer),
   573  			}),
   574  		)
   575  		Expect(err).ToNot(HaveOccurred())
   576  		defer ln.Close()
   577  		proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   578  		defer proxy.Close()
   579  		check0RTTRejected(ln, proxy.LocalPort(), clientConf)
   580  
   581  		// The client should send 0-RTT packets, but the server doesn't process them.
   582  		num0RTT := num0RTTPackets.Load()
   583  		fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
   584  		Expect(num0RTT).ToNot(BeZero())
   585  		Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty())
   586  	})
   587  
   588  	It("rejects 0-RTT when the ALPN changed", func() {
   589  		tlsConf, clientConf := dialAndReceiveSessionTicket(nil)
   590  
   591  		// now close the listener and dial new connection with a different ALPN
   592  		clientConf.NextProtos = []string{"new-alpn"}
   593  		tlsConf.NextProtos = []string{"new-alpn"}
   594  		counter, tracer := newPacketTracer()
   595  		ln, err := quic.ListenAddrEarly(
   596  			"localhost:0",
   597  			tlsConf,
   598  			getQuicConfig(&quic.Config{
   599  				Allow0RTT: true,
   600  				Tracer:    newTracer(tracer),
   601  			}),
   602  		)
   603  		Expect(err).ToNot(HaveOccurred())
   604  		defer ln.Close()
   605  		proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   606  		defer proxy.Close()
   607  
   608  		check0RTTRejected(ln, proxy.LocalPort(), clientConf)
   609  
   610  		// The client should send 0-RTT packets, but the server doesn't process them.
   611  		num0RTT := num0RTTPackets.Load()
   612  		fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
   613  		Expect(num0RTT).ToNot(BeZero())
   614  		Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty())
   615  	})
   616  
   617  	It("rejects 0-RTT when the application doesn't allow it", func() {
   618  		tlsConf, clientConf := dialAndReceiveSessionTicket(nil)
   619  
   620  		// now close the listener and dial new connection with a different ALPN
   621  		counter, tracer := newPacketTracer()
   622  		ln, err := quic.ListenAddrEarly(
   623  			"localhost:0",
   624  			tlsConf,
   625  			getQuicConfig(&quic.Config{
   626  				Allow0RTT: false, // application rejects 0-RTT
   627  				Tracer:    newTracer(tracer),
   628  			}),
   629  		)
   630  		Expect(err).ToNot(HaveOccurred())
   631  		defer ln.Close()
   632  		proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   633  		defer proxy.Close()
   634  
   635  		check0RTTRejected(ln, proxy.LocalPort(), clientConf)
   636  
   637  		// The client should send 0-RTT packets, but the server doesn't process them.
   638  		num0RTT := num0RTTPackets.Load()
   639  		fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
   640  		Expect(num0RTT).ToNot(BeZero())
   641  		Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty())
   642  	})
   643  
   644  	It("doesn't use 0-RTT, if the server didn't enable it", func() {
   645  		server, err := quic.ListenAddr("localhost:0", getTLSConfig(), getQuicConfig(nil))
   646  		Expect(err).ToNot(HaveOccurred())
   647  		defer server.Close()
   648  
   649  		gets := make(chan string, 100)
   650  		puts := make(chan string, 100)
   651  		cache := newClientSessionCache(tls.NewLRUClientSessionCache(10), gets, puts)
   652  		tlsConf := getTLSClientConfig()
   653  		tlsConf.ClientSessionCache = cache
   654  		conn1, err := quic.DialAddr(
   655  			context.Background(),
   656  			fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
   657  			tlsConf,
   658  			getQuicConfig(nil),
   659  		)
   660  		Expect(err).ToNot(HaveOccurred())
   661  		defer conn1.CloseWithError(0, "")
   662  		var sessionKey string
   663  		Eventually(puts).Should(Receive(&sessionKey))
   664  		Expect(conn1.ConnectionState().TLS.DidResume).To(BeFalse())
   665  
   666  		serverConn, err := server.Accept(context.Background())
   667  		Expect(err).ToNot(HaveOccurred())
   668  		Expect(serverConn.ConnectionState().TLS.DidResume).To(BeFalse())
   669  
   670  		conn2, err := quic.DialAddrEarly(
   671  			context.Background(),
   672  			fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
   673  			tlsConf,
   674  			getQuicConfig(nil),
   675  		)
   676  		Expect(err).ToNot(HaveOccurred())
   677  		Expect(gets).To(Receive(Equal(sessionKey)))
   678  		Expect(conn2.ConnectionState().TLS.DidResume).To(BeTrue())
   679  
   680  		serverConn, err = server.Accept(context.Background())
   681  		Expect(err).ToNot(HaveOccurred())
   682  		Expect(serverConn.ConnectionState().TLS.DidResume).To(BeTrue())
   683  		Expect(serverConn.ConnectionState().Used0RTT).To(BeFalse())
   684  		conn2.CloseWithError(0, "")
   685  	})
   686  
   687  	DescribeTable("flow control limits",
   688  		func(addFlowControlLimit func(*quic.Config, uint64)) {
   689  			counter, tracer := newPacketTracer()
   690  			firstConf := getQuicConfig(&quic.Config{Allow0RTT: true})
   691  			addFlowControlLimit(firstConf, 3)
   692  			tlsConf, clientConf := dialAndReceiveSessionTicket(firstConf)
   693  
   694  			secondConf := getQuicConfig(&quic.Config{
   695  				Allow0RTT: true,
   696  				Tracer:    newTracer(tracer),
   697  			})
   698  			addFlowControlLimit(secondConf, 100)
   699  			ln, err := quic.ListenAddrEarly(
   700  				"localhost:0",
   701  				tlsConf,
   702  				secondConf,
   703  			)
   704  			Expect(err).ToNot(HaveOccurred())
   705  			defer ln.Close()
   706  			proxy, _ := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   707  			defer proxy.Close()
   708  
   709  			conn, err := quic.DialAddrEarly(
   710  				context.Background(),
   711  				fmt.Sprintf("localhost:%d", proxy.LocalPort()),
   712  				clientConf,
   713  				getQuicConfig(nil),
   714  			)
   715  			Expect(err).ToNot(HaveOccurred())
   716  			str, err := conn.OpenUniStream()
   717  			Expect(err).ToNot(HaveOccurred())
   718  			written := make(chan struct{})
   719  			go func() {
   720  				defer GinkgoRecover()
   721  				defer close(written)
   722  				_, err := str.Write([]byte("foobar"))
   723  				Expect(err).ToNot(HaveOccurred())
   724  				Expect(str.Close()).To(Succeed())
   725  			}()
   726  
   727  			Eventually(written).Should(BeClosed())
   728  
   729  			serverConn, err := ln.Accept(context.Background())
   730  			Expect(err).ToNot(HaveOccurred())
   731  			rstr, err := serverConn.AcceptUniStream(context.Background())
   732  			Expect(err).ToNot(HaveOccurred())
   733  			data, err := io.ReadAll(rstr)
   734  			Expect(err).ToNot(HaveOccurred())
   735  			Expect(data).To(Equal([]byte("foobar")))
   736  			Expect(serverConn.ConnectionState().Used0RTT).To(BeTrue())
   737  			Expect(serverConn.CloseWithError(0, "")).To(Succeed())
   738  			Eventually(conn.Context().Done()).Should(BeClosed())
   739  
   740  			var processedFirst bool
   741  			for _, p := range counter.getRcvdLongHeaderPackets() {
   742  				for _, f := range p.frames {
   743  					if sf, ok := f.(*logging.StreamFrame); ok {
   744  						if !processedFirst {
   745  							// The first STREAM should have been sent in a 0-RTT packet.
   746  							// Due to the flow control limit, the STREAM frame was limit to the first 3 bytes.
   747  							Expect(p.hdr.Type).To(Equal(protocol.PacketType0RTT))
   748  							Expect(sf.Length).To(BeEquivalentTo(3))
   749  							processedFirst = true
   750  						} else {
   751  							Fail("STREAM was shouldn't have been sent in 0-RTT")
   752  						}
   753  					}
   754  				}
   755  			}
   756  		},
   757  		Entry("doesn't reject 0-RTT when the server's transport stream flow control limit increased", func(c *quic.Config, limit uint64) { c.InitialStreamReceiveWindow = limit }),
   758  		Entry("doesn't reject 0-RTT when the server's transport connection flow control limit increased", func(c *quic.Config, limit uint64) { c.InitialConnectionReceiveWindow = limit }),
   759  	)
   760  
   761  	for _, l := range []int{0, 15} {
   762  		connIDLen := l
   763  
   764  		It(fmt.Sprintf("correctly deals with 0-RTT rejections, for %d byte connection IDs", connIDLen), func() {
   765  			tlsConf, clientConf := dialAndReceiveSessionTicket(nil)
   766  			// now dial new connection with different transport parameters
   767  			counter, tracer := newPacketTracer()
   768  			ln, err := quic.ListenAddrEarly(
   769  				"localhost:0",
   770  				tlsConf,
   771  				getQuicConfig(&quic.Config{
   772  					MaxIncomingUniStreams: 1,
   773  					Tracer:                newTracer(tracer),
   774  				}),
   775  			)
   776  			Expect(err).ToNot(HaveOccurred())
   777  			defer ln.Close()
   778  			proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   779  			defer proxy.Close()
   780  
   781  			conn, err := quic.DialAddrEarly(
   782  				context.Background(),
   783  				fmt.Sprintf("localhost:%d", proxy.LocalPort()),
   784  				clientConf,
   785  				getQuicConfig(nil),
   786  			)
   787  			Expect(err).ToNot(HaveOccurred())
   788  			// The client remembers that it was allowed to open 2 uni-directional streams.
   789  			firstStr, err := conn.OpenUniStream()
   790  			Expect(err).ToNot(HaveOccurred())
   791  			written := make(chan struct{}, 2)
   792  			go func() {
   793  				defer GinkgoRecover()
   794  				defer func() { written <- struct{}{} }()
   795  				_, err := firstStr.Write([]byte("first flight"))
   796  				Expect(err).ToNot(HaveOccurred())
   797  			}()
   798  			secondStr, err := conn.OpenUniStream()
   799  			Expect(err).ToNot(HaveOccurred())
   800  			go func() {
   801  				defer GinkgoRecover()
   802  				defer func() { written <- struct{}{} }()
   803  				_, err := secondStr.Write([]byte("first flight"))
   804  				Expect(err).ToNot(HaveOccurred())
   805  			}()
   806  
   807  			ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   808  			defer cancel()
   809  			_, err = conn.AcceptStream(ctx)
   810  			Expect(err).To(MatchError(quic.Err0RTTRejected))
   811  			Eventually(written).Should(Receive())
   812  			Eventually(written).Should(Receive())
   813  			_, err = firstStr.Write([]byte("foobar"))
   814  			Expect(err).To(MatchError(quic.Err0RTTRejected))
   815  			_, err = conn.OpenUniStream()
   816  			Expect(err).To(MatchError(quic.Err0RTTRejected))
   817  
   818  			_, err = conn.AcceptStream(ctx)
   819  			Expect(err).To(Equal(quic.Err0RTTRejected))
   820  
   821  			newConn := conn.NextConnection()
   822  			str, err := newConn.OpenUniStream()
   823  			Expect(err).ToNot(HaveOccurred())
   824  			_, err = newConn.OpenUniStream()
   825  			Expect(err).To(HaveOccurred())
   826  			Expect(err.Error()).To(ContainSubstring("too many open streams"))
   827  			_, err = str.Write([]byte("second flight"))
   828  			Expect(err).ToNot(HaveOccurred())
   829  			Expect(str.Close()).To(Succeed())
   830  			Expect(conn.CloseWithError(0, "")).To(Succeed())
   831  
   832  			// The client should send 0-RTT packets, but the server doesn't process them.
   833  			num0RTT := num0RTTPackets.Load()
   834  			fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
   835  			Expect(num0RTT).ToNot(BeZero())
   836  			Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty())
   837  		})
   838  	}
   839  
   840  	It("queues 0-RTT packets, if the Initial is delayed", func() {
   841  		tlsConf, clientConf := dialAndReceiveSessionTicket(nil)
   842  
   843  		counter, tracer := newPacketTracer()
   844  		ln, err := quic.ListenAddrEarly(
   845  			"localhost:0",
   846  			tlsConf,
   847  			getQuicConfig(&quic.Config{
   848  				Allow0RTT: true,
   849  				Tracer:    newTracer(tracer),
   850  			}),
   851  		)
   852  		Expect(err).ToNot(HaveOccurred())
   853  		defer ln.Close()
   854  		proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
   855  			RemoteAddr: ln.Addr().String(),
   856  			DelayPacket: func(dir quicproxy.Direction, data []byte) time.Duration {
   857  				if dir == quicproxy.DirectionIncoming && wire.IsLongHeaderPacket(data[0]) && data[0]&0x30>>4 == 0 { // Initial packet from client
   858  					return rtt/2 + rtt
   859  				}
   860  				return rtt / 2
   861  			},
   862  		})
   863  		Expect(err).ToNot(HaveOccurred())
   864  		defer proxy.Close()
   865  
   866  		transfer0RTTData(ln, proxy.LocalPort(), protocol.DefaultConnectionIDLength, clientConf, nil, PRData)
   867  
   868  		Expect(counter.getRcvdLongHeaderPackets()[0].hdr.Type).To(Equal(protocol.PacketTypeInitial))
   869  		zeroRTTPackets := get0RTTPackets(counter.getRcvdLongHeaderPackets())
   870  		Expect(len(zeroRTTPackets)).To(BeNumerically(">", 10))
   871  		Expect(zeroRTTPackets[0]).To(Equal(protocol.PacketNumber(0)))
   872  	})
   873  
   874  	It("sends 0-RTT datagrams", func() {
   875  		tlsConf, clientTLSConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{
   876  			EnableDatagrams: true,
   877  		}))
   878  
   879  		counter, tracer := newPacketTracer()
   880  		ln, err := quic.ListenAddrEarly(
   881  			"localhost:0",
   882  			tlsConf,
   883  			getQuicConfig(&quic.Config{
   884  				Allow0RTT:       true,
   885  				EnableDatagrams: true,
   886  				Tracer:          newTracer(tracer),
   887  			}),
   888  		)
   889  		Expect(err).ToNot(HaveOccurred())
   890  		defer ln.Close()
   891  
   892  		proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   893  		defer proxy.Close()
   894  
   895  		// second connection
   896  		sentMessage := GeneratePRData(100)
   897  		var receivedMessage []byte
   898  		received := make(chan struct{})
   899  		go func() {
   900  			defer GinkgoRecover()
   901  			defer close(received)
   902  			conn, err := ln.Accept(context.Background())
   903  			Expect(err).ToNot(HaveOccurred())
   904  			receivedMessage, err = conn.ReceiveDatagram(context.Background())
   905  			Expect(err).ToNot(HaveOccurred())
   906  			Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
   907  		}()
   908  		conn, err := quic.DialAddrEarly(
   909  			context.Background(),
   910  			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
   911  			clientTLSConf,
   912  			getQuicConfig(&quic.Config{
   913  				EnableDatagrams: true,
   914  			}),
   915  		)
   916  		Expect(err).ToNot(HaveOccurred())
   917  		Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue())
   918  		Expect(conn.SendDatagram(sentMessage)).To(Succeed())
   919  		<-conn.HandshakeComplete()
   920  		<-received
   921  
   922  		Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
   923  		Expect(receivedMessage).To(Equal(sentMessage))
   924  		Expect(conn.CloseWithError(0, "")).To(Succeed())
   925  		num0RTT := num0RTTPackets.Load()
   926  		fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
   927  		Expect(num0RTT).ToNot(BeZero())
   928  		zeroRTTPackets := get0RTTPackets(counter.getRcvdLongHeaderPackets())
   929  		Expect(zeroRTTPackets).To(HaveLen(1))
   930  	})
   931  
   932  	It("rejects 0-RTT datagrams when the server doesn't support datagrams anymore", func() {
   933  		tlsConf, clientTLSConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{
   934  			EnableDatagrams: true,
   935  		}))
   936  
   937  		counter, tracer := newPacketTracer()
   938  		ln, err := quic.ListenAddrEarly(
   939  			"localhost:0",
   940  			tlsConf,
   941  			getQuicConfig(&quic.Config{
   942  				Allow0RTT:       true,
   943  				EnableDatagrams: false,
   944  				Tracer:          newTracer(tracer),
   945  			}),
   946  		)
   947  		Expect(err).ToNot(HaveOccurred())
   948  		defer ln.Close()
   949  
   950  		proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
   951  		defer proxy.Close()
   952  
   953  		// second connection
   954  		go func() {
   955  			defer GinkgoRecover()
   956  			conn, err := ln.Accept(context.Background())
   957  			Expect(err).ToNot(HaveOccurred())
   958  			_, err = conn.ReceiveDatagram(context.Background())
   959  			Expect(err.Error()).To(Equal("datagram support disabled"))
   960  			<-conn.HandshakeComplete()
   961  			Expect(conn.ConnectionState().Used0RTT).To(BeFalse())
   962  		}()
   963  		conn, err := quic.DialAddrEarly(
   964  			context.Background(),
   965  			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
   966  			clientTLSConf,
   967  			getQuicConfig(&quic.Config{
   968  				EnableDatagrams: true,
   969  			}),
   970  		)
   971  		Expect(err).ToNot(HaveOccurred())
   972  		// the client can temporarily send datagrams but the server doesn't process them.
   973  		Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue())
   974  		Expect(conn.SendDatagram(make([]byte, 100))).To(Succeed())
   975  		<-conn.HandshakeComplete()
   976  
   977  		Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse())
   978  		Expect(conn.ConnectionState().Used0RTT).To(BeFalse())
   979  		Expect(conn.CloseWithError(0, "")).To(Succeed())
   980  		num0RTT := num0RTTPackets.Load()
   981  		fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
   982  		Expect(num0RTT).ToNot(BeZero())
   983  		Expect(get0RTTPackets(counter.getRcvdLongHeaderPackets())).To(BeEmpty())
   984  	})
   985  })