From c28f3014fff23e0d14c4eaf962fcb0ce9d48cb8f Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Fri, 23 Jun 2023 22:14:38 +1000 Subject: [PATCH] Fix UseSources panicking when sqlite storage is closed --- go.mod | 2 +- go.sum | 4 +- storage/interface.go | 1 + storage/sqlite/direct.go | 4 +- storage/test/bench-piece-mark-complete.go | 2 +- test/misc_test.go | 54 +++++++++++++++++++++++ 6 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 test/misc_test.go diff --git a/go.mod b/go.mod index f0eadcc2..2e19887b 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/anacrolix/missinggo/perf v1.0.0 github.com/anacrolix/missinggo/v2 v2.7.2-0.20230527121029-a582b4f397b9 github.com/anacrolix/multiless v0.3.0 - github.com/anacrolix/squirrel v0.4.1-0.20220122230132-14b040773bac + github.com/anacrolix/squirrel v0.4.1-0.20230623120945-75cf0ad9a958 github.com/anacrolix/sync v0.4.0 github.com/anacrolix/tagflag v1.3.0 github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 diff --git a/go.sum b/go.sum index 5ed1f2bf..28ef842a 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,8 @@ github.com/anacrolix/mmsg v1.0.0 h1:btC7YLjOn29aTUAExJiVUhQOuf/8rhm+/nWCMAnL3Hg= github.com/anacrolix/mmsg v1.0.0/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc= github.com/anacrolix/multiless v0.3.0 h1:5Bu0DZncjE4e06b9r1Ap2tUY4Au0NToBP5RpuEngSis= github.com/anacrolix/multiless v0.3.0/go.mod h1:TrCLEZfIDbMVfLoQt5tOoiBS/uq4y8+ojuEVVvTNPX4= -github.com/anacrolix/squirrel v0.4.1-0.20220122230132-14b040773bac h1:eddZTnM9TIy3Z9ARLeDMlUpEjcs0ZdoFMXSG0ChAHvE= -github.com/anacrolix/squirrel v0.4.1-0.20220122230132-14b040773bac/go.mod h1:YzgVvikMdFD441oTWlNG189bpKabO9Sbf3uCSVgca04= +github.com/anacrolix/squirrel v0.4.1-0.20230623120945-75cf0ad9a958 h1:A+tNxHKFCGj/CP8WaQDZC+QwDjjoXUHDByIzKVyzKw4= +github.com/anacrolix/squirrel v0.4.1-0.20230623120945-75cf0ad9a958/go.mod h1:YzgVvikMdFD441oTWlNG189bpKabO9Sbf3uCSVgca04= github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg= github.com/anacrolix/stm v0.4.0 h1:tOGvuFwaBjeu1u9X1eIh9TX8OEedEiEQ1se1FjhFnXY= github.com/anacrolix/stm v0.4.0/go.mod h1:GCkwqWoAsP7RfLW+jw+Z0ovrt2OO7wRzcTtFYMYY5t8= diff --git a/storage/interface.go b/storage/interface.go index b28a52b0..9e8de06c 100644 --- a/storage/interface.go +++ b/storage/interface.go @@ -51,6 +51,7 @@ type PieceImpl interface { type Completion struct { Complete bool Ok bool + Err error } // Allows a storage backend to override hashing (i.e. if it can do it more efficiently than the torrent client can) diff --git a/storage/sqlite/direct.go b/storage/sqlite/direct.go index 3d51fd31..bd656e60 100644 --- a/storage/sqlite/direct.go +++ b/storage/sqlite/direct.go @@ -79,8 +79,6 @@ func (p piece) Completion() (ret storage.Completion) { ret.Complete = stmt.ColumnInt(0) != 0 }) ret.Ok = err == nil - if err != nil { - panic(err) - } + ret.Err = err return } diff --git a/storage/test/bench-piece-mark-complete.go b/storage/test/bench-piece-mark-complete.go index 71b27afc..db0049f2 100644 --- a/storage/test/bench-piece-mark-complete.go +++ b/storage/test/bench-piece-mark-complete.go @@ -66,7 +66,7 @@ func BenchmarkPieceMarkComplete( // This might not apply if users of this benchmark don't cache with the expected capacity. c.Assert(pi.Completion(), qt.Equals, storage.Completion{Complete: false, Ok: true}) c.Assert(pi.MarkComplete(), qt.IsNil) - c.Assert(pi.Completion(), qt.Equals, storage.Completion{true, true}) + c.Assert(pi.Completion(), qt.Equals, storage.Completion{Complete: true, Ok: true}) n, err := pi.WriteTo(bytes.NewBuffer(readData[:0])) b.StopTimer() c.Assert(err, qt.IsNil) diff --git a/test/misc_test.go b/test/misc_test.go new file mode 100644 index 00000000..a72746c8 --- /dev/null +++ b/test/misc_test.go @@ -0,0 +1,54 @@ +package test + +import ( + "net" + "net/http" + "testing" + + qt "github.com/frankban/quicktest" + + "github.com/anacrolix/torrent" + "github.com/anacrolix/torrent/bencode" + "github.com/anacrolix/torrent/metainfo" + sqliteStorage "github.com/anacrolix/torrent/storage/sqlite" +) + +func TestUseSourcesSqliteStorageClosed(t *testing.T) { + c := qt.New(t) + cfg := torrent.TestingConfig(t) + storage, err := sqliteStorage.NewDirectStorage(sqliteStorage.NewDirectStorageOpts{}) + defer storage.Close() + cfg.DefaultStorage = storage + c.Assert(err, qt.IsNil) + cl, err := torrent.NewClient(cfg) + c.Assert(err, qt.IsNil) + defer cl.Close() + l, err := net.Listen("tcp", "localhost:0") + c.Assert(err, qt.IsNil) + defer l.Close() + // We need at least once piece to trigger a call to storage to determine completion state. + i := metainfo.Info{Pieces: make([]byte, metainfo.HashSize)} + mi := metainfo.MetaInfo{} + mi.InfoBytes, err = bencode.Marshal(i) + c.Assert(err, qt.IsNil) + s := http.Server{ + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mi.Write(w) + }), + } + defer s.Close() + go func() { + err := s.Serve(l) + if err != http.ErrServerClosed { + panic(err) + } + }() + // Close storage prematurely. + storage.Close() + tor, _, err := cl.AddTorrentSpec(&torrent.TorrentSpec{ + InfoHash: mi.HashInfoBytes(), + Sources: []string{"http://" + l.Addr().String()}, + }) + c.Assert(err, qt.IsNil) + <-tor.GotInfo() +} -- 2.44.0