reader.go | 4 ++++ test/issue377_test.go | 24 +++++++++++++++++++++++- torrent.go | 3 +++ diff --git a/reader.go b/reader.go index 1f68fdbe6c94e658acbc44a5a37048748e47ddf4..1e1c36e120eaa8df583869cd3ed2a0898998fbd3 100644 --- a/reader.go +++ b/reader.go @@ -199,6 +199,10 @@ if *ctxErr != nil { err = *ctxErr return } + if r.t.dataDownloadDisallowed || !r.t.networkingEnabled { + err = errors.New("downloading disabled and data not already available") + return + } if !wait { return } diff --git a/test/issue377_test.go b/test/issue377_test.go index abc57a9051b1841534ff213b19bc5ff11af12fc5..05ef14292c3d75c8afa91ea0b31d642943de4a5b 100644 --- a/test/issue377_test.go +++ b/test/issue377_test.go @@ -2,6 +2,8 @@ package test import ( "errors" + "io" + "io/ioutil" "os" "sync" "testing" @@ -73,7 +75,27 @@ require.NoError(t, err) // Tell the seeder to find the leecher. Is it guaranteed seeders will always try to do this? seederTorrent.AddClientPeer(leecherClient) <-leecherTorrent.GotInfo() - assertReadAllGreeting(t, leecherTorrent.NewReader()) + r := leecherTorrent.Files()[0].NewReader() + defer r.Close() + // We can't use assertReadAllGreeting here, because the default storage write error handler + // disables data downloads, which now causes Readers to error when they're blocked. + if false { + assertReadAllGreeting(t, leecherTorrent.NewReader()) + } else { + for func() bool { + // We don't seem to need to seek, but that's probably just because the storage failure is + // happening on the first read. + r.Seek(0, io.SeekStart) + output, err := ioutil.ReadAll(r) + if err != nil { + t.Logf("got error while reading: %v", err) + return true + } + assert.EqualValues(t, testutil.GreetingFileContents, output) + return false + }() { + } + } // TODO: Check that PeerConns fastEnabled matches seederFast? //select {} } diff --git a/torrent.go b/torrent.go index ace386eb3fce410cde0a57bf9742fea57e21ee0e..561d3d60bbd9ef265af1f748d19f6b5ca1a9dd24 100644 --- a/torrent.go +++ b/torrent.go @@ -2024,6 +2024,7 @@ if t.userOnWriteChunkErr != nil { go t.userOnWriteChunkErr(err) return } + t.logger.WithDefaultLevel(log.Critical).Printf("default chunk write error handler: disabling data download") t.disallowDataDownloadLocked() } @@ -2038,12 +2039,14 @@ t.dataDownloadDisallowed = true t.iterPeers(func(c *peer) { c.updateRequests() }) + t.tickleReaders() } func (t *Torrent) AllowDataDownload() { t.cl.lock() defer t.cl.unlock() t.dataDownloadDisallowed = false + t.tickleReaders() t.iterPeers(func(c *peer) { c.updateRequests() })