9 "github.com/anacrolix/log"
11 "github.com/anacrolix/torrent/internal/testutil"
12 qt "github.com/frankban/quicktest"
13 "github.com/stretchr/testify/assert"
14 "github.com/stretchr/testify/require"
17 // Check that after completing leeching, a leecher transitions to a seeding
18 // correctly. Connected in a chain like so: Seeder <-> Leecher <-> LeecherLeecher.
19 func TestHolepunchConnect(t *testing.T) {
20 greetingTempDir, mi := testutil.GreetingTestTorrent()
21 defer os.RemoveAll(greetingTempDir)
23 cfg := TestingConfig(t)
25 cfg.MaxAllocPeerRequestDataPerConn = 4
26 cfg.DataDir = greetingTempDir
29 cfg.AcceptPeerConnections = false
30 //cfg.DisableUTP = true
31 seeder, err := NewClient(cfg)
32 require.NoError(t, err)
34 defer testutil.ExportStatusWriter(seeder, "s", t)()
35 seederTorrent, ok, err := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
36 require.NoError(t, err)
38 seederTorrent.VerifyData()
40 cfg = TestingConfig(t)
42 cfg.DataDir = t.TempDir()
43 cfg.AlwaysWantConns = true
44 // This way the leecher leecher will still try to use this peer as a relay, but won't be told
45 // about the seeder via PEX.
46 //cfg.DisablePEX = true
48 leecher, err := NewClient(cfg)
49 require.NoError(t, err)
51 defer testutil.ExportStatusWriter(leecher, "l", t)()
53 cfg = TestingConfig(t)
55 cfg.DataDir = t.TempDir()
56 cfg.MaxAllocPeerRequestDataPerConn = 4
58 cfg.NominalDialTimeout = time.Second
59 //cfg.DisableUTP = true
60 leecherLeecher, _ := NewClient(cfg)
61 require.NoError(t, err)
62 defer leecherLeecher.Close()
63 defer testutil.ExportStatusWriter(leecherLeecher, "ll", t)()
64 leecherGreeting, ok, err := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
65 ret = TorrentSpecFromMetaInfo(mi)
70 require.NoError(t, err)
72 llg, ok, err := leecherLeecher.AddTorrentSpec(func() (ret *TorrentSpec) {
73 ret = TorrentSpecFromMetaInfo(mi)
77 require.NoError(t, err)
86 qt.Check(t, iotest.TestReader(r, []byte(testutil.GreetingFileContents)), qt.IsNil)
88 go seederTorrent.AddClientPeer(leecher)
89 waitForConns(seederTorrent)
90 go llg.AddClientPeer(leecher)
92 time.Sleep(time.Second)
94 targetAddr := seeder.ListenAddrs()[0]
95 log.Printf("trying to initiate to %v", targetAddr)
96 initiateConn(outgoingConnOpts{
101 requireRendezvous: true,
102 skipHolepunchRendezvous: false,
103 HeaderObfuscationPolicy: llg.cl.config.HeaderObfuscationPolicy,
108 llClientStats := leecherLeecher.Stats()
109 c.Check(llClientStats.NumPeersDialableOnlyAfterHolepunch, qt.Not(qt.Equals), 0)
111 llClientStats.NumPeersDialableOnlyAfterHolepunch,
113 llClientStats.NumPeersUndialableWithoutHolepunchDialedAfterHolepunchConnect,
117 func waitForConns(t *Torrent) {
128 func TestDialTcpNotAccepting(t *testing.T) {
129 l, err := net.Listen("tcp", "localhost:0")
131 c.Check(err, qt.IsNil)
133 _, err = net.Dial("tcp", l.Addr().String())
134 c.Assert(err, qt.IsNotNil)