diff --git a/integrationtests/drop_test.go b/integrationtests/drop_test.go index e8b6f933..8312f73c 100644 --- a/integrationtests/drop_test.go +++ b/integrationtests/drop_test.go @@ -30,7 +30,7 @@ func runDropTest(incomingPacketDropper, outgoingPacketDropper dropCallback, vers iPort, _ := strconv.Atoi(port) var err error - proxy, err = NewUDPProxy(proxyPort, "localhost", iPort, incomingPacketDropper, outgoingPacketDropper) + proxy, err = NewUDPProxy(proxyPort, "localhost", iPort, incomingPacketDropper, outgoingPacketDropper, 0) Expect(err).ToNot(HaveOccurred()) command := exec.Command( diff --git a/integrationtests/rtt_test.go b/integrationtests/rtt_test.go new file mode 100644 index 00000000..49e3a48b --- /dev/null +++ b/integrationtests/rtt_test.go @@ -0,0 +1,66 @@ +package integrationtests + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "runtime" + "strconv" + "time" + + _ "github.com/lucas-clemente/quic-clients" // download clients + "github.com/lucas-clemente/quic-go/protocol" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("RTT", func() { + var rttProxy *UDPProxy + + runRTTTest := func(rtt time.Duration, version protocol.VersionNumber) { + proxyPort := 12345 + + clientPath := fmt.Sprintf( + "%s/src/github.com/lucas-clemente/quic-clients/client-%s-debug", + os.Getenv("GOPATH"), + runtime.GOOS, + ) + + iPort, _ := strconv.Atoi(port) + var err error + rttProxy, err = NewUDPProxy(proxyPort, "localhost", iPort, nil, nil, rtt) + Expect(err).ToNot(HaveOccurred()) + + command := exec.Command( + clientPath, + "--quic-version="+strconv.Itoa(int(version)), + "--host=127.0.0.1", + "--port="+strconv.Itoa(proxyPort), + "https://quic.clemente.io/data", + ) + + session, err := Start(command, nil, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + defer session.Kill() + Eventually(session, 4).Should(Exit(0)) + Expect(bytes.Contains(session.Out.Contents(), data)).To(BeTrue()) + } + + AfterEach(func() { + rttProxy.Stop() + time.Sleep(time.Millisecond) + }) + + for i := range protocol.SupportedVersions { + version := protocol.SupportedVersions[i] + + Context(fmt.Sprintf("with quic version %d", version), func() { + It("gets a file with 10ms RTT", func() { + runRTTTest(10*time.Millisecond, version) + }) + }) + } +}) diff --git a/integrationtests/udp_proxy.go b/integrationtests/udp_proxy.go index 9322ea11..6c83867f 100644 --- a/integrationtests/udp_proxy.go +++ b/integrationtests/udp_proxy.go @@ -4,6 +4,7 @@ import ( "net" "strconv" "sync" + "time" ) // Connection is a UDP connection @@ -26,13 +27,14 @@ type UDPProxy struct { proxyConn *net.UDPConn dropIncomingPacket dropCallback dropOutgoingPacket dropCallback + rtt time.Duration // Mapping from client addresses (as host:port) to connection clientDict map[string]*connection } // NewUDPProxy creates a new UDP proxy -func NewUDPProxy(proxyPort int, serverAddress string, serverPort int, dropIncomingPacket, dropOutgoingPacket dropCallback) (*UDPProxy, error) { +func NewUDPProxy(proxyPort int, serverAddress string, serverPort int, dropIncomingPacket, dropOutgoingPacket dropCallback, rtt time.Duration) (*UDPProxy, error) { dontDrop := func(p PacketNumber) bool { return false } @@ -48,6 +50,7 @@ func NewUDPProxy(proxyPort int, serverAddress string, serverPort int, dropIncomi clientDict: make(map[string]*connection), dropIncomingPacket: dropIncomingPacket, dropOutgoingPacket: dropOutgoingPacket, + rtt: rtt, } saddr, err := net.ResolveUDPAddr("udp", ":"+strconv.Itoa(proxyPort)) @@ -89,9 +92,8 @@ func (p *UDPProxy) newConnection(cliAddr *net.UDPAddr) (*connection, error) { // runProxy handles inputs to Proxy port func (p *UDPProxy) runProxy() error { - buffer := make([]byte, 1500) - for { + buffer := make([]byte, 1500) n, cliaddr, err := p.proxyConn.ReadFromUDP(buffer[0:]) if err != nil { return err @@ -119,19 +121,18 @@ func (p *UDPProxy) runProxy() error { if !p.dropIncomingPacket(conn.incomingPacketCounter) { // Relay to server - _, err = conn.ServerConn.Write(buffer[0:n]) - if err != nil { - return err - } + go func() { + time.Sleep(p.rtt / 2) + conn.ServerConn.Write(buffer[0:n]) + }() } } } // runConnection handles packets from server to a single client func (p *UDPProxy) runConnection(conn *connection) error { - buffer := make([]byte, 1500) - for { + buffer := make([]byte, 1500) n, err := conn.ServerConn.Read(buffer[0:]) if err != nil { return err @@ -141,10 +142,10 @@ func (p *UDPProxy) runConnection(conn *connection) error { if !p.dropOutgoingPacket(conn.outgoingPacketCounter) { // Relay it to client - _, err = p.proxyConn.WriteToUDP(buffer[0:n], conn.ClientAddr) - if err != nil { - return err - } + go func() { + time.Sleep(p.rtt / 2) + p.proxyConn.WriteToUDP(buffer[0:n], conn.ClientAddr) + }() } } } diff --git a/integrationtests/udp_proxy_test.go b/integrationtests/udp_proxy_test.go index 04645360..0c78d8ce 100644 --- a/integrationtests/udp_proxy_test.go +++ b/integrationtests/udp_proxy_test.go @@ -19,7 +19,7 @@ var _ = Describe("Integrationtests", func() { }) It("sets up the UDPProxy", func() { - proxy, err := NewUDPProxy(13370, "localhost", serverPort, nil, nil) + proxy, err := NewUDPProxy(13370, "localhost", serverPort, nil, nil, 0) Expect(err).ToNot(HaveOccurred()) Expect(proxy.clientDict).To(HaveLen(0)) @@ -34,7 +34,7 @@ var _ = Describe("Integrationtests", func() { }) It("stops the UDPProxy", func() { - proxy, err := NewUDPProxy(13371, "localhost", serverPort, nil, nil) + proxy, err := NewUDPProxy(13371, "localhost", serverPort, nil, nil, 0) Expect(err).ToNot(HaveOccurred()) proxy.Stop() @@ -102,7 +102,7 @@ var _ = Describe("Integrationtests", func() { BeforeEach(func() { // setup the proxy var err error - proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, nil) + proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, nil, 0) Expect(err).ToNot(HaveOccurred()) }) @@ -175,7 +175,7 @@ var _ = Describe("Integrationtests", func() { } var err error - proxy, err = NewUDPProxy(10001, "localhost", serverPort, dropper, nil) + proxy, err = NewUDPProxy(10001, "localhost", serverPort, dropper, nil, 0) Expect(err).ToNot(HaveOccurred()) for i := 1; i <= 6; i++ { @@ -195,7 +195,7 @@ var _ = Describe("Integrationtests", func() { } var err error - proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, dropper) + proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, dropper, 0) Expect(err).ToNot(HaveOccurred()) for i := 1; i <= 6; i++ {