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