]> Sergey Matveev's repositories - btrtrc.git/blob - ut-holepunching_test.go
Attempt holepunch after initial dial fails
[btrtrc.git] / ut-holepunching_test.go
1 package torrent
2
3 import (
4         "os"
5         "sync"
6         "testing"
7         "testing/iotest"
8
9         "github.com/anacrolix/log"
10
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"
15 )
16
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)
22
23         cfg := TestingConfig(t)
24         cfg.Seed = true
25         cfg.MaxAllocPeerRequestDataPerConn = 4
26         cfg.DataDir = greetingTempDir
27         cfg.DisablePEX = true
28         cfg.Debug = true
29         cfg.AcceptPeerConnections = false
30         //cfg.DisableUTP = true
31         seeder, err := NewClient(cfg)
32         require.NoError(t, err)
33         defer seeder.Close()
34         defer testutil.ExportStatusWriter(seeder, "s", t)()
35         seederTorrent, ok, err := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
36         require.NoError(t, err)
37         assert.True(t, ok)
38         seederTorrent.VerifyData()
39
40         cfg = TestingConfig(t)
41         cfg.Seed = true
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
47         //cfg.Debug = true
48         leecher, err := NewClient(cfg)
49         require.NoError(t, err)
50         defer leecher.Close()
51         defer testutil.ExportStatusWriter(leecher, "l", t)()
52
53         cfg = TestingConfig(t)
54         cfg.Seed = false
55         cfg.DataDir = t.TempDir()
56         cfg.MaxAllocPeerRequestDataPerConn = 4
57         cfg.Debug = true
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)
66                 ret.ChunkSize = 2
67                 return
68         }())
69         _ = leecherGreeting
70         require.NoError(t, err)
71         assert.True(t, ok)
72         llg, ok, err := leecherLeecher.AddTorrentSpec(func() (ret *TorrentSpec) {
73                 ret = TorrentSpecFromMetaInfo(mi)
74                 ret.ChunkSize = 3
75                 return
76         }())
77         require.NoError(t, err)
78         assert.True(t, ok)
79
80         var wg sync.WaitGroup
81         wg.Add(1)
82         go func() {
83                 defer wg.Done()
84                 r := llg.NewReader()
85                 defer r.Close()
86                 qt.Check(t, iotest.TestReader(r, []byte(testutil.GreetingFileContents)), qt.IsNil)
87         }()
88         go seederTorrent.AddClientPeer(leecher)
89         waitForConns(seederTorrent)
90         go llg.AddClientPeer(leecher)
91         waitForConns(llg)
92         time.Sleep(time.Second)
93         llg.cl.lock()
94         targetAddr := seeder.ListenAddrs()[0]
95         log.Printf("trying to initiate to %v", targetAddr)
96         initiateConn(outgoingConnOpts{
97                 peerInfo: PeerInfo{
98                         Addr: targetAddr,
99                 },
100                 t:                       llg,
101                 requireRendezvous:       true,
102                 skipHolepunchRendezvous: false,
103                 HeaderObfuscationPolicy: llg.cl.config.HeaderObfuscationPolicy,
104         }, true)
105         llg.cl.unlock()
106         wg.Wait()
107
108         llClientStats := leecherLeecher.Stats()
109         c.Check(llClientStats.NumPeersDialableOnlyAfterHolepunch, qt.Not(qt.Equals), 0)
110         c.Check(
111                 llClientStats.NumPeersDialableOnlyAfterHolepunch,
112                 qt.Equals,
113                 llClientStats.NumPeersUndialableWithoutHolepunchDialedAfterHolepunchConnect,
114         )
115 }
116
117 func waitForConns(t *Torrent) {
118         t.cl.lock()
119         defer t.cl.unlock()
120         for {
121                 for range t.conns {
122                         return
123                 }
124                 t.cl.event.Wait()
125         }
126 }
127
128 func TestDialTcpNotAccepting(t *testing.T) {
129         l, err := net.Listen("tcp", "localhost:0")
130         c := qt.New(t)
131         c.Check(err, qt.IsNil)
132         defer l.Close()
133         _, err = net.Dial("tcp", l.Addr().String())
134         c.Assert(err, qt.IsNotNil)
135 }