4 "bitbucket.org/anacrolix/go.torrent/mmap_span"
5 "bitbucket.org/anacrolix/go.torrent/peer_protocol"
8 "github.com/anacrolix/libtorgo/metainfo"
17 pieceHash = crypto.SHA1
18 maxRequests = 250 // Maximum pending requests we allow peers to send us.
19 chunkSize = 0x4000 // 16KiB
20 BEP20 = "-GT0000-" // Peer ID client identifier prefix
21 dialTimeout = time.Second * 15
24 type InfoHash [20]byte
26 type pieceSum [20]byte
28 func copyHashSum(dst, src []byte) {
29 if len(dst) != len(src) || copy(dst, src) != len(dst) {
30 panic("hash sum sizes differ")
34 func BytesInfoHash(b []byte) (ih InfoHash) {
35 if len(b) != len(ih) || copy(ih[:], b) != len(ih) {
36 panic("bad infohash bytes")
43 PendingChunkSpecs map[chunkSpec]struct{}
49 func (p *piece) shuffledPendingChunkSpecs() (css []chunkSpec) {
50 css = make([]chunkSpec, 0, len(p.PendingChunkSpecs))
51 for cs := range p.PendingChunkSpecs {
56 css[i], css[j] = css[j], css[i]
61 func (p *piece) Complete() bool {
62 return len(p.PendingChunkSpecs) == 0 && p.EverHashed
65 func lastChunkSpec(pieceLength peer_protocol.Integer) (cs chunkSpec) {
66 cs.Begin = (pieceLength - 1) / chunkSize * chunkSize
67 cs.Length = pieceLength - cs.Begin
71 type chunkSpec struct {
72 Begin, Length peer_protocol.Integer
76 Index peer_protocol.Integer
80 func newRequest(index, begin, length peer_protocol.Integer) request {
81 return request{index, chunkSpec{begin, length}}
84 type pieceByBytesPendingSlice struct {
85 Pending, Indices []peer_protocol.Integer
88 func (pcs pieceByBytesPendingSlice) Len() int {
89 return len(pcs.Indices)
92 func (me pieceByBytesPendingSlice) Less(i, j int) bool {
93 return me.Pending[me.Indices[i]] < me.Pending[me.Indices[j]]
96 func (me pieceByBytesPendingSlice) Swap(i, j int) {
97 me.Indices[i], me.Indices[j] = me.Indices[j], me.Indices[i]
101 // Requested data not yet available.
102 ErrDataNotReady = errors.New("data not ready")
105 func upvertedSingleFileInfoFiles(info *metainfo.Info) []metainfo.FileInfo {
106 if len(info.Files) != 0 {
109 return []metainfo.FileInfo{{Length: info.Length, Path: nil}}
112 func mmapTorrentData(md *metainfo.Info, location string) (mms mmap_span.MMapSpan, err error) {
119 for _, miFile := range upvertedSingleFileInfoFiles(md) {
120 fileName := filepath.Join(append([]string{location, md.Name}, miFile.Path...)...)
121 err = os.MkdirAll(filepath.Dir(fileName), 0777)
126 file, err = os.OpenFile(fileName, os.O_CREATE|os.O_RDWR, 0666)
133 fi, err = file.Stat()
137 if fi.Size() < miFile.Length {
138 err = file.Truncate(miFile.Length)
144 mMap, err = gommap.MapRegion(file.Fd(), 0, miFile.Length, gommap.PROT_READ|gommap.PROT_WRITE, gommap.MAP_SHARED)
148 if int64(len(mMap)) != miFile.Length {
149 panic("mmap has wrong length")
151 mms = append(mms, mMap)
160 func metadataPieceSize(totalSize int, piece int) int {
161 ret := totalSize - piece*(1<<14)