]> Sergey Matveev's repositories - btrtrc.git/blob - ut-holepunching_test.go
a45eb8e591d7154bdf211493ecbac7c6538b2d58
[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.DisableUTP = true
59         leecherLeecher, _ := NewClient(cfg)
60         require.NoError(t, err)
61         defer leecherLeecher.Close()
62         defer testutil.ExportStatusWriter(leecherLeecher, "ll", t)()
63         leecherGreeting, ok, err := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
64                 ret = TorrentSpecFromMetaInfo(mi)
65                 ret.ChunkSize = 2
66                 return
67         }())
68         _ = leecherGreeting
69         require.NoError(t, err)
70         assert.True(t, ok)
71         llg, ok, err := leecherLeecher.AddTorrentSpec(func() (ret *TorrentSpec) {
72                 ret = TorrentSpecFromMetaInfo(mi)
73                 ret.ChunkSize = 3
74                 return
75         }())
76         require.NoError(t, err)
77         assert.True(t, ok)
78
79         var wg sync.WaitGroup
80         wg.Add(1)
81         go func() {
82                 defer wg.Done()
83                 r := llg.NewReader()
84                 defer r.Close()
85                 qt.Check(t, iotest.TestReader(r, []byte(testutil.GreetingFileContents)), qt.IsNil)
86         }()
87         go seederTorrent.AddClientPeer(leecher)
88         waitForConns(seederTorrent)
89         go llg.AddClientPeer(leecher)
90         waitForConns(llg)
91         //time.Sleep(time.Second)
92         llg.cl.lock()
93         targetAddr := seeder.ListenAddrs()[1]
94         log.Printf("trying to initiate to %v", targetAddr)
95         llg.initiateConn(PeerInfo{
96                 Addr: targetAddr,
97         }, true, false, false, false)
98         llg.cl.unlock()
99         wg.Wait()
100         // These checks would require that the leecher leecher first attempt to connect without
101         // holepunching.
102
103         //llClientStats := leecherLeecher.Stats()
104         //c := qt.New(t)
105         //c.Check(llClientStats.NumPeersDialedRequiringHolepunch, qt.Not(qt.Equals), 0)
106         //c.Check(
107         //      llClientStats.NumPeersDialedRequiringHolepunch,
108         //      qt.Equals,
109         //      llClientStats.NumPeersUndiableWithoutHolepunch,
110         //)
111 }
112
113 func waitForConns(t *Torrent) {
114         t.cl.lock()
115         defer t.cl.unlock()
116         for {
117                 for range t.conns {
118                         return
119                 }
120                 t.cl.event.Wait()
121         }
122 }