github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/integrationtests/self/zero_rtt_test.go (about)

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