X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=ut-holepunching_test.go;h=ef7cda6ba7770455c22576466e0083cc7cf81c6d;hb=HEAD;hp=5df98bfbb11b6e1fe74215ef44f98e60ee17966d;hpb=92bba56b87fd06e3b0a5ea42862307718d8c4bd9;p=btrtrc.git diff --git a/ut-holepunching_test.go b/ut-holepunching_test.go index 5df98bfb..ef7cda6b 100644 --- a/ut-holepunching_test.go +++ b/ut-holepunching_test.go @@ -18,6 +18,7 @@ import ( qt "github.com/frankban/quicktest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/time/rate" "github.com/anacrolix/torrent/internal/testutil" ) @@ -36,9 +37,13 @@ func TestHolepunchConnect(t *testing.T) { cfg.DisablePEX = true cfg.Debug = true cfg.AcceptPeerConnections = false - // Listening, even without accepting, still means the leecher-leecher completes the dial to the seeder, and so it - // won't attempt to holepunch. + // Listening, even without accepting, still means the leecher-leecher completes the dial to the + // seeder, and so it won't attempt to holepunch. cfg.DisableTCP = true + // Ensure that responding to holepunch connects don't wait around for the dial limit. We also + // have to allow the initial connection to the leecher though, so it can rendezvous for us. + cfg.DialRateLimiter = rate.NewLimiter(0, 1) + cfg.Logger = cfg.Logger.WithContextText("seeder") seeder, err := NewClient(cfg) require.NoError(t, err) defer seeder.Close() @@ -52,10 +57,11 @@ func TestHolepunchConnect(t *testing.T) { cfg.Seed = true cfg.DataDir = t.TempDir() cfg.AlwaysWantConns = true + cfg.Logger = cfg.Logger.WithContextText("leecher") // This way the leecher leecher will still try to use this peer as a relay, but won't be told // about the seeder via PEX. //cfg.DisablePEX = true - //cfg.Debug = true + cfg.Debug = true leecher, err := NewClient(cfg) require.NoError(t, err) defer leecher.Close() @@ -67,6 +73,7 @@ func TestHolepunchConnect(t *testing.T) { cfg.MaxAllocPeerRequestDataPerConn = 4 cfg.Debug = true cfg.NominalDialTimeout = time.Second + cfg.Logger = cfg.Logger.WithContextText("leecher-leecher") //cfg.DisableUTP = true leecherLeecher, _ := NewClient(cfg) require.NoError(t, err) @@ -303,6 +310,7 @@ const defaultMsg = "hello" // get separate connections. This means that holepunch connect may result in an accept (and dial) // for one or both peers involved. func TestUtpSimultaneousOpen(t *testing.T) { + t.Parallel() c := qt.New(t) const network = "udp" ctx := context.Background() @@ -318,34 +326,52 @@ func TestUtpSimultaneousOpen(t *testing.T) { c.Assert(err, qt.IsNil) return socket } - first := newUtpSocket("localhost:3000") + first := newUtpSocket("localhost:0") defer first.Close() - second := newUtpSocket("localhost:3001") + second := newUtpSocket("localhost:0") defer second.Close() getDial := func(sock utpSocket, addr string) func() (net.Conn, error) { return func() (net.Conn, error) { return sock.DialContext(ctx, network, addr) } } - err := testSimultaneousOpen( - c.Cleanup, - getDial(first, "localhost:3001"), - getDial(second, "localhost:3000"), - ) - c.Assert(err, qt.ErrorIs, errMsgNotReceived) + t.Logf("first addr is %v. second addr is %v", first.Addr().String(), second.Addr().String()) + for range iter.N(10) { + err := testSimultaneousOpen( + c.Cleanup, + getDial(first, second.Addr().String()), + getDial(second, first.Addr().String()), + ) + if err == nil { + t.Fatal("expected utp to fail simultaneous open") + } + if errors.Is(err, errMsgNotReceived) { + return + } + skipGoUtpDialIssue(t, err) + t.Log(err) + time.Sleep(time.Second) + } + t.FailNow() } -func testDirectDialMsg(c *qt.C, r, w net.Conn) { +func writeAndReadMsg(r, w net.Conn) error { go writeMsg(w) - err := readMsg(r) - c.Assert(err, qt.IsNil) + return readMsg(r) +} + +func skipGoUtpDialIssue(t *testing.T, err error) { + if err.Error() == "timed out waiting for ack" { + t.Skip("anacrolix go utp implementation has issues. Use anacrolix/go-libutp by enabling CGO.") + } } // Show that dialling one socket and accepting from the other results in them having ends of the // same connection. func TestUtpDirectDialMsg(t *testing.T) { + t.Parallel() c := qt.New(t) - const network = "udp" + const network = "udp4" ctx := context.Background() newUtpSocket := func(addr string) utpSocket { socket, err := NewUtpSocket(network, addr, func(net.Addr) bool { @@ -354,15 +380,28 @@ func TestUtpDirectDialMsg(t *testing.T) { c.Assert(err, qt.IsNil) return socket } - first := newUtpSocket("localhost:0") - defer first.Close() - second := newUtpSocket("localhost:0") - defer second.Close() - writer, err := first.DialContext(ctx, network, second.Addr().String()) - c.Assert(err, qt.IsNil) - defer writer.Close() - reader, err := second.Accept() - defer reader.Close() - c.Assert(err, qt.IsNil) - testDirectDialMsg(c, reader, writer) + for range iter.N(10) { + err := func() error { + first := newUtpSocket("localhost:0") + defer first.Close() + second := newUtpSocket("localhost:0") + defer second.Close() + writer, err := first.DialContext(ctx, network, second.Addr().String()) + if err != nil { + return err + } + defer writer.Close() + reader, err := second.Accept() + defer reader.Close() + c.Assert(err, qt.IsNil) + return writeAndReadMsg(reader, writer) + }() + if err == nil { + return + } + skipGoUtpDialIssue(t, err) + t.Log(err) + time.Sleep(time.Second) + } + t.FailNow() }