forked from quic-go/quic-go
proxy: rename to Proxy, refactor initialization (#4921)
* proxy: rename to Proxy, refactor initialization * improve documentation
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
package quicproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -16,6 +13,14 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newUPDConnLocalhost(t testing.TB) *net.UDPConn {
|
||||
t.Helper()
|
||||
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0})
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { conn.Close() })
|
||||
return conn
|
||||
}
|
||||
|
||||
type packetData []byte
|
||||
|
||||
func makePacket(t *testing.T, p protocol.PacketNumber, payload []byte) []byte {
|
||||
@@ -47,37 +52,6 @@ func readPacketNumber(t *testing.T, b []byte) protocol.PacketNumber {
|
||||
return extHdr.PacketNumber
|
||||
}
|
||||
|
||||
func TestProxyShutdown(t *testing.T) {
|
||||
isProxyRunning := func() bool {
|
||||
var b bytes.Buffer
|
||||
pprof.Lookup("goroutine").WriteTo(&b, 1)
|
||||
return strings.Contains(b.String(), "proxy.(*QuicProxy).runProxy")
|
||||
}
|
||||
|
||||
proxy, err := NewQuicProxy("localhost:0", nil)
|
||||
require.NoError(t, err)
|
||||
require.Eventually(t, func() bool { return isProxyRunning() }, time.Second, 10*time.Millisecond)
|
||||
|
||||
conn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
_, err = conn.Write(makePacket(t, 1, []byte("foobar")))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, proxy.Close())
|
||||
|
||||
// check that the proxy port is not in use anymore
|
||||
// sometimes it takes a while for the OS to free the port
|
||||
require.Eventually(t, func() bool {
|
||||
ln, err := net.ListenUDP("udp", proxy.LocalAddr().(*net.UDPAddr))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
ln.Close()
|
||||
return true
|
||||
}, time.Second, 10*time.Millisecond)
|
||||
require.Eventually(t, func() bool { return !isProxyRunning() }, time.Second, 10*time.Millisecond)
|
||||
}
|
||||
|
||||
// Set up a dumb UDP server.
|
||||
// In production this would be a QUIC server.
|
||||
func runServer(t *testing.T) (*net.UDPAddr, chan packetData) {
|
||||
@@ -116,25 +90,19 @@ func runServer(t *testing.T) (*net.UDPAddr, chan packetData) {
|
||||
return serverConn.LocalAddr().(*net.UDPAddr), serverReceivedPackets
|
||||
}
|
||||
|
||||
func startProxy(t *testing.T, opts *Opts) (clientConn *net.UDPConn) {
|
||||
proxy, err := NewQuicProxy("localhost:0", opts)
|
||||
require.NoError(t, err)
|
||||
clientConn, err = net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, proxy.Close())
|
||||
require.NoError(t, clientConn.Close())
|
||||
})
|
||||
return clientConn
|
||||
}
|
||||
|
||||
func TestProxyyingBackAndForth(t *testing.T) {
|
||||
serverAddr, _ := runServer(t)
|
||||
clientConn := startProxy(t, &Opts{RemoteAddr: serverAddr.String()})
|
||||
proxy := Proxy{
|
||||
Conn: newUPDConnLocalhost(t),
|
||||
ServerAddr: serverAddr,
|
||||
}
|
||||
require.NoError(t, proxy.Start())
|
||||
defer proxy.Close()
|
||||
clientConn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
// send the first packet
|
||||
_, err := clientConn.Write(makePacket(t, 1, []byte("foobar")))
|
||||
_, err = clientConn.Write(makePacket(t, 1, []byte("foobar")))
|
||||
require.NoError(t, err)
|
||||
// send the second packet
|
||||
_, err = clientConn.Write(makePacket(t, 2, []byte("decafbad")))
|
||||
@@ -153,15 +121,20 @@ func TestDropIncomingPackets(t *testing.T) {
|
||||
const numPackets = 6
|
||||
serverAddr, serverReceivedPackets := runServer(t)
|
||||
var counter atomic.Int32
|
||||
clientConn := startProxy(t, &Opts{
|
||||
RemoteAddr: serverAddr.String(),
|
||||
proxy := Proxy{
|
||||
Conn: newUPDConnLocalhost(t),
|
||||
ServerAddr: serverAddr,
|
||||
DropPacket: func(d Direction, _ []byte) bool {
|
||||
if d != DirectionIncoming {
|
||||
return false
|
||||
}
|
||||
return counter.Add(1)%2 == 1
|
||||
},
|
||||
})
|
||||
}
|
||||
require.NoError(t, proxy.Start())
|
||||
defer proxy.Close()
|
||||
clientConn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := 1; i <= numPackets; i++ {
|
||||
_, err := clientConn.Write(makePacket(t, protocol.PacketNumber(i), []byte("foobar"+strconv.Itoa(i))))
|
||||
@@ -186,15 +159,20 @@ func TestDropOutgoingPackets(t *testing.T) {
|
||||
const numPackets = 6
|
||||
serverAddr, serverReceivedPackets := runServer(t)
|
||||
var counter atomic.Int32
|
||||
clientConn := startProxy(t, &Opts{
|
||||
RemoteAddr: serverAddr.String(),
|
||||
proxy := Proxy{
|
||||
Conn: newUPDConnLocalhost(t),
|
||||
ServerAddr: serverAddr,
|
||||
DropPacket: func(d Direction, _ []byte) bool {
|
||||
if d != DirectionOutgoing {
|
||||
return false
|
||||
}
|
||||
return counter.Add(1)%2 == 1
|
||||
},
|
||||
})
|
||||
}
|
||||
require.NoError(t, proxy.Start())
|
||||
defer proxy.Close()
|
||||
clientConn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
clientReceivedPackets := make(chan struct{}, numPackets)
|
||||
// receive the packets echoed by the server on client side
|
||||
@@ -234,19 +212,24 @@ func TestDelayIncomingPackets(t *testing.T) {
|
||||
const delay = 200 * time.Millisecond
|
||||
serverAddr, serverReceivedPackets := runServer(t)
|
||||
var counter atomic.Int32
|
||||
clientConn := startProxy(t, &Opts{
|
||||
RemoteAddr: serverAddr.String(),
|
||||
// delay packet 1 by 200 ms
|
||||
// delay packet 2 by 400 ms
|
||||
// ...
|
||||
proxy := Proxy{
|
||||
Conn: newUPDConnLocalhost(t),
|
||||
ServerAddr: serverAddr,
|
||||
DelayPacket: func(d Direction, _ []byte) time.Duration {
|
||||
// delay packet 1 by 200 ms
|
||||
// delay packet 2 by 400 ms
|
||||
// ...
|
||||
if d == DirectionOutgoing {
|
||||
return 0
|
||||
}
|
||||
p := counter.Add(1)
|
||||
return time.Duration(p) * delay
|
||||
},
|
||||
})
|
||||
}
|
||||
require.NoError(t, proxy.Start())
|
||||
defer proxy.Close()
|
||||
clientConn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
start := time.Now()
|
||||
for i := 1; i <= numPackets; i++ {
|
||||
@@ -276,19 +259,24 @@ func TestPacketReordering(t *testing.T) {
|
||||
|
||||
serverAddr, serverReceivedPackets := runServer(t)
|
||||
var counter atomic.Int32
|
||||
clientConn := startProxy(t, &Opts{
|
||||
RemoteAddr: serverAddr.String(),
|
||||
// delay packet 1 by 600 ms
|
||||
// delay packet 2 by 400 ms
|
||||
// delay packet 3 by 200 ms
|
||||
proxy := Proxy{
|
||||
Conn: newUPDConnLocalhost(t),
|
||||
ServerAddr: serverAddr,
|
||||
DelayPacket: func(d Direction, _ []byte) time.Duration {
|
||||
// delay packet 1 by 600 ms
|
||||
// delay packet 2 by 400 ms
|
||||
// delay packet 3 by 200 ms
|
||||
if d == DirectionOutgoing {
|
||||
return 0
|
||||
}
|
||||
p := counter.Add(1)
|
||||
return 600*time.Millisecond - time.Duration(p-1)*delay
|
||||
},
|
||||
})
|
||||
}
|
||||
require.NoError(t, proxy.Start())
|
||||
defer proxy.Close()
|
||||
clientConn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
// send 3 packets
|
||||
start := time.Now()
|
||||
@@ -310,15 +298,20 @@ func TestPacketReordering(t *testing.T) {
|
||||
|
||||
func TestConstantDelay(t *testing.T) { // no reordering expected here
|
||||
serverAddr, serverReceivedPackets := runServer(t)
|
||||
clientConn := startProxy(t, &Opts{
|
||||
RemoteAddr: serverAddr.String(),
|
||||
proxy := Proxy{
|
||||
Conn: newUPDConnLocalhost(t),
|
||||
ServerAddr: serverAddr,
|
||||
DelayPacket: func(d Direction, _ []byte) time.Duration {
|
||||
if d == DirectionOutgoing {
|
||||
return 0
|
||||
}
|
||||
return 100 * time.Millisecond
|
||||
},
|
||||
})
|
||||
}
|
||||
require.NoError(t, proxy.Start())
|
||||
defer proxy.Close()
|
||||
clientConn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
// send 100 packets
|
||||
for i := 0; i < 100; i++ {
|
||||
@@ -343,19 +336,24 @@ func TestDelayOutgoingPackets(t *testing.T) {
|
||||
|
||||
serverAddr, serverReceivedPackets := runServer(t)
|
||||
var counter atomic.Int32
|
||||
clientConn := startProxy(t, &Opts{
|
||||
RemoteAddr: serverAddr.String(),
|
||||
// delay packet 1 by 200 ms
|
||||
// delay packet 2 by 400 ms
|
||||
// ...
|
||||
proxy := Proxy{
|
||||
Conn: newUPDConnLocalhost(t),
|
||||
ServerAddr: serverAddr,
|
||||
DelayPacket: func(d Direction, _ []byte) time.Duration {
|
||||
// delay packet 1 by 200 ms
|
||||
// delay packet 2 by 400 ms
|
||||
// ...
|
||||
if d == DirectionIncoming {
|
||||
return 0
|
||||
}
|
||||
p := counter.Add(1)
|
||||
return time.Duration(p) * delay
|
||||
},
|
||||
})
|
||||
}
|
||||
require.NoError(t, proxy.Start())
|
||||
defer proxy.Close()
|
||||
clientConn, err := net.DialUDP("udp", nil, proxy.LocalAddr().(*net.UDPAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
clientReceivedPackets := make(chan packetData, numPackets)
|
||||
// receive the packets echoed by the server on client side
|
||||
|
||||
Reference in New Issue
Block a user