metainfo/file-tree.go | 9 +++++++++ metainfo/info.go | 8 ++++++-- metainfo/metainfo.go | 10 ++++++---- peer_protocol/handshake.go | 11 +++++++---- peer_protocol/reserved_test.go | 13 +++++++++++++ types/infohash/infohash.go | 8 ++++++++ diff --git a/metainfo/file-tree.go b/metainfo/file-tree.go new file mode 100644 index 0000000000000000000000000000000000000000..0bccb15365cd8e9f6bc92a709304d92a4613eba8 --- /dev/null +++ b/metainfo/file-tree.go @@ -0,0 +1,9 @@ +package metainfo + +type FileTree struct { + File struct { + Length int64 `bencode:"length"` + PiecesRoot string `bencode:"pieces root"` + } + Dir map[string]FileTree +} diff --git a/metainfo/info.go b/metainfo/info.go index 1ee2704ec97b760025eda2a951966a8174665626..5eedfa3b4c41730ddb92543abfb855ad635e27e4 100644 --- a/metainfo/info.go +++ b/metainfo/info.go @@ -11,7 +11,7 @@ "github.com/anacrolix/missinggo/v2/slices" ) -// The info dictionary. +// The info dictionary. See BEP 3 and BEP 52. type Info struct { PieceLength int64 `bencode:"piece length"` // BEP3 Pieces []byte `bencode:"pieces"` // BEP3 @@ -22,6 +22,10 @@ Private *bool `bencode:"private,omitempty"` // BEP27 // TODO: Document this field. Source string `bencode:"source,omitempty"` Files []FileInfo `bencode:"files,omitempty"` // BEP3, mutually exclusive with Length + + // BEP 52 (BitTorrent v2) + MetaVersion int64 `bencode:"meta version,omitempty"` + FileTree FileTree `bencode:"file tree,omitempty"` } // The Info.Name field is "advisory". For multi-file torrents it's usually a suggested directory @@ -157,7 +161,7 @@ func (info *Info) Piece(index int) Piece { return Piece{info, pieceIndex(index)} } -func (info Info) BestName() string { +func (info *Info) BestName() string { if info.NameUtf8 != "" { return info.NameUtf8 } diff --git a/metainfo/metainfo.go b/metainfo/metainfo.go index 93f9103b968b09f661cb3aa9a9a6618a8102cdb6..9f4109899c7a6b54f202a0c14f43cfbcd8806722 100644 --- a/metainfo/metainfo.go +++ b/metainfo/metainfo.go @@ -10,6 +10,7 @@ "github.com/anacrolix/torrent/bencode" ) +// Also known as a torrent file. type MetaInfo struct { InfoBytes bencode.Bytes `bencode:"info,omitempty"` // BEP 3 Announce string `bencode:"announce,omitempty"` // BEP 3 @@ -23,10 +24,12 @@ Comment string `bencode:"comment,omitempty"` CreatedBy string `bencode:"created by,omitempty"` Encoding string `bencode:"encoding,omitempty"` UrlList UrlList `bencode:"url-list,omitempty"` // BEP 19 WebSeeds + // BEP 52 (BitTorrent v2): Keys are file merkle roots (pieces root?), and the values are the + // concatenated hashes of the merkle tree layer that corresponds to the piece length. + PieceLayers map[string]string `bencode:"piece layers,omitempty"` } -// Load a MetaInfo from an io.Reader. Returns a non-nil error in case of -// failure. +// Load a MetaInfo from an io.Reader. Returns a non-nil error in case of failure. func Load(r io.Reader) (*MetaInfo, error) { var mi MetaInfo d := bencode.NewDecoder(r) @@ -85,8 +88,7 @@ m.Params["ws"] = mi.UrlList return } -// Returns the announce list converted from the old single announce field if -// necessary. +// Returns the announce-list converted from the old single announce field if necessary. func (mi *MetaInfo) UpvertedAnnounceList() AnnounceList { if mi.AnnounceList.OverridesAnnounce(mi.Announce) { return mi.AnnounceList diff --git a/peer_protocol/handshake.go b/peer_protocol/handshake.go index a6f648cfe6e16ea3a6b147dd8bd5490a14c57022..bce28340bbe8c60d75c4aa735ae1c42d790a9990 100644 --- a/peer_protocol/handshake.go +++ b/peer_protocol/handshake.go @@ -18,9 +18,12 @@ // https://www.bittorrent.org/beps/bep_0004.html // https://wiki.theory.org/BitTorrentSpecification.html#Reserved_Bytes const ( - ExtensionBitDht = 0 // http://www.bittorrent.org/beps/bep_0005.html - ExtensionBitFast = 2 // http://www.bittorrent.org/beps/bep_0006.html - ExtensionBitV2 = 7 // "Hybrid torrent legacy to v2 upgrade" + ExtensionBitDht = 0 // http://www.bittorrent.org/beps/bep_0005.html + ExtensionBitFast = 2 // http://www.bittorrent.org/beps/bep_0006.html + // A peer connection initiator can set this when sending a v1 infohash during handshake if they + // allow the receiving end to upgrade to v2 by responding with the corresponding v2 infohash. + // BEP 52, and BEP 4 + ExtensionBitV2Upgrade = 4 ExtensionBitAzureusExtensionNegotiation1 = 16 ExtensionBitAzureusExtensionNegotiation2 = 17 // LibTorrent Extension Protocol, http://www.bittorrent.org/beps/bep_0010.html @@ -56,7 +59,7 @@ {ExtensionBitLocationAwareProtocol, "loc"}, {ExtensionBitLtep, "ltep"}, {ExtensionBitAzureusExtensionNegotiation2, "azen2"}, {ExtensionBitAzureusExtensionNegotiation1, "azen1"}, - {ExtensionBitV2, "v2"}, + {ExtensionBitV2Upgrade, "v2"}, {ExtensionBitFast, "fast"}, {ExtensionBitDht, "dht"}, } diff --git a/peer_protocol/reserved_test.go b/peer_protocol/reserved_test.go new file mode 100644 index 0000000000000000000000000000000000000000..8ee3a722779c15cd1ace08eb6fe5fd140c770c62 --- /dev/null +++ b/peer_protocol/reserved_test.go @@ -0,0 +1,13 @@ +package peer_protocol + +import ( + qt "github.com/frankban/quicktest" + "testing" +) + +func TestV2BitLocation(t *testing.T) { + var bits PeerExtensionBits + bits.SetBit(ExtensionBitV2Upgrade, true) + c := qt.New(t) + c.Assert(bits[7], qt.Equals, byte(0x10)) +} diff --git a/testdata/bittorrent-v2-hybrid-test.torrent b/testdata/bittorrent-v2-hybrid-test.torrent new file mode 100644 index 0000000000000000000000000000000000000000..9a5c8762d6cfd0c2ebf61bace1498871aab7a648 Binary files /dev/null and b/testdata/bittorrent-v2-hybrid-test.torrent differ diff --git a/testdata/bittorrent-v2-test.torrent b/testdata/bittorrent-v2-test.torrent new file mode 100644 index 0000000000000000000000000000000000000000..8ad4c7eab07617e0c2b5c53df29c58d629cf3566 Binary files /dev/null and b/testdata/bittorrent-v2-test.torrent differ diff --git a/types/infohash/infohash.go b/types/infohash/infohash.go index 0763b01e0e8c4243e186407a22019b5620ba3f67..c90f7451e45d443d4889904a450c3552bf166cbf 100644 --- a/types/infohash/infohash.go +++ b/types/infohash/infohash.go @@ -2,6 +2,7 @@ package infohash import ( "crypto/sha1" + "crypto/sha256" "encoding" "encoding/hex" "fmt" @@ -78,3 +79,10 @@ hasher.Write(b) copy(ret[:], hasher.Sum(nil)) return } + +func HashBytesV2(b []byte) (ret T) { + hasher := sha256.New() + hasher.Write(b) + copy(ret[:], hasher.Sum(nil)) + return +}