]> Sergey Matveev's repositories - btrtrc.git/blob - misc.go
Use metainfo.Hash for piece and info hashes
[btrtrc.git] / misc.go
1 package torrent
2
3 import (
4         "crypto"
5         "errors"
6         "time"
7
8         "github.com/anacrolix/torrent/metainfo"
9         pp "github.com/anacrolix/torrent/peer_protocol"
10 )
11
12 const (
13         pieceHash        = crypto.SHA1
14         maxRequests      = 250    // Maximum pending requests we allow peers to send us.
15         defaultChunkSize = 0x4000 // 16KiB
16         // Peer ID client identifier prefix. We'll update this occasionally to
17         // reflect changes to client behaviour that other clients may depend on.
18         // Also see `extendedHandshakeClientVersion`.
19         bep20              = "-GT0001-"
20         nominalDialTimeout = time.Second * 30
21         minDialTimeout     = 5 * time.Second
22 )
23
24 func lastChunkSpec(pieceLength, chunkSize pp.Integer) (cs chunkSpec) {
25         cs.Begin = (pieceLength - 1) / chunkSize * chunkSize
26         cs.Length = pieceLength - cs.Begin
27         return
28 }
29
30 type chunkSpec struct {
31         Begin, Length pp.Integer
32 }
33
34 type request struct {
35         Index pp.Integer
36         chunkSpec
37 }
38
39 func newRequest(index, begin, length pp.Integer) request {
40         return request{index, chunkSpec{begin, length}}
41 }
42
43 var (
44         // Requested data not yet available.
45         errDataNotReady = errors.New("data not ready")
46 )
47
48 // The size in bytes of a metadata extension piece.
49 func metadataPieceSize(totalSize int, piece int) int {
50         ret := totalSize - piece*(1<<14)
51         if ret > 1<<14 {
52                 ret = 1 << 14
53         }
54         return ret
55 }
56
57 type superer interface {
58         Super() interface{}
59 }
60
61 // Returns ok if there's a parent, and it's not nil.
62 func super(child interface{}) (parent interface{}, ok bool) {
63         s, ok := child.(superer)
64         if !ok {
65                 return
66         }
67         parent = s.Super()
68         ok = parent != nil
69         return
70 }
71
72 // Return the request that would include the given offset into the torrent data.
73 func torrentOffsetRequest(torrentLength, pieceSize, chunkSize, offset int64) (
74         r request, ok bool) {
75         if offset < 0 || offset >= torrentLength {
76                 return
77         }
78         r.Index = pp.Integer(offset / pieceSize)
79         r.Begin = pp.Integer(offset % pieceSize / chunkSize * chunkSize)
80         r.Length = pp.Integer(chunkSize)
81         pieceLeft := pp.Integer(pieceSize - int64(r.Begin))
82         if r.Length > pieceLeft {
83                 r.Length = pieceLeft
84         }
85         torrentLeft := torrentLength - int64(r.Index)*pieceSize - int64(r.Begin)
86         if int64(r.Length) > torrentLeft {
87                 r.Length = pp.Integer(torrentLeft)
88         }
89         ok = true
90         return
91 }
92
93 func torrentRequestOffset(torrentLength, pieceSize int64, r request) (off int64) {
94         off = int64(r.Index)*pieceSize + int64(r.Begin)
95         if off < 0 || off >= torrentLength {
96                 panic("invalid request")
97         }
98         return
99 }
100
101 func validateInfo(info *metainfo.Info) error {
102         if len(info.Pieces)%20 != 0 {
103                 return errors.New("pieces has invalid length")
104         }
105         if int((info.TotalLength()+info.PieceLength-1)/info.PieceLength) != info.NumPieces() {
106                 return errors.New("piece count and file lengths are at odds")
107         }
108         return nil
109 }
110
111 func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
112         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
113         if ret.Begin+ret.Length > pieceLength {
114                 ret.Length = pieceLength - ret.Begin
115         }
116         return ret
117 }