17 "github.com/anacrolix/dht/v2"
18 "github.com/anacrolix/log"
19 "github.com/anacrolix/missinggo/v2"
20 "github.com/anacrolix/missinggo/v2/filecache"
21 "github.com/frankban/quicktest"
22 qt "github.com/frankban/quicktest"
23 "github.com/stretchr/testify/assert"
24 "github.com/stretchr/testify/require"
26 "github.com/anacrolix/torrent/bencode"
27 "github.com/anacrolix/torrent/internal/testutil"
28 "github.com/anacrolix/torrent/iplist"
29 "github.com/anacrolix/torrent/metainfo"
30 "github.com/anacrolix/torrent/storage"
33 func TestClientDefault(t *testing.T) {
34 cl, err := NewClient(TestingConfig(t))
35 require.NoError(t, err)
36 require.Empty(t, cl.Close())
39 func TestClientNilConfig(t *testing.T) {
40 // The default config will put crap in the working directory.
41 origDir, _ := os.Getwd()
42 defer os.Chdir(origDir)
44 cl, err := NewClient(nil)
45 require.NoError(t, err)
46 require.Empty(t, cl.Close())
49 func TestAddDropTorrent(t *testing.T) {
50 cl, err := NewClient(TestingConfig(t))
51 require.NoError(t, err)
53 dir, mi := testutil.GreetingTestTorrent()
54 defer os.RemoveAll(dir)
55 tt, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
56 require.NoError(t, err)
58 tt.SetMaxEstablishedConns(0)
59 tt.SetMaxEstablishedConns(1)
63 func TestAddTorrentNoSupportedTrackerSchemes(t *testing.T) {
68 func TestAddTorrentNoUsableURLs(t *testing.T) {
73 func TestAddPeersToUnknownTorrent(t *testing.T) {
78 func TestPieceHashSize(t *testing.T) {
79 assert.Equal(t, 20, pieceHash.Size())
82 func TestTorrentInitialState(t *testing.T) {
83 dir, mi := testutil.GreetingTestTorrent()
84 defer os.RemoveAll(dir)
86 cl.init(TestingConfig(t))
90 storage.NewFileWithCompletion(t.TempDir(), storage.NewMapPieceCompletion()),
94 err := tor.setInfoBytesLocked(mi.InfoBytes)
96 require.NoError(t, err)
97 require.Len(t, tor.pieces, 3)
98 tor.pendAllChunkSpecs(0)
100 assert.EqualValues(t, 3, tor.pieceNumPendingChunks(0))
102 assert.EqualValues(t, ChunkSpec{4, 1}, chunkIndexSpec(2, tor.pieceLength(0), tor.chunkSize))
105 func TestReducedDialTimeout(t *testing.T) {
106 cfg := NewDefaultClientConfig()
107 for _, _case := range []struct {
111 ExpectedReduced time.Duration
113 {cfg.NominalDialTimeout, 40, 0, cfg.NominalDialTimeout},
114 {cfg.NominalDialTimeout, 40, 1, cfg.NominalDialTimeout},
115 {cfg.NominalDialTimeout, 40, 39, cfg.NominalDialTimeout},
116 {cfg.NominalDialTimeout, 40, 40, cfg.NominalDialTimeout / 2},
117 {cfg.NominalDialTimeout, 40, 80, cfg.NominalDialTimeout / 3},
118 {cfg.NominalDialTimeout, 40, 4000, cfg.NominalDialTimeout / 101},
120 reduced := reducedDialTimeout(cfg.MinDialTimeout, _case.Max, _case.HalfOpenLimit, _case.PendingPeers)
121 expected := _case.ExpectedReduced
122 if expected < cfg.MinDialTimeout {
123 expected = cfg.MinDialTimeout
125 if reduced != expected {
126 t.Fatalf("expected %s, got %s", _case.ExpectedReduced, reduced)
131 func TestAddDropManyTorrents(t *testing.T) {
132 cl, err := NewClient(TestingConfig(t))
133 require.NoError(t, err)
135 for i := range 1000 {
137 binary.PutVarint(spec.InfoHash[:], int64(i+1))
138 tt, new, err := cl.AddTorrentSpec(&spec)
139 assert.NoError(t, err)
145 func fileCachePieceResourceStorage(fc *filecache.Cache) storage.ClientImpl {
146 return storage.NewResourcePiecesOpts(
147 fc.AsResourceProvider(),
148 storage.ResourcePiecesOpts{
149 LeaveIncompleteChunks: true,
154 func TestMergingTrackersByAddingSpecs(t *testing.T) {
155 cl, err := NewClient(TestingConfig(t))
156 require.NoError(t, err)
158 spec := TorrentSpec{}
159 rand.Read(spec.InfoHash[:])
160 T, new, _ := cl.AddTorrentSpec(&spec)
164 spec.Trackers = [][]string{{"http://a"}, {"udp://b"}}
165 _, new, _ = cl.AddTorrentSpec(&spec)
167 assert.EqualValues(t, [][]string{{"http://a"}, {"udp://b"}}, T.metainfo.AnnounceList)
168 // Because trackers are disabled in TestingConfig.
169 assert.EqualValues(t, 0, len(T.trackerAnnouncers))
172 // We read from a piece which is marked completed, but is missing data.
173 func TestCompletedPieceWrongSize(t *testing.T) {
174 cfg := TestingConfig(t)
175 cfg.DefaultStorage = badStorage{}
176 cl, err := NewClient(cfg)
177 require.NoError(t, err)
179 info := metainfo.Info{
181 Pieces: make([]byte, 20),
182 Files: []metainfo.FileInfo{
183 {Path: []string{"greeting"}, Length: 13},
186 b, err := bencode.Marshal(info)
187 require.NoError(t, err)
188 tt, new, err := cl.AddTorrentSpec(&TorrentSpec{
190 InfoHash: metainfo.HashBytes(b),
192 require.NoError(t, err)
197 quicktest.Check(t, iotest.TestReader(r, []byte(testutil.GreetingFileContents)), quicktest.IsNil)
200 func BenchmarkAddLargeTorrent(b *testing.B) {
201 cfg := TestingConfig(b)
202 cfg.DisableTCP = true
203 cfg.DisableUTP = true
204 cl, err := NewClient(cfg)
205 require.NoError(b, err)
208 for i := 0; i < b.N; i += 1 {
209 t, err := cl.AddTorrentFromFile("testdata/bootstrap.dat.torrent")
217 func TestResponsive(t *testing.T) {
218 seederDataDir, mi := testutil.GreetingTestTorrent()
219 defer os.RemoveAll(seederDataDir)
220 cfg := TestingConfig(t)
222 cfg.DataDir = seederDataDir
223 seeder, err := NewClient(cfg)
226 seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
227 seederTorrent.VerifyData()
228 leecherDataDir := t.TempDir()
229 cfg = TestingConfig(t)
230 cfg.DataDir = leecherDataDir
231 leecher, err := NewClient(cfg)
233 defer leecher.Close()
234 leecherTorrent, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
235 ret = TorrentSpecFromMetaInfo(mi)
239 leecherTorrent.AddClientPeer(seeder)
240 reader := leecherTorrent.NewReader()
242 reader.SetReadahead(0)
243 reader.SetResponsive()
245 _, err = reader.Seek(3, io.SeekStart)
246 require.NoError(t, err)
247 _, err = io.ReadFull(reader, b)
249 assert.EqualValues(t, "lo", string(b))
250 _, err = reader.Seek(11, io.SeekStart)
251 require.NoError(t, err)
252 n, err := io.ReadFull(reader, b)
254 assert.EqualValues(t, 2, n)
255 assert.EqualValues(t, "d\n", string(b))
258 // TestResponsive was the first test to fail if uTP is disabled and TCP sockets dial from the
260 func TestResponsiveTcpOnly(t *testing.T) {
261 seederDataDir, mi := testutil.GreetingTestTorrent()
262 defer os.RemoveAll(seederDataDir)
263 cfg := TestingConfig(t)
264 cfg.DisableUTP = true
266 cfg.DataDir = seederDataDir
267 seeder, err := NewClient(cfg)
270 seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
271 seederTorrent.VerifyData()
272 leecherDataDir := t.TempDir()
273 cfg = TestingConfig(t)
274 cfg.DataDir = leecherDataDir
275 leecher, err := NewClient(cfg)
277 defer leecher.Close()
278 leecherTorrent, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
279 ret = TorrentSpecFromMetaInfo(mi)
283 leecherTorrent.AddClientPeer(seeder)
284 reader := leecherTorrent.NewReader()
286 reader.SetReadahead(0)
287 reader.SetResponsive()
289 _, err = reader.Seek(3, io.SeekStart)
290 require.NoError(t, err)
291 _, err = io.ReadFull(reader, b)
293 assert.EqualValues(t, "lo", string(b))
294 _, err = reader.Seek(11, io.SeekStart)
295 require.NoError(t, err)
296 n, err := io.ReadFull(reader, b)
298 assert.EqualValues(t, 2, n)
299 assert.EqualValues(t, "d\n", string(b))
302 func TestTorrentDroppedDuringResponsiveRead(t *testing.T) {
303 seederDataDir, mi := testutil.GreetingTestTorrent()
304 defer os.RemoveAll(seederDataDir)
305 cfg := TestingConfig(t)
307 cfg.DataDir = seederDataDir
308 seeder, err := NewClient(cfg)
311 seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
312 seederTorrent.VerifyData()
313 leecherDataDir := t.TempDir()
314 cfg = TestingConfig(t)
315 cfg.DataDir = leecherDataDir
316 leecher, err := NewClient(cfg)
318 defer leecher.Close()
319 leecherTorrent, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
320 ret = TorrentSpecFromMetaInfo(mi)
324 leecherTorrent.AddClientPeer(seeder)
325 reader := leecherTorrent.NewReader()
327 reader.SetReadahead(0)
328 reader.SetResponsive()
330 _, err = reader.Seek(3, io.SeekStart)
331 require.NoError(t, err)
332 _, err = io.ReadFull(reader, b)
334 assert.EqualValues(t, "lo", string(b))
335 _, err = reader.Seek(11, io.SeekStart)
336 require.NoError(t, err)
337 leecherTorrent.Drop()
338 n, err := reader.Read(b)
339 assert.EqualError(t, err, "torrent closed")
340 assert.EqualValues(t, 0, n)
343 func TestDhtInheritBlocklist(t *testing.T) {
345 ipl := iplist.New(nil)
346 require.NotNil(t, ipl)
347 cfg := TestingConfig(t)
348 cfg.IPBlocklist = ipl
350 cl, err := NewClient(cfg)
351 require.NoError(t, err)
354 cl.eachDhtServer(func(s DhtServer) {
356 assert.Equal(t, ipl, s.(AnacrolixDhtServerWrapper).Server.IPBlocklist())
359 c.Assert(numServers, qt.Not(qt.Equals), 0)
362 // Check that stuff is merged in subsequent AddTorrentSpec for the same
364 func TestAddTorrentSpecMerging(t *testing.T) {
365 cl, err := NewClient(TestingConfig(t))
366 require.NoError(t, err)
368 dir, mi := testutil.GreetingTestTorrent()
369 defer os.RemoveAll(dir)
370 tt, new, err := cl.AddTorrentSpec(&TorrentSpec{
371 InfoHash: mi.HashInfoBytes(),
373 require.NoError(t, err)
375 require.Nil(t, tt.Info())
376 _, new, err = cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
377 require.NoError(t, err)
378 require.False(t, new)
379 require.NotNil(t, tt.Info())
382 func TestTorrentDroppedBeforeGotInfo(t *testing.T) {
383 dir, mi := testutil.GreetingTestTorrent()
385 cl, _ := NewClient(TestingConfig(t))
387 tt, _, _ := cl.AddTorrentSpec(&TorrentSpec{
388 InfoHash: mi.HashInfoBytes(),
391 assert.EqualValues(t, 0, len(cl.Torrents()))
399 func writeTorrentData(ts *storage.Torrent, info metainfo.Info, b []byte) {
400 for i := 0; i < info.NumPieces(); i += 1 {
402 ts.Piece(p).WriteAt(b[p.Offset():p.Offset()+p.Length()], 0)
406 func testAddTorrentPriorPieceCompletion(t *testing.T, alreadyCompleted bool, csf func(*filecache.Cache) storage.ClientImpl) {
407 fileCacheDir := t.TempDir()
408 fileCache, err := filecache.NewCache(fileCacheDir)
409 require.NoError(t, err)
410 greetingDataTempDir, greetingMetainfo := testutil.GreetingTestTorrent()
411 defer os.RemoveAll(greetingDataTempDir)
412 filePieceStore := csf(fileCache)
413 info, err := greetingMetainfo.UnmarshalInfo()
414 require.NoError(t, err)
415 ih := greetingMetainfo.HashInfoBytes()
416 greetingData, err := storage.NewClient(filePieceStore).OpenTorrent(&info, ih)
417 require.NoError(t, err)
418 writeTorrentData(greetingData, info, []byte(testutil.GreetingFileContents))
419 // require.Equal(t, len(testutil.GreetingFileContents), written)
420 // require.NoError(t, err)
421 for i := 0; i < info.NumPieces(); i++ {
423 if alreadyCompleted {
424 require.NoError(t, greetingData.Piece(p).MarkComplete())
427 cfg := TestingConfig(t)
428 // TODO: Disable network option?
429 cfg.DisableTCP = true
430 cfg.DisableUTP = true
431 cfg.DefaultStorage = filePieceStore
432 cl, err := NewClient(cfg)
433 require.NoError(t, err)
435 tt, err := cl.AddTorrent(greetingMetainfo)
436 require.NoError(t, err)
437 psrs := tt.PieceStateRuns()
438 assert.Len(t, psrs, 1)
439 assert.EqualValues(t, 3, psrs[0].Length)
440 assert.Equal(t, alreadyCompleted, psrs[0].Complete)
441 if alreadyCompleted {
443 quicktest.Check(t, iotest.TestReader(r, []byte(testutil.GreetingFileContents)), quicktest.IsNil)
447 func TestAddTorrentPiecesAlreadyCompleted(t *testing.T) {
448 testAddTorrentPriorPieceCompletion(t, true, fileCachePieceResourceStorage)
451 func TestAddTorrentPiecesNotAlreadyCompleted(t *testing.T) {
452 testAddTorrentPriorPieceCompletion(t, false, fileCachePieceResourceStorage)
455 func TestAddMetainfoWithNodes(t *testing.T) {
456 cfg := TestingConfig(t)
457 cfg.ListenHost = func(string) string { return "" }
459 cfg.DhtStartingNodes = func(string) dht.StartingNodesGetter { return func() ([]dht.Addr, error) { return nil, nil } }
460 // For now, we want to just jam the nodes into the table, without verifying them first. Also the
461 // DHT code doesn't support mixing secure and insecure nodes if security is enabled (yet).
462 // cfg.DHTConfig.NoSecurity = true
463 cl, err := NewClient(cfg)
464 require.NoError(t, err)
466 sum := func() (ret int64) {
467 cl.eachDhtServer(func(s DhtServer) {
468 ret += s.Stats().(dht.ServerStats).OutboundQueriesAttempted
472 assert.EqualValues(t, 0, sum())
473 tt, err := cl.AddTorrentFromFile("metainfo/testdata/issue_65a.torrent")
474 require.NoError(t, err)
475 // Nodes are not added or exposed in Torrent's metainfo. We just randomly
476 // check if the announce-list is here instead. TODO: Add nodes.
477 assert.Len(t, tt.metainfo.AnnounceList, 5)
478 // There are 6 nodes in the torrent file.
479 for sum() != int64(6*len(cl.dhtServers)) {
480 time.Sleep(time.Millisecond)
484 type testDownloadCancelParams struct {
485 SetLeecherStorageCapacity bool
486 LeecherStorageCapacity int64
490 func testDownloadCancel(t *testing.T, ps testDownloadCancelParams) {
491 greetingTempDir, mi := testutil.GreetingTestTorrent()
492 defer os.RemoveAll(greetingTempDir)
493 cfg := TestingConfig(t)
495 cfg.DataDir = greetingTempDir
496 seeder, err := NewClient(cfg)
497 require.NoError(t, err)
499 defer testutil.ExportStatusWriter(seeder, "s", t)()
500 seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
501 seederTorrent.VerifyData()
502 leecherDataDir := t.TempDir()
503 fc, err := filecache.NewCache(leecherDataDir)
504 require.NoError(t, err)
505 if ps.SetLeecherStorageCapacity {
506 fc.SetCapacity(ps.LeecherStorageCapacity)
508 cfg.DefaultStorage = storage.NewResourcePieces(fc.AsResourceProvider())
509 cfg.DataDir = leecherDataDir
510 leecher, err := NewClient(cfg)
511 require.NoError(t, err)
512 defer leecher.Close()
513 defer testutil.ExportStatusWriter(leecher, "l", t)()
514 leecherGreeting, new, err := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
515 ret = TorrentSpecFromMetaInfo(mi)
519 require.NoError(t, err)
521 psc := leecherGreeting.SubscribePieceStateChanges()
524 leecherGreeting.cl.lock()
525 leecherGreeting.downloadPiecesLocked(0, leecherGreeting.numPieces())
527 leecherGreeting.cancelPiecesLocked(0, leecherGreeting.NumPieces(), "")
529 leecherGreeting.cl.unlock()
530 done := make(chan struct{})
532 go leecherGreeting.AddClientPeer(seeder)
533 completes := make(map[int]bool, 3)
534 expected := func() map[int]bool {
536 return map[int]bool{0: false, 1: false, 2: false}
538 return map[int]bool{0: true, 1: true, 2: true}
541 for !reflect.DeepEqual(completes, expected) {
543 completes[v.Index] = v.Complete
547 func TestTorrentDownloadAll(t *testing.T) {
548 testDownloadCancel(t, testDownloadCancelParams{})
551 func TestTorrentDownloadAllThenCancel(t *testing.T) {
552 testDownloadCancel(t, testDownloadCancelParams{
557 // Ensure that it's an error for a peer to send an invalid have message.
558 func TestPeerInvalidHave(t *testing.T) {
559 cfg := TestingConfig(t)
560 cfg.DropMutuallyCompletePeers = false
561 cl, err := NewClient(cfg)
562 require.NoError(t, err)
564 info := metainfo.Info{
566 Pieces: make([]byte, 20),
567 Files: []metainfo.FileInfo{{Length: 1}},
569 infoBytes, err := bencode.Marshal(info)
570 require.NoError(t, err)
571 tt, _new, err := cl.AddTorrentSpec(&TorrentSpec{
572 InfoBytes: infoBytes,
573 InfoHash: metainfo.HashBytes(infoBytes),
574 Storage: badStorage{},
576 require.NoError(t, err)
579 cn := &PeerConn{Peer: Peer{
581 callbacks: &cfg.Callbacks,
583 tt.conns[cn] = struct{}{}
587 assert.NoError(t, cn.peerSentHave(0))
588 assert.Error(t, cn.peerSentHave(1))
591 func TestPieceCompletedInStorageButNotClient(t *testing.T) {
593 greetingTempDir, greetingMetainfo := testutil.GreetingTestTorrent()
594 defer os.RemoveAll(greetingTempDir)
595 cfg := TestingConfig(t)
596 cfg.DataDir = greetingTempDir
597 seeder, err := NewClient(TestingConfig(t))
598 require.NoError(t, err)
600 _, new, err := seeder.AddTorrentSpec(&TorrentSpec{
601 InfoBytes: greetingMetainfo.InfoBytes,
602 InfoHash: greetingMetainfo.HashInfoBytes(),
604 c.Check(err, qt.IsNil)
605 c.Check(new, qt.IsTrue)
608 // Check that when the listen port is 0, all the protocols listened on have
609 // the same port, and it isn't zero.
610 func TestClientDynamicListenPortAllProtocols(t *testing.T) {
611 cl, err := NewClient(TestingConfig(t))
612 require.NoError(t, err)
614 port := cl.LocalPort()
615 assert.NotEqual(t, 0, port)
616 cl.eachListener(func(s Listener) bool {
617 assert.Equal(t, port, missinggo.AddrPort(s.Addr()))
622 func TestClientDynamicListenTCPOnly(t *testing.T) {
623 cfg := TestingConfig(t)
624 cfg.DisableUTP = true
625 cfg.DisableTCP = false
626 cl, err := NewClient(cfg)
627 require.NoError(t, err)
629 assert.NotEqual(t, 0, cl.LocalPort())
632 func TestClientDynamicListenUTPOnly(t *testing.T) {
633 cfg := TestingConfig(t)
634 cfg.DisableTCP = true
635 cfg.DisableUTP = false
636 cl, err := NewClient(cfg)
637 require.NoError(t, err)
639 assert.NotEqual(t, 0, cl.LocalPort())
642 func totalConns(tts []*Torrent) (ret int) {
643 for _, tt := range tts {
651 func TestSetMaxEstablishedConn(t *testing.T) {
653 ih := testutil.GreetingMetaInfo().HashInfoBytes()
654 cfg := TestingConfig(t)
655 cfg.DisableAcceptRateLimiting = true
656 cfg.DropDuplicatePeerIds = true
657 for i := 0; i < 3; i += 1 {
658 cl, err := NewClient(cfg)
659 require.NoError(t, err)
661 tt, _ := cl.AddTorrentInfoHash(ih)
662 tt.SetMaxEstablishedConns(2)
663 defer testutil.ExportStatusWriter(cl, fmt.Sprintf("%d", i), t)()
664 tts = append(tts, tt)
667 for _, tt := range tts {
668 for _, _tt := range tts {
670 tt.AddClientPeer(_tt.cl)
675 waitTotalConns := func(num int) {
676 for totalConns(tts) != num {
678 time.Sleep(time.Millisecond)
683 tts[0].SetMaxEstablishedConns(1)
685 tts[0].SetMaxEstablishedConns(0)
687 tts[0].SetMaxEstablishedConns(1)
690 tts[0].SetMaxEstablishedConns(2)
695 // Creates a file containing its own name as data. Make a metainfo from that, adds it to the given
696 // client, and returns a magnet link.
697 func makeMagnet(t *testing.T, cl *Client, dir, name string) string {
698 os.MkdirAll(dir, 0o770)
699 file, err := os.Create(filepath.Join(dir, name))
700 require.NoError(t, err)
701 file.Write([]byte(name))
703 mi := metainfo.MetaInfo{}
705 info := metainfo.Info{PieceLength: 256 * 1024}
706 err = info.BuildFromFilePath(filepath.Join(dir, name))
707 require.NoError(t, err)
708 mi.InfoBytes, err = bencode.Marshal(info)
709 require.NoError(t, err)
710 magnet := mi.Magnet(nil, &info).String()
711 tr, err := cl.AddTorrent(&mi)
712 require.NoError(t, err)
713 require.True(t, tr.Seeding())
718 // https://github.com/anacrolix/torrent/issues/114
719 func TestMultipleTorrentsWithEncryption(t *testing.T) {
720 testSeederLeecherPair(
722 func(cfg *ClientConfig) {
723 cfg.HeaderObfuscationPolicy.Preferred = true
724 cfg.HeaderObfuscationPolicy.RequirePreferred = true
726 func(cfg *ClientConfig) {
727 cfg.HeaderObfuscationPolicy.RequirePreferred = false
732 // Test that the leecher can download a torrent in its entirety from the seeder. Note that the
733 // seeder config is done first.
734 func testSeederLeecherPair(t *testing.T, seeder, leecher func(*ClientConfig)) {
735 cfg := TestingConfig(t)
737 cfg.DataDir = filepath.Join(cfg.DataDir, "server")
738 os.Mkdir(cfg.DataDir, 0o755)
740 server, err := NewClient(cfg)
741 require.NoError(t, err)
743 defer testutil.ExportStatusWriter(server, "s", t)()
744 magnet1 := makeMagnet(t, server, cfg.DataDir, "test1")
745 // Extra torrents are added to test the seeder having to match incoming obfuscated headers
746 // against more than one torrent. See issue #114
747 makeMagnet(t, server, cfg.DataDir, "test2")
748 for i := 0; i < 100; i++ {
749 makeMagnet(t, server, cfg.DataDir, fmt.Sprintf("test%d", i+2))
751 cfg = TestingConfig(t)
752 cfg.DataDir = filepath.Join(cfg.DataDir, "client")
754 client, err := NewClient(cfg)
755 require.NoError(t, err)
757 defer testutil.ExportStatusWriter(client, "c", t)()
758 tr, err := client.AddMagnet(magnet1)
759 require.NoError(t, err)
760 tr.AddClientPeer(server)
766 // This appears to be the situation with the S3 BitTorrent client.
767 func TestObfuscatedHeaderFallbackSeederDisallowsLeecherPrefers(t *testing.T) {
768 // Leecher prefers obfuscation, but the seeder does not allow it.
769 testSeederLeecherPair(
771 func(cfg *ClientConfig) {
772 cfg.HeaderObfuscationPolicy.Preferred = false
773 cfg.HeaderObfuscationPolicy.RequirePreferred = true
775 func(cfg *ClientConfig) {
776 cfg.HeaderObfuscationPolicy.Preferred = true
777 cfg.HeaderObfuscationPolicy.RequirePreferred = false
782 func TestObfuscatedHeaderFallbackSeederRequiresLeecherPrefersNot(t *testing.T) {
783 // Leecher prefers no obfuscation, but the seeder enforces it.
784 testSeederLeecherPair(
786 func(cfg *ClientConfig) {
787 cfg.HeaderObfuscationPolicy.Preferred = true
788 cfg.HeaderObfuscationPolicy.RequirePreferred = true
790 func(cfg *ClientConfig) {
791 cfg.HeaderObfuscationPolicy.Preferred = false
792 cfg.HeaderObfuscationPolicy.RequirePreferred = false
797 func TestClientAddressInUse(t *testing.T) {
798 s, _ := NewUtpSocket("udp", "localhost:50007", nil, log.Default)
802 cfg := TestingConfig(t).SetListenAddr("localhost:50007")
803 cfg.DisableUTP = false
804 cl, err := NewClient(cfg)
806 assert.Nil(t, cl.Close())
808 require.Error(t, err)
812 func TestClientHasDhtServersWhenUtpDisabled(t *testing.T) {
813 cc := TestingConfig(t)
816 cl, err := NewClient(cc)
817 require.NoError(t, err)
819 assert.NotEmpty(t, cl.DhtServers())
822 func TestClientDisabledImplicitNetworksButDhtEnabled(t *testing.T) {
823 cfg := TestingConfig(t)
824 cfg.DisableTCP = true
825 cfg.DisableUTP = true
827 cl, err := NewClient(cfg)
828 require.NoError(t, err)
830 assert.Empty(t, cl.listeners)
831 assert.NotEmpty(t, cl.DhtServers())
834 func TestBadPeerIpPort(t *testing.T) {
835 for _, tc := range []struct {
842 {"empty both", nil, 0, true, func(*Client) {}},
843 {"empty/nil ip", nil, 6666, true, func(*Client) {}},
846 net.ParseIP("127.0.0.1/32"),
851 "in doppleganger addresses",
852 net.ParseIP("127.0.0.1/32"),
856 cl.dopplegangerAddrs["10.0.0.1:2322"] = struct{}{}
861 net.ParseIP("10.0.0.1"),
865 cl.ipBlockList = iplist.New([]iplist.Range{
866 {First: net.ParseIP("10.0.0.1"), Last: net.ParseIP("10.0.0.255")},
872 net.ParseIP("10.0.0.1"),
876 ipAddr, ok := netip.AddrFromSlice(net.ParseIP("10.0.0.1"))
878 cl.badPeerIPs = map[netip.Addr]struct{}{}
879 cl.badPeerIPs[ipAddr] = struct{}{}
884 net.ParseIP("10.0.0.1"),
890 t.Run(tc.title, func(t *testing.T) {
891 cfg := TestingConfig(t)
892 cfg.DisableTCP = true
893 cfg.DisableUTP = true
895 cl, err := NewClient(cfg)
896 require.NoError(t, err)
900 require.Equal(t, tc.expectedOk, cl.badPeerIPPort(tc.ip, tc.port))
905 // https://github.com/anacrolix/torrent/issues/837
906 func TestClientConfigSetHandlerNotIgnored(t *testing.T) {
907 cfg := TestingConfig(t)
908 cfg.Logger.SetHandlers(log.DiscardHandler)
910 cl, err := NewClient(cfg)
911 c.Assert(err, qt.IsNil)
913 c.Assert(cl.logger.Handlers, qt.HasLen, 1)
914 h := cl.logger.Handlers[0].(log.StreamHandler)
915 c.Check(h.W, qt.Equals, io.Discard)