implement the Transport

This commit is contained in:
Marten Seemann 2023-04-06 18:02:51 +08:00
parent ae5a8bd35c
commit 8189e75be6
31 changed files with 1309 additions and 1250 deletions

View file

@ -660,6 +660,7 @@ var _ = Describe("Stream Cancellations", func() {
getQuicConfig(&quic.Config{MaxIncomingStreams: maxIncomingStreams, MaxIdleTimeout: 10 * time.Second}),
)
Expect(err).ToNot(HaveOccurred())
defer server.Close()
var wg sync.WaitGroup
wg.Add(2 * 4 * maxIncomingStreams)

View file

@ -24,6 +24,7 @@ var _ = Describe("Connection ID lengths tests", func() {
}),
)
Expect(err).ToNot(HaveOccurred())
defer server.Close()
var drop atomic.Bool
dropped := make(chan []byte, 100)
@ -50,6 +51,7 @@ var _ = Describe("Connection ID lengths tests", func() {
getQuicConfig(nil),
)
Expect(err).ToNot(HaveOccurred())
defer conn.CloseWithError(0, "")
sconn, err := server.Accept(context.Background())
Expect(err).ToNot(HaveOccurred())

View file

@ -35,7 +35,11 @@ var _ = Describe("Connection ID lengths tests", func() {
randomConnIDLen := func() int { return 4 + int(mrand.Int31n(15)) }
runServer := func(conf *quic.Config) *quic.Listener {
GinkgoWriter.Write([]byte(fmt.Sprintf("Using %d byte connection ID for the server\n", conf.ConnectionIDLength)))
if conf.ConnectionIDGenerator != nil {
GinkgoWriter.Write([]byte(fmt.Sprintf("Using %d byte connection ID generator for the server\n", conf.ConnectionIDGenerator.ConnectionIDLen())))
} else {
GinkgoWriter.Write([]byte(fmt.Sprintf("Using %d byte connection ID for the server\n", conf.ConnectionIDLength)))
}
ln, err := quic.ListenAddr("localhost:0", getTLSConfig(), conf)
Expect(err).ToNot(HaveOccurred())
go func() {
@ -59,7 +63,11 @@ var _ = Describe("Connection ID lengths tests", func() {
}
runClient := func(addr net.Addr, conf *quic.Config) {
GinkgoWriter.Write([]byte(fmt.Sprintf("Using %d byte connection ID for the client\n", conf.ConnectionIDLength)))
if conf.ConnectionIDGenerator != nil {
GinkgoWriter.Write([]byte(fmt.Sprintf("Using %d byte connection ID generator for the client\n", conf.ConnectionIDGenerator.ConnectionIDLen())))
} else {
GinkgoWriter.Write([]byte(fmt.Sprintf("Using %d byte connection ID for the client\n", conf.ConnectionIDLength)))
}
cl, err := quic.DialAddr(
context.Background(),
fmt.Sprintf("localhost:%d", addr.(*net.UDPAddr).Port),

View file

@ -22,12 +22,11 @@ var _ = Describe("Datagram test", func() {
const num = 100
var (
proxy *quicproxy.QuicProxy
serverConn, clientConn *net.UDPConn
dropped, total int32
)
startServerAndProxy := func(enableDatagram, expectDatagramSupport bool) {
startServerAndProxy := func(enableDatagram, expectDatagramSupport bool) (port int, closeFn func()) {
addr, err := net.ResolveUDPAddr("udp", "localhost:0")
Expect(err).ToNot(HaveOccurred())
serverConn, err = net.ListenUDP("udp", addr)
@ -39,8 +38,10 @@ var _ = Describe("Datagram test", func() {
)
Expect(err).ToNot(HaveOccurred())
accepted := make(chan struct{})
go func() {
defer GinkgoRecover()
defer close(accepted)
conn, err := ln.Accept(context.Background())
Expect(err).ToNot(HaveOccurred())
@ -67,7 +68,7 @@ var _ = Describe("Datagram test", func() {
}()
serverPort := ln.Addr().(*net.UDPAddr).Port
proxy, err = quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
RemoteAddr: fmt.Sprintf("localhost:%d", serverPort),
// drop 10% of Short Header packets sent from the server
DropPacket: func(dir quicproxy.Direction, packet []byte) bool {
@ -87,6 +88,11 @@ var _ = Describe("Datagram test", func() {
},
})
Expect(err).ToNot(HaveOccurred())
return proxy.LocalPort(), func() {
Eventually(accepted).Should(BeClosed())
proxy.Close()
ln.Close()
}
}
BeforeEach(func() {
@ -96,13 +102,10 @@ var _ = Describe("Datagram test", func() {
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
Expect(proxy.Close()).To(Succeed())
})
It("sends datagrams", func() {
startServerAndProxy(true, true)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
proxyPort, close := startServerAndProxy(true, true)
defer close()
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxyPort))
Expect(err).ToNot(HaveOccurred())
conn, err := quic.Dial(
context.Background(),
@ -117,6 +120,7 @@ var _ = Describe("Datagram test", func() {
for {
// Close the connection if no message is received for 100 ms.
timer := time.AfterFunc(scaleDuration(100*time.Millisecond), func() {
fmt.Println("closing conn")
conn.CloseWithError(0, "")
})
if _, err := conn.ReceiveMessage(); err != nil {
@ -134,11 +138,12 @@ var _ = Describe("Datagram test", func() {
BeNumerically(">", expVal*9/10),
BeNumerically("<", num),
))
Eventually(conn.Context().Done).Should(BeClosed())
})
It("server can disable datagram", func() {
startServerAndProxy(false, true)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
proxyPort, close := startServerAndProxy(false, true)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxyPort))
Expect(err).ToNot(HaveOccurred())
conn, err := quic.Dial(
context.Background(),
@ -150,13 +155,13 @@ var _ = Describe("Datagram test", func() {
Expect(err).ToNot(HaveOccurred())
Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse())
close()
conn.CloseWithError(0, "")
<-time.After(10 * time.Millisecond)
})
It("client can disable datagram", func() {
startServerAndProxy(false, true)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
proxyPort, close := startServerAndProxy(false, true)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxyPort))
Expect(err).ToNot(HaveOccurred())
conn, err := quic.Dial(
context.Background(),
@ -169,7 +174,8 @@ var _ = Describe("Datagram test", func() {
Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse())
Expect(conn.SendMessage([]byte{0})).To(HaveOccurred())
close()
conn.CloseWithError(0, "")
<-time.After(10 * time.Millisecond)
})
})

View file

@ -24,6 +24,7 @@ var _ = Describe("early data", func() {
getQuicConfig(nil),
)
Expect(err).ToNot(HaveOccurred())
defer ln.Close()
done := make(chan struct{})
go func() {
defer GinkgoRecover()

View file

@ -8,10 +8,9 @@ import (
"time"
)
var (
go120 = false
errNotSupported = errors.New("not supported")
)
const go120 = false
var errNotSupported = errors.New("not supported")
func setReadDeadline(w http.ResponseWriter, deadline time.Time) error {
return errNotSupported

View file

@ -7,7 +7,7 @@ import (
"time"
)
var go120 = true
const go120 = true
func setReadDeadline(w http.ResponseWriter, deadline time.Time) error {
rc := http.NewResponseController(w)

View file

@ -62,13 +62,14 @@ var _ = Describe("Handshake RTT tests", func() {
runProxy(ln.Addr())
startTime := time.Now()
_, err = quic.DialAddr(
conn, err := quic.DialAddr(
context.Background(),
fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
getTLSClientConfig(),
getQuicConfig(nil),
)
Expect(err).ToNot(HaveOccurred())
defer conn.CloseWithError(0, "")
expectDurationInRTTs(startTime, 2)
})
@ -79,13 +80,14 @@ var _ = Describe("Handshake RTT tests", func() {
runProxy(ln.Addr())
startTime := time.Now()
_, err = quic.DialAddr(
conn, err := quic.DialAddr(
context.Background(),
fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
getTLSClientConfig(),
getQuicConfig(nil),
)
Expect(err).ToNot(HaveOccurred())
defer conn.CloseWithError(0, "")
expectDurationInRTTs(startTime, 1)
})
@ -97,13 +99,14 @@ var _ = Describe("Handshake RTT tests", func() {
runProxy(ln.Addr())
startTime := time.Now()
_, err = quic.DialAddr(
conn, err := quic.DialAddr(
context.Background(),
fmt.Sprintf("localhost:%d", proxy.LocalAddr().(*net.UDPAddr).Port),
getTLSClientConfig(),
getQuicConfig(nil),
)
Expect(err).ToNot(HaveOccurred())
defer conn.CloseWithError(0, "")
expectDurationInRTTs(startTime, 2)
})
@ -131,6 +134,7 @@ var _ = Describe("Handshake RTT tests", func() {
getQuicConfig(nil),
)
Expect(err).ToNot(HaveOccurred())
defer conn.CloseWithError(0, "")
str, err := conn.AcceptUniStream(context.Background())
Expect(err).ToNot(HaveOccurred())
data, err := io.ReadAll(str)
@ -166,6 +170,7 @@ var _ = Describe("Handshake RTT tests", func() {
getQuicConfig(nil),
)
Expect(err).ToNot(HaveOccurred())
defer conn.CloseWithError(0, "")
str, err := conn.AcceptUniStream(context.Background())
Expect(err).ToNot(HaveOccurred())
data, err := io.ReadAll(str)

View file

@ -114,7 +114,7 @@ var _ = Describe("Handshake tests", func() {
context.Background(),
fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port),
getTLSClientConfig(),
nil,
getQuicConfig(nil),
)
Expect(err).ToNot(HaveOccurred())
str, err := conn.AcceptStream(context.Background())
@ -223,13 +223,14 @@ var _ = Describe("Handshake tests", func() {
var (
server *quic.Listener
pconn net.PacketConn
dialer *quic.Transport
)
dial := func() (quic.Connection, error) {
remoteAddr := fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port)
raddr, err := net.ResolveUDPAddr("udp", remoteAddr)
Expect(err).ToNot(HaveOccurred())
return quic.Dial(context.Background(), pconn, raddr, getTLSClientConfig(), nil)
return dialer.Dial(context.Background(), raddr, getTLSClientConfig(), getQuicConfig(nil))
}
BeforeEach(func() {
@ -243,11 +244,13 @@ var _ = Describe("Handshake tests", func() {
Expect(err).ToNot(HaveOccurred())
pconn, err = net.ListenUDP("udp", laddr)
Expect(err).ToNot(HaveOccurred())
dialer = &quic.Transport{Conn: pconn}
})
AfterEach(func() {
Expect(server.Close()).To(Succeed())
Expect(pconn.Close()).To(Succeed())
Expect(dialer.Close()).To(Succeed())
})
It("rejects new connection attempts if connections don't get accepted", func() {
@ -366,6 +369,7 @@ var _ = Describe("Handshake tests", func() {
It("uses tokens provided in NEW_TOKEN frames", func() {
server, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig)
Expect(err).ToNot(HaveOccurred())
defer server.Close()
// dial the first connection and receive the token
go func() {

View file

@ -382,6 +382,7 @@ var _ = Describe("HTTP tests", func() {
tlsConf.NextProtos = []string{"h3"}
ln, err := quic.ListenAddr("localhost:0", tlsConf, nil)
Expect(err).ToNot(HaveOccurred())
defer ln.Close()
done := make(chan struct{})
go func() {
defer GinkgoRecover()
@ -398,57 +399,51 @@ var _ = Describe("HTTP tests", func() {
Eventually(done).Should(BeClosed())
})
It("supports read deadlines", func() {
if !go120 {
Skip("This test requires Go 1.20+")
}
if go120 {
It("supports read deadlines", func() {
mux.HandleFunc("/read-deadline", func(w http.ResponseWriter, r *http.Request) {
defer GinkgoRecover()
err := setReadDeadline(w, time.Now().Add(deadlineDelay))
Expect(err).ToNot(HaveOccurred())
mux.HandleFunc("/read-deadline", func(w http.ResponseWriter, r *http.Request) {
defer GinkgoRecover()
err := setReadDeadline(w, time.Now().Add(deadlineDelay))
body, err := io.ReadAll(r.Body)
Expect(err).To(MatchError(os.ErrDeadlineExceeded))
Expect(body).To(ContainSubstring("aa"))
w.Write([]byte("ok"))
})
expectedEnd := time.Now().Add(deadlineDelay)
resp, err := client.Post("https://localhost:"+port+"/read-deadline", "text/plain", neverEnding('a'))
Expect(err).ToNot(HaveOccurred())
Expect(resp.StatusCode).To(Equal(200))
body, err := io.ReadAll(r.Body)
Expect(err).To(MatchError(os.ErrDeadlineExceeded))
Expect(body).To(ContainSubstring("aa"))
w.Write([]byte("ok"))
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 2*deadlineDelay))
Expect(err).ToNot(HaveOccurred())
Expect(time.Now().After(expectedEnd)).To(BeTrue())
Expect(string(body)).To(Equal("ok"))
})
expectedEnd := time.Now().Add(deadlineDelay)
resp, err := client.Post("https://localhost:"+port+"/read-deadline", "text/plain", neverEnding('a'))
Expect(err).ToNot(HaveOccurred())
Expect(resp.StatusCode).To(Equal(200))
It("supports write deadlines", func() {
mux.HandleFunc("/write-deadline", func(w http.ResponseWriter, r *http.Request) {
defer GinkgoRecover()
err := setWriteDeadline(w, time.Now().Add(deadlineDelay))
Expect(err).ToNot(HaveOccurred())
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 2*deadlineDelay))
Expect(err).ToNot(HaveOccurred())
Expect(time.Now().After(expectedEnd)).To(BeTrue())
Expect(string(body)).To(Equal("ok"))
})
_, err = io.Copy(w, neverEnding('a'))
Expect(err).To(MatchError(os.ErrDeadlineExceeded))
})
It("supports write deadlines", func() {
if !go120 {
Skip("This test requires Go 1.20+")
}
expectedEnd := time.Now().Add(deadlineDelay)
mux.HandleFunc("/write-deadline", func(w http.ResponseWriter, r *http.Request) {
defer GinkgoRecover()
err := setWriteDeadline(w, time.Now().Add(deadlineDelay))
resp, err := client.Get("https://localhost:" + port + "/write-deadline")
Expect(err).ToNot(HaveOccurred())
Expect(resp.StatusCode).To(Equal(200))
_, err = io.Copy(w, neverEnding('a'))
Expect(err).To(MatchError(os.ErrDeadlineExceeded))
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 2*deadlineDelay))
Expect(err).ToNot(HaveOccurred())
Expect(time.Now().After(expectedEnd)).To(BeTrue())
Expect(string(body)).To(ContainSubstring("aa"))
})
expectedEnd := time.Now().Add(deadlineDelay)
resp, err := client.Get("https://localhost:" + port + "/write-deadline")
Expect(err).ToNot(HaveOccurred())
Expect(resp.StatusCode).To(Equal(200))
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 2*deadlineDelay))
Expect(err).ToNot(HaveOccurred())
Expect(time.Now().After(expectedEnd)).To(BeTrue())
Expect(string(body)).To(ContainSubstring("aa"))
})
}
})

View file

@ -34,10 +34,9 @@ var _ = Describe("Multiplexing", func() {
}()
}
dial := func(pconn net.PacketConn, addr net.Addr) {
conn, err := quic.Dial(
dial := func(tr *quic.Transport, addr net.Addr) {
conn, err := tr.Dial(
context.Background(),
pconn,
addr,
getTLSClientConfig(),
getQuicConfig(nil),
@ -72,17 +71,18 @@ var _ = Describe("Multiplexing", func() {
conn, err := net.ListenUDP("udp", addr)
Expect(err).ToNot(HaveOccurred())
defer conn.Close()
tr := &quic.Transport{Conn: conn}
done1 := make(chan struct{})
done2 := make(chan struct{})
go func() {
defer GinkgoRecover()
dial(conn, server.Addr())
dial(tr, server.Addr())
close(done1)
}()
go func() {
defer GinkgoRecover()
dial(conn, server.Addr())
dial(tr, server.Addr())
close(done2)
}()
timeout := 30 * time.Second
@ -106,17 +106,18 @@ var _ = Describe("Multiplexing", func() {
conn, err := net.ListenUDP("udp", addr)
Expect(err).ToNot(HaveOccurred())
defer conn.Close()
tr := &quic.Transport{Conn: conn}
done1 := make(chan struct{})
done2 := make(chan struct{})
go func() {
defer GinkgoRecover()
dial(conn, server1.Addr())
dial(tr, server1.Addr())
close(done1)
}()
go func() {
defer GinkgoRecover()
dial(conn, server2.Addr())
dial(tr, server2.Addr())
close(done2)
}()
timeout := 30 * time.Second
@ -135,9 +136,9 @@ var _ = Describe("Multiplexing", func() {
conn, err := net.ListenUDP("udp", addr)
Expect(err).ToNot(HaveOccurred())
defer conn.Close()
tr := &quic.Transport{Conn: conn}
server, err := quic.Listen(
conn,
server, err := tr.Listen(
getTLSConfig(),
getQuicConfig(nil),
)
@ -146,7 +147,7 @@ var _ = Describe("Multiplexing", func() {
done := make(chan struct{})
go func() {
defer GinkgoRecover()
dial(conn, server.Addr())
dial(tr, server.Addr())
close(done)
}()
timeout := 30 * time.Second
@ -165,15 +166,16 @@ var _ = Describe("Multiplexing", func() {
conn1, err := net.ListenUDP("udp", addr1)
Expect(err).ToNot(HaveOccurred())
defer conn1.Close()
tr1 := &quic.Transport{Conn: conn1}
addr2, err := net.ResolveUDPAddr("udp", "localhost:0")
Expect(err).ToNot(HaveOccurred())
conn2, err := net.ListenUDP("udp", addr2)
Expect(err).ToNot(HaveOccurred())
defer conn2.Close()
tr2 := &quic.Transport{Conn: conn2}
server1, err := quic.Listen(
conn1,
server1, err := tr1.Listen(
getTLSConfig(),
getQuicConfig(nil),
)
@ -181,8 +183,7 @@ var _ = Describe("Multiplexing", func() {
runServer(server1)
defer server1.Close()
server2, err := quic.Listen(
conn2,
server2, err := tr2.Listen(
getTLSConfig(),
getQuicConfig(nil),
)
@ -194,12 +195,12 @@ var _ = Describe("Multiplexing", func() {
done2 := make(chan struct{})
go func() {
defer GinkgoRecover()
dial(conn2, server1.Addr())
dial(tr2, server1.Addr())
close(done1)
}()
go func() {
defer GinkgoRecover()
dial(conn1, server2.Addr())
dial(tr1, server2.Addr())
close(done2)
}()
timeout := 30 * time.Second

View file

@ -31,8 +31,8 @@ var _ = Describe("Packetization", func() {
}),
)
Expect(err).ToNot(HaveOccurred())
serverAddr := fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port)
defer server.Close()
serverAddr := fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port)
proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
RemoteAddr: serverAddr,
@ -54,6 +54,7 @@ var _ = Describe("Packetization", func() {
}),
)
Expect(err).ToNot(HaveOccurred())
defer conn.CloseWithError(0, "")
go func() {
defer GinkgoRecover()

View file

@ -199,8 +199,16 @@ func areHandshakesRunning() bool {
return strings.Contains(b.String(), "RunHandshake")
}
func areTransportsRunning() bool {
var b bytes.Buffer
pprof.Lookup("goroutine").WriteTo(&b, 1)
return strings.Contains(b.String(), "quic-go.(*Transport).listen")
}
var _ = AfterEach(func() {
Expect(areHandshakesRunning()).To(BeFalse())
Eventually(areTransportsRunning).Should(BeFalse())
if debugLog() {
logFile, err := os.Create(logFileName)
Expect(err).ToNot(HaveOccurred())

View file

@ -2,7 +2,6 @@ package self_test
import (
"context"
"errors"
"fmt"
"math/rand"
"net"
@ -27,7 +26,13 @@ var _ = Describe("Stateless Resets", func() {
rand.Read(statelessResetKey[:])
serverConfig := getQuicConfig(&quic.Config{StatelessResetKey: &statelessResetKey})
ln, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig)
c, err := net.ListenUDP("udp", nil)
Expect(err).ToNot(HaveOccurred())
tr := &quic.Transport{
Conn: c,
}
defer tr.Close()
ln, err := tr.Listen(getTLSConfig(), serverConfig)
Expect(err).ToNot(HaveOccurred())
serverPort := ln.Addr().(*net.UDPAddr).Port
@ -42,7 +47,8 @@ var _ = Describe("Stateless Resets", func() {
_, err = str.Write([]byte("foobar"))
Expect(err).ToNot(HaveOccurred())
<-closeServer
ln.Close()
Expect(ln.Close()).To(Succeed())
Expect(tr.Close()).To(Succeed())
}()
var drop atomic.Bool
@ -77,11 +83,14 @@ var _ = Describe("Stateless Resets", func() {
close(closeServer)
time.Sleep(100 * time.Millisecond)
ln2, err := quic.ListenAddr(
fmt.Sprintf("localhost:%d", serverPort),
getTLSConfig(),
serverConfig,
)
// We need to create a new Transport here, since the old one is still sending out
// CONNECTION_CLOSE packets for (recently) closed connections).
tr2 := &quic.Transport{
Conn: c,
StatelessResetKey: &statelessResetKey,
}
defer tr2.Close()
ln2, err := tr2.Listen(getTLSConfig(), serverConfig)
Expect(err).ToNot(HaveOccurred())
drop.Store(false)
@ -100,8 +109,7 @@ var _ = Describe("Stateless Resets", func() {
_, serr = str.Read([]byte{0})
}
Expect(serr).To(HaveOccurred())
statelessResetErr := &quic.StatelessResetError{}
Expect(errors.As(serr, &statelessResetErr)).To(BeTrue())
Expect(serr).To(BeAssignableToTypeOf(&quic.StatelessResetError{}))
Expect(ln2.Close()).To(Succeed())
Eventually(acceptStopped).Should(BeClosed())
})

View file

@ -94,6 +94,8 @@ var _ = Describe("Bidirectional streams", func() {
)
Expect(err).ToNot(HaveOccurred())
runSendingPeer(client)
client.CloseWithError(0, "")
<-conn.Context().Done()
})
It(fmt.Sprintf("server opening %d streams to a client", numStreams), func() {
@ -149,5 +151,6 @@ var _ = Describe("Bidirectional streams", func() {
runReceivingPeer(client)
<-done1
<-done2
client.CloseWithError(0, "")
})
})

View file

@ -473,6 +473,7 @@ var _ = Describe("Timeout tests", func() {
}),
)
Expect(err).ToNot(HaveOccurred())
defer ln.Close()
serverErrChan := make(chan error, 1)
go func() {

View file

@ -88,11 +88,14 @@ var _ = Describe("Unidirectional Streams", func() {
})
It(fmt.Sprintf("server opening %d streams to a client", numStreams), func() {
done := make(chan struct{})
go func() {
defer GinkgoRecover()
defer close(done)
conn, err := server.Accept(context.Background())
Expect(err).ToNot(HaveOccurred())
runSendingPeer(conn)
<-conn.Context().Done()
}()
client, err := quic.DialAddr(
@ -103,6 +106,7 @@ var _ = Describe("Unidirectional Streams", func() {
)
Expect(err).ToNot(HaveOccurred())
runReceivingPeer(client)
client.CloseWithError(0, "")
})
It(fmt.Sprintf("client and server opening %d streams each and sending data to the peer", numStreams), func() {