From e35276b17edff109c83a72ba91238b4aa336ac43 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 1 Aug 2016 14:22:07 +0700 Subject: [PATCH] implement a RTTGenerator for generating random RTTs for the UDP Proxy ref #233 --- integrationtests/drop_test.go | 2 +- integrationtests/proxy/rtt_generator.go | 31 +++++++++++ integrationtests/proxy/rtt_generator_test.go | 56 ++++++++++++++++++++ integrationtests/proxy/udp_proxy.go | 10 ++-- integrationtests/proxy/udp_proxy_test.go | 10 ++-- integrationtests/rtt_test.go | 4 +- 6 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 integrationtests/proxy/rtt_generator.go create mode 100644 integrationtests/proxy/rtt_generator_test.go diff --git a/integrationtests/drop_test.go b/integrationtests/drop_test.go index f8d22da4..8a32dabe 100644 --- a/integrationtests/drop_test.go +++ b/integrationtests/drop_test.go @@ -32,7 +32,7 @@ var _ = Describe("Drop Proxy", func() { iPort, _ := strconv.Atoi(port) var err error - dropproxy, err = proxy.NewUDPProxy(proxyPort, "localhost", iPort, incomingPacketDropper, outgoingPacketDropper, 0) + dropproxy, err = proxy.NewUDPProxy(proxyPort, "localhost", iPort, incomingPacketDropper, outgoingPacketDropper, 0, 0) Expect(err).ToNot(HaveOccurred()) command := exec.Command( diff --git a/integrationtests/proxy/rtt_generator.go b/integrationtests/proxy/rtt_generator.go new file mode 100644 index 00000000..6f18623d --- /dev/null +++ b/integrationtests/proxy/rtt_generator.go @@ -0,0 +1,31 @@ +package proxy + +import ( + "math/rand" + "time" +) + +type rttGenerator struct { + min time.Duration + max time.Duration +} + +func newRttGenerator(min, max time.Duration) rttGenerator { + rand.Seed(time.Now().UnixNano()) + return rttGenerator{ + min: min, + max: max, + } +} + +func (s *rttGenerator) getRTT() time.Duration { + if s.min == s.max { + return s.min + } + + minns := s.min.Nanoseconds() + maxns := s.max.Nanoseconds() + rttns := rand.Int63n(maxns-minns) + minns + + return time.Duration(rttns) * time.Nanosecond +} diff --git a/integrationtests/proxy/rtt_generator_test.go b/integrationtests/proxy/rtt_generator_test.go new file mode 100644 index 00000000..773dfbbe --- /dev/null +++ b/integrationtests/proxy/rtt_generator_test.go @@ -0,0 +1,56 @@ +package proxy + +import ( + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("RTT settings", func() { + Context("no variance", func() { + It("always gets the same value", func() { + rttGen := newRttGenerator(10*time.Millisecond, 10*time.Millisecond) + for i := 0; i < 100; i++ { + Expect(rttGen.getRTT()).To(Equal(10 * time.Millisecond)) + } + }) + }) + + Context("random RTT", func() { + var rttGen rttGenerator + + BeforeEach(func() { + rttGen = newRttGenerator(10*time.Millisecond, 30*time.Millisecond) + }) + + It("has the right mean value", func() { + var rttSum time.Duration + rep := 1000 + for i := 0; i < rep; i++ { + rttSum += rttGen.getRTT() + } + averageRTT := rttSum.Nanoseconds() / 1000 / int64(rep) // in microseconds + Expect(averageRTT).To(BeNumerically("~", 20000, 1000)) // between 19 and 21 microseconds + }) + + It("covers the whole interval", func() { + var max time.Duration + min := time.Hour + + rep := 1000 + for i := 0; i < rep; i++ { + rtt := rttGen.getRTT() + if rtt > max { + max = rtt + } + if rtt < min { + min = rtt + } + } + + Expect(min.Nanoseconds() / 1000).To(BeNumerically("<", 11000)) + Expect(max.Nanoseconds() / 1000).To(BeNumerically(">", 29000)) + }) + }) +}) diff --git a/integrationtests/proxy/udp_proxy.go b/integrationtests/proxy/udp_proxy.go index 7b7f1823..2d5c80d1 100644 --- a/integrationtests/proxy/udp_proxy.go +++ b/integrationtests/proxy/udp_proxy.go @@ -31,14 +31,14 @@ type UDPProxy struct { proxyConn *net.UDPConn dropIncomingPacket DropCallback dropOutgoingPacket DropCallback - rtt time.Duration + rttGen rttGenerator // 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, rtt time.Duration) (*UDPProxy, error) { +func NewUDPProxy(proxyPort int, serverAddress string, serverPort int, dropIncomingPacket, dropOutgoingPacket DropCallback, rttMin time.Duration, rttMax time.Duration) (*UDPProxy, error) { dontDrop := func(p PacketNumber) bool { return false } @@ -54,7 +54,7 @@ func NewUDPProxy(proxyPort int, serverAddress string, serverPort int, dropIncomi clientDict: make(map[string]*connection), dropIncomingPacket: dropIncomingPacket, dropOutgoingPacket: dropOutgoingPacket, - rtt: rtt, + rttGen: newRttGenerator(rttMin, rttMax), } saddr, err := net.ResolveUDPAddr("udp", ":"+strconv.Itoa(proxyPort)) @@ -126,7 +126,7 @@ func (p *UDPProxy) runProxy() error { if !p.dropIncomingPacket(conn.incomingPacketCounter) { // Relay to server go func() { - time.Sleep(p.rtt / 2) + time.Sleep(p.rttGen.getRTT() / 2) conn.ServerConn.Write(buffer[0:n]) }() } @@ -147,7 +147,7 @@ func (p *UDPProxy) runConnection(conn *connection) error { if !p.dropOutgoingPacket(conn.outgoingPacketCounter) { // Relay it to client go func() { - time.Sleep(p.rtt / 2) + time.Sleep(p.rttGen.getRTT() / 2) p.proxyConn.WriteToUDP(buffer[0:n], conn.ClientAddr) }() } diff --git a/integrationtests/proxy/udp_proxy_test.go b/integrationtests/proxy/udp_proxy_test.go index 4c939712..4ef5c457 100644 --- a/integrationtests/proxy/udp_proxy_test.go +++ b/integrationtests/proxy/udp_proxy_test.go @@ -19,7 +19,7 @@ var _ = Describe("UDP Proxy", func() { }) It("sets up the UDPProxy", func() { - proxy, err := NewUDPProxy(13370, "localhost", serverPort, nil, nil, 0) + proxy, err := NewUDPProxy(13370, "localhost", serverPort, nil, nil, 0, 0) Expect(err).ToNot(HaveOccurred()) Expect(proxy.clientDict).To(HaveLen(0)) @@ -34,7 +34,7 @@ var _ = Describe("UDP Proxy", func() { }) It("stops the UDPProxy", func() { - proxy, err := NewUDPProxy(13371, "localhost", serverPort, nil, nil, 0) + proxy, err := NewUDPProxy(13371, "localhost", serverPort, nil, nil, 0, 0) Expect(err).ToNot(HaveOccurred()) proxy.Stop() @@ -102,7 +102,7 @@ var _ = Describe("UDP Proxy", func() { BeforeEach(func() { // setup the proxy var err error - proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, nil, 0) + proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, nil, 0, 0) Expect(err).ToNot(HaveOccurred()) }) @@ -175,7 +175,7 @@ var _ = Describe("UDP Proxy", func() { } var err error - proxy, err = NewUDPProxy(10001, "localhost", serverPort, dropper, nil, 0) + proxy, err = NewUDPProxy(10001, "localhost", serverPort, dropper, nil, 0, 0) Expect(err).ToNot(HaveOccurred()) for i := 1; i <= 6; i++ { @@ -195,7 +195,7 @@ var _ = Describe("UDP Proxy", func() { } var err error - proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, dropper, 0) + proxy, err = NewUDPProxy(10001, "localhost", serverPort, nil, dropper, 0, 0) Expect(err).ToNot(HaveOccurred()) for i := 1; i <= 6; i++ { diff --git a/integrationtests/rtt_test.go b/integrationtests/rtt_test.go index 4366deec..a55a5b33 100644 --- a/integrationtests/rtt_test.go +++ b/integrationtests/rtt_test.go @@ -18,7 +18,7 @@ import ( . "github.com/onsi/gomega/gexec" ) -var _ = Describe("RTT", func() { +var _ = Describe("non-zero RTT", func() { var rttProxy *proxy.UDPProxy runRTTTest := func(rtt time.Duration, version protocol.VersionNumber) { @@ -32,7 +32,7 @@ var _ = Describe("RTT", func() { iPort, _ := strconv.Atoi(port) var err error - rttProxy, err = proxy.NewUDPProxy(proxyPort, "localhost", iPort, nil, nil, rtt) + rttProxy, err = proxy.NewUDPProxy(proxyPort, "localhost", iPort, nil, nil, rtt, rtt) Expect(err).ToNot(HaveOccurred()) command := exec.Command(