Files
quic-go/integrationtests/self/handshake_rtt_test.go
Marten Seemann 79d546379b rename ClientHelloInfo to ClientInfo (#5016)
There’s no ClientHello (which is a TLS concept) involved here.
2025-03-31 16:15:09 +02:00

180 lines
5.0 KiB
Go

package self_test
import (
"context"
"crypto/tls"
"io"
"net"
"testing"
"time"
"github.com/quic-go/quic-go"
quicproxy "github.com/quic-go/quic-go/integrationtests/tools/proxy"
"github.com/stretchr/testify/require"
)
func handshakeWithRTT(t *testing.T, serverAddr net.Addr, tlsConf *tls.Config, quicConf *quic.Config, rtt time.Duration) quic.Connection {
t.Helper()
proxy := quicproxy.Proxy{
Conn: newUDPConnLocalhost(t),
ServerAddr: serverAddr.(*net.UDPAddr),
DelayPacket: func(quicproxy.Direction, net.Addr, net.Addr, []byte) time.Duration { return rtt / 2 },
}
require.NoError(t, proxy.Start())
t.Cleanup(func() { proxy.Close() })
ctx, cancel := context.WithTimeout(context.Background(), 10*rtt)
defer cancel()
conn, err := quic.Dial(
ctx,
newUDPConnLocalhost(t),
proxy.LocalAddr(),
tlsConf,
quicConf,
)
require.NoError(t, err)
t.Cleanup(func() { conn.CloseWithError(0, "") })
return conn
}
func TestHandshakeRTTWithoutRetry(t *testing.T) {
ln, err := quic.Listen(newUDPConnLocalhost(t), getTLSConfig(), getQuicConfig(nil))
require.NoError(t, err)
defer ln.Close()
clientConfig := getQuicConfig(&quic.Config{
GetConfigForClient: func(info *quic.ClientInfo) (*quic.Config, error) {
require.False(t, info.AddrVerified)
return nil, nil
},
})
const rtt = 400 * time.Millisecond
start := time.Now()
handshakeWithRTT(t, ln.Addr(), getTLSClientConfig(), clientConfig, rtt)
rtts := time.Since(start).Seconds() / rtt.Seconds()
require.GreaterOrEqual(t, rtts, float64(1))
require.Less(t, rtts, float64(2))
}
func TestHandshakeRTTWithRetry(t *testing.T) {
tr := &quic.Transport{
Conn: newUDPConnLocalhost(t),
VerifySourceAddress: func(net.Addr) bool { return true },
}
addTracer(tr)
defer tr.Close()
ln, err := tr.Listen(getTLSConfig(), getQuicConfig(nil))
require.NoError(t, err)
defer ln.Close()
clientConfig := getQuicConfig(&quic.Config{
GetConfigForClient: func(info *quic.ClientInfo) (*quic.Config, error) {
require.True(t, info.AddrVerified)
return nil, nil
},
})
const rtt = 400 * time.Millisecond
start := time.Now()
handshakeWithRTT(t, ln.Addr(), getTLSClientConfig(), clientConfig, rtt)
rtts := time.Since(start).Seconds() / rtt.Seconds()
require.GreaterOrEqual(t, rtts, float64(2))
require.Less(t, rtts, float64(3))
}
func TestHandshakeRTTWithHelloRetryRequest(t *testing.T) {
tlsConf := getTLSConfig()
tlsConf.CurvePreferences = []tls.CurveID{tls.CurveP384}
ln, err := quic.Listen(newUDPConnLocalhost(t), tlsConf, getQuicConfig(nil))
require.NoError(t, err)
defer ln.Close()
const rtt = 400 * time.Millisecond
start := time.Now()
handshakeWithRTT(t, ln.Addr(), getTLSClientConfig(), getQuicConfig(nil), rtt)
rtts := time.Since(start).Seconds() / rtt.Seconds()
require.GreaterOrEqual(t, rtts, float64(2))
require.Less(t, rtts, float64(3))
}
func TestHandshakeRTTReceiveMessage(t *testing.T) {
sendAndReceive := func(t *testing.T, serverConn, clientConn quic.Connection) {
t.Helper()
serverStr, err := serverConn.OpenUniStream()
require.NoError(t, err)
_, err = serverStr.Write([]byte("foobar"))
require.NoError(t, err)
require.NoError(t, serverStr.Close())
str, err := clientConn.AcceptUniStream(context.Background())
require.NoError(t, err)
data, err := io.ReadAll(str)
require.NoError(t, err)
require.Equal(t, []byte("foobar"), data)
}
t.Run("using Listen", func(t *testing.T) {
ln, err := quic.Listen(newUDPConnLocalhost(t), getTLSConfig(), getQuicConfig(nil))
require.NoError(t, err)
defer ln.Close()
connChan := make(chan quic.Connection, 1)
go func() {
conn, err := ln.Accept(context.Background())
if err != nil {
t.Logf("failed to accept connection: %s", err)
close(connChan)
return
}
connChan <- conn
}()
const rtt = 400 * time.Millisecond
start := time.Now()
conn := handshakeWithRTT(t, ln.Addr(), getTLSClientConfig(), getQuicConfig(nil), rtt)
serverConn := <-connChan
if serverConn == nil {
t.Fatal("serverConn is nil")
}
sendAndReceive(t, serverConn, conn)
rtts := time.Since(start).Seconds() / rtt.Seconds()
require.GreaterOrEqual(t, rtts, float64(2))
require.Less(t, rtts, float64(3))
})
t.Run("using ListenEarly", func(t *testing.T) {
ln, err := quic.ListenEarly(newUDPConnLocalhost(t), getTLSConfig(), getQuicConfig(nil))
require.NoError(t, err)
defer ln.Close()
connChan := make(chan quic.Connection, 1)
go func() {
conn, err := ln.Accept(context.Background())
if err != nil {
t.Logf("failed to accept connection: %s", err)
close(connChan)
return
}
connChan <- conn
}()
const rtt = 400 * time.Millisecond
start := time.Now()
conn := handshakeWithRTT(t, ln.Addr(), getTLSClientConfig(), getQuicConfig(nil), rtt)
serverConn := <-connChan
if serverConn == nil {
t.Fatal("serverConn is nil")
}
sendAndReceive(t, serverConn, conn)
took := time.Since(start)
rtts := float64(took) / float64(rtt)
require.GreaterOrEqual(t, rtts, float64(1))
require.Less(t, rtts, float64(2))
})
}